aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release-notes.md2
-rw-r--r--src/Makefile.am8
-rw-r--r--src/bench/prevector.cpp6
-rw-r--r--src/bench/verify_script.cpp1
-rw-r--r--src/bitcoin-tx.cpp4
-rw-r--r--src/crypto/sha256.cpp6
-rw-r--r--src/init.cpp34
-rw-r--r--src/net.cpp2
-rw-r--r--src/net.h2
-rw-r--r--src/net_processing.cpp10
-rw-r--r--src/net_processing.h10
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp9
-rw-r--r--src/script/sign.cpp397
-rw-r--r--src/script/sign.h29
-rw-r--r--src/test/denialofservice_tests.cpp24
-rw-r--r--src/test/script_tests.cpp86
-rw-r--r--src/test/transaction_tests.cpp17
-rw-r--r--src/wallet/rpcwallet.cpp6
-rw-r--r--src/wallet/wallet.cpp2
-rw-r--r--src/zmq/zmqnotificationinterface.cpp13
-rw-r--r--src/zmq/zmqnotificationinterface.h6
-rw-r--r--src/zmq/zmqrpc.cpp61
-rw-r--r--src/zmq/zmqrpc.h12
-rwxr-xr-xtest/functional/p2p_segwit.py1784
-rwxr-xr-xtest/functional/rpc_zmq.py33
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_multiwallet.py4
28 files changed, 1388 insertions, 1183 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md
index e1bb84cca9..57f93abe03 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -79,6 +79,8 @@ RPC changes
`getmempoolentry` when verbosity is set to `true` with sub-fields `ancestor`, `base`, `modified`
and `descendant` denominated in BTC. This new field deprecates previous fee fields, such as
`fee`, `modifiedfee`, `ancestorfee` and `descendantfee`.
+- The new RPC `getzmqnotifications` returns information about active ZMQ
+ notifications.
External wallet files
---------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 4286ee990d..70f59c6e84 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,7 +53,7 @@ LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a
LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2)
endif
-$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
+$(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
@@ -194,7 +194,8 @@ BITCOIN_CORE_H = \
zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\
zmq/zmqnotificationinterface.h \
- zmq/zmqpublishnotifier.h
+ zmq/zmqpublishnotifier.h \
+ zmq/zmqrpc.h
obj/build.h: FORCE
@@ -255,7 +256,8 @@ libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_zmq_a_SOURCES = \
zmq/zmqabstractnotifier.cpp \
zmq/zmqnotificationinterface.cpp \
- zmq/zmqpublishnotifier.cpp
+ zmq/zmqpublishnotifier.cpp \
+ zmq/zmqrpc.cpp
endif
diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp
index 3cfad1b2c4..09c7020848 100644
--- a/src/bench/prevector.cpp
+++ b/src/bench/prevector.cpp
@@ -42,7 +42,7 @@ static void PrevectorClear(benchmark::State& state)
t0.resize(28);
t0.clear();
t1.resize(29);
- t0.clear();
+ t1.clear();
}
}
}
@@ -64,11 +64,11 @@ static void PrevectorResize(benchmark::State& state)
#define PREVECTOR_TEST(name, nontrivops, trivops) \
static void Prevector ## name ## Nontrivial(benchmark::State& state) { \
- PrevectorResize<nontrivial_t>(state); \
+ Prevector ## name<nontrivial_t>(state); \
} \
BENCHMARK(Prevector ## name ## Nontrivial, nontrivops); \
static void Prevector ## name ## Trivial(benchmark::State& state) { \
- PrevectorResize<trivial_t>(state); \
+ Prevector ## name<trivial_t>(state); \
} \
BENCHMARK(Prevector ## name ## Trivial, trivops);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 4100519d48..ae60588c2d 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -9,6 +9,7 @@
#endif
#include <script/script.h>
#include <script/sign.h>
+#include <script/standard.h>
#include <streams.h>
#include <array>
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index e6eb723cf4..ab0efde05c 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -645,13 +645,11 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
- SignatureData sigdata;
+ SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata);
- // ... and merge in other signatures:
- sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
UpdateInput(txin, sigdata);
}
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index e62ddc125e..3f02a05aab 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -9,7 +9,7 @@
#include <string.h>
#include <atomic>
-#if defined(__x86_64__) || defined(__amd64__)
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
#if defined(USE_ASM)
#include <cpuid.h>
namespace sha256_sse4
@@ -534,7 +534,11 @@ bool SelfTest() {
// We can't use cpuid.h's __get_cpuid as it does not support subleafs.
void inline cpuid(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)
{
+#ifdef __GNUC__
+ __cpuid_count(leaf, subleaf, a, b, c, d);
+#else
__asm__ ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(leaf), "2"(subleaf));
+#endif
}
/** Check whether the OS has enabled AVX registers. */
diff --git a/src/init.cpp b/src/init.cpp
index 80c9b25d0e..66b0b65eb4 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -63,6 +63,7 @@
#if ENABLE_ZMQ
#include <zmq/zmqnotificationinterface.h>
+#include <zmq/zmqrpc.h>
#endif
bool fFeeEstimatesInitialized = false;
@@ -100,10 +101,6 @@ void DummyWalletInit::AddWalletOptions() const
const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
#endif
-#if ENABLE_ZMQ
-static CZMQNotificationInterface* pzmqNotificationInterface = nullptr;
-#endif
-
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
// accessing block files don't count towards the fd_set size limit
@@ -269,10 +266,10 @@ void Shutdown()
g_wallet_init_interface.Stop();
#if ENABLE_ZMQ
- if (pzmqNotificationInterface) {
- UnregisterValidationInterface(pzmqNotificationInterface);
- delete pzmqNotificationInterface;
- pzmqNotificationInterface = nullptr;
+ if (g_zmq_notification_interface) {
+ UnregisterValidationInterface(g_zmq_notification_interface);
+ delete g_zmq_notification_interface;
+ g_zmq_notification_interface = nullptr;
}
#endif
@@ -367,7 +364,7 @@ void SetupServerArgs()
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS);
- gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (0 to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS);
gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-loadblock=<file>", "Imports blocks from external blk000??.dat file on startup", false, OptionsCategory::OPTIONS);
@@ -479,7 +476,7 @@ void SetupServerArgs()
gArgs.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST);
- gArgs.AddArg("-printtoconsole", "Send trace/debug info to console instead of debug.log file", false, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set debuglogfile=0)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", false, OptionsCategory::DEBUG_TEST);
@@ -1282,6 +1279,9 @@ bool AppInitMain()
*/
RegisterAllCoreRPCCommands(tableRPC);
g_wallet_init_interface.RegisterRPC(tableRPC);
+#if ENABLE_ZMQ
+ RegisterZMQRPCCommands(tableRPC);
+#endif
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
@@ -1295,8 +1295,6 @@ bool AppInitMain()
return InitError(_("Unable to start HTTP server. See debug log for details."));
}
- int64_t nStart;
-
// ********************************************************* Step 5: verify wallet database integrity
if (!g_wallet_init_interface.Verify()) return false;
@@ -1400,10 +1398,10 @@ bool AppInitMain()
}
#if ENABLE_ZMQ
- pzmqNotificationInterface = CZMQNotificationInterface::Create();
+ g_zmq_notification_interface = CZMQNotificationInterface::Create();
- if (pzmqNotificationInterface) {
- RegisterValidationInterface(pzmqNotificationInterface);
+ if (g_zmq_notification_interface) {
+ RegisterValidationInterface(g_zmq_notification_interface);
}
#endif
uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set
@@ -1448,8 +1446,8 @@ bool AppInitMain()
LOCK(cs_main);
- nStart = GetTimeMillis();
do {
+ const int64_t load_block_index_start_time = GetTimeMillis();
try {
UnloadBlockIndex();
pcoinsTip.reset();
@@ -1572,6 +1570,7 @@ bool AppInitMain()
}
fLoaded = true;
+ LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
} while(false);
if (!fLoaded && !ShutdownRequested()) {
@@ -1601,9 +1600,6 @@ bool AppInitMain()
LogPrintf("Shutdown requested. Exiting.\n");
return false;
}
- if (fLoaded) {
- LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
- }
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
diff --git a/src/net.cpp b/src/net.cpp
index 55043ffe30..b24ceb67d6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2042,7 +2042,7 @@ void CConnman::ThreadMessageHandler()
// Send messages
{
LOCK(pnode->cs_sendProcessing);
- m_msgproc->SendMessages(pnode, flagInterruptMsgProc);
+ m_msgproc->SendMessages(pnode);
}
if (flagInterruptMsgProc)
diff --git a/src/net.h b/src/net.h
index 1bcc3cbb44..697aa37a58 100644
--- a/src/net.h
+++ b/src/net.h
@@ -466,7 +466,7 @@ class NetEventsInterface
{
public:
virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
- virtual bool SendMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
+ virtual bool SendMessages(CNode* pnode) = 0;
virtual void InitializeNode(CNode* pnode) = 0;
virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 17ae6a82db..458e9c2e9f 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -664,10 +664,10 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE
// large transaction with a missing parent then we assume
// it will rebroadcast it later, after the parent transaction(s)
// have been mined or received.
- // 100 orphans, each of which is at most 99,999 bytes big is
+ // 100 orphans, each of which is at most 100,000 bytes big is
// at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
unsigned int sz = GetTransactionWeight(*tx);
- if (sz >= MAX_STANDARD_TX_WEIGHT)
+ if (sz > MAX_STANDARD_TX_WEIGHT)
{
LogPrint(BCLog::MEMPOOL, "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
return false;
@@ -1070,7 +1070,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connma
connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
-void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
+void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman)
{
bool send = false;
std::shared_ptr<const CBlock> a_recent_block;
@@ -1274,7 +1274,7 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
const CInv &inv = *it;
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) {
it++;
- ProcessGetBlockData(pfrom, chainparams, inv, connman, interruptMsgProc);
+ ProcessGetBlockData(pfrom, chainparams, inv, connman);
}
}
@@ -3218,7 +3218,7 @@ public:
}
};
-bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptMsgProc)
+bool PeerLogicValidation::SendMessages(CNode* pto)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
diff --git a/src/net_processing.h b/src/net_processing.h
index 3bdb4785a2..0d97b316eb 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -68,16 +68,20 @@ public:
void InitializeNode(CNode* pnode) override;
/** Handle removal of a peer by updating various state and removing it from mapNodeState */
void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override;
- /** Process protocol messages received from a given node */
+ /**
+ * Process protocol messages received from a given node
+ *
+ * @param[in] pfrom The node which we have received messages from.
+ * @param[in] interrupt Interrupt condition for processing threads
+ */
bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
/**
* Send queued protocol messages to be sent to a give node.
*
* @param[in] pto The node which we are sending messages to.
- * @param[in] interrupt Interrupt condition for processing threads
* @return True if there is more work to be done
*/
- bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
+ bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index aac3fe5c14..3a592e40d3 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -88,7 +88,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
// computing signature hashes is O(ninputs*txsize). Limiting transactions
// to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks.
unsigned int sz = GetTransactionWeight(tx);
- if (sz >= MAX_STANDARD_TX_WEIGHT) {
+ if (sz > MAX_STANDARD_TX_WEIGHT) {
reason = "tx-size";
return false;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 61e77789be..63548bff05 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -733,17 +733,15 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
if (coin.IsSpent()) {
throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent");
}
- const CScript& prevPubKey = coin.out.scriptPubKey;
- const CAmount& amount = coin.out.nValue;
-
SignatureData sigdata;
// ... and merge in other signatures:
for (const CMutableTransaction& txv : txVariants) {
if (txv.vin.size() > i) {
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ sigdata.MergeSignatureData(DataFromTransaction(txv, i, coin.out));
}
}
+ ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&mergedTx, i, coin.out.nValue, 1), coin.out.scriptPubKey, sigdata);
UpdateInput(txin, sigdata);
}
@@ -872,12 +870,11 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
- SignatureData sigdata;
+ SignatureData sigdata = DataFromTransaction(mtx, i, coin.out);
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mtx.vout.size())) {
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
}
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(mtx, i));
UpdateInput(txin, sigdata);
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 6dbfbda029..60a8a2655d 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -33,27 +33,51 @@ bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provid
return true;
}
-static bool Sign1(const SigningProvider& provider, const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
+static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
{
- std::vector<unsigned char> vchSig;
- if (!creator.CreateSig(provider, vchSig, address, scriptCode, sigversion))
- return false;
- ret.push_back(vchSig);
- return true;
+ if (provider.GetCScript(scriptid, script)) {
+ return true;
+ }
+ // Look for scripts in SignatureData
+ if (CScriptID(sigdata.redeem_script) == scriptid) {
+ script = sigdata.redeem_script;
+ return true;
+ } else if (CScriptID(sigdata.witness_script) == scriptid) {
+ script = sigdata.witness_script;
+ return true;
+ }
+ return false;
}
-static bool SignN(const SigningProvider& provider, const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
+static bool GetPubKey(const SigningProvider& provider, const SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey)
{
- int nSigned = 0;
- int nRequired = multisigdata.front()[0];
- for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
- {
- const valtype& pubkey = multisigdata[i];
- CKeyID keyID = CPubKey(pubkey).GetID();
- if (Sign1(provider, keyID, creator, scriptCode, ret, sigversion))
- ++nSigned;
+ if (provider.GetPubKey(address, pubkey)) {
+ return true;
+ }
+ // Look for pubkey in all partial sigs
+ const auto it = sigdata.signatures.find(address);
+ if (it != sigdata.signatures.end()) {
+ pubkey = it->second.first;
+ return true;
}
- return nSigned==nRequired;
+ return false;
+}
+
+static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion)
+{
+ const auto it = sigdata.signatures.find(keyid);
+ if (it != sigdata.signatures.end()) {
+ sig_out = it->second.second;
+ return true;
+ }
+ if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) {
+ CPubKey pubkey;
+ GetPubKey(provider, sigdata, keyid, pubkey);
+ auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));
+ assert(i.second);
+ return true;
+ }
+ return false;
}
/**
@@ -63,17 +87,17 @@ static bool SignN(const SigningProvider& provider, const std::vector<valtype>& m
* Returns false if scriptPubKey could not be completely satisfied.
*/
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey,
- std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion)
+ std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
{
CScript scriptRet;
uint160 h160;
ret.clear();
+ std::vector<unsigned char> sig;
std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
return false;
- CKeyID keyID;
switch (whichTypeRet)
{
case TX_NONSTANDARD:
@@ -81,37 +105,47 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
case TX_WITNESS_UNKNOWN:
return false;
case TX_PUBKEY:
- keyID = CPubKey(vSolutions[0]).GetID();
- return Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion);
- case TX_PUBKEYHASH:
- keyID = CKeyID(uint160(vSolutions[0]));
- if (!Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion))
- return false;
- else
- {
- CPubKey vch;
- provider.GetPubKey(keyID, vch);
- ret.push_back(ToByteVector(vch));
- }
+ if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false;
+ ret.push_back(std::move(sig));
+ return true;
+ case TX_PUBKEYHASH: {
+ CKeyID keyID = CKeyID(uint160(vSolutions[0]));
+ if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false;
+ ret.push_back(std::move(sig));
+ CPubKey pubkey;
+ GetPubKey(provider, sigdata, keyID, pubkey);
+ ret.push_back(ToByteVector(pubkey));
return true;
+ }
case TX_SCRIPTHASH:
- if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) {
+ if (GetCScript(provider, sigdata, uint160(vSolutions[0]), scriptRet)) {
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
return true;
}
return false;
- case TX_MULTISIG:
+ case TX_MULTISIG: {
+ size_t required = vSolutions.front()[0];
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
- return (SignN(provider, vSolutions, creator, scriptPubKey, ret, sigversion));
-
+ for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
+ CPubKey pubkey = CPubKey(vSolutions[i]);
+ if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) {
+ ret.push_back(std::move(sig));
+ }
+ }
+ bool ok = ret.size() == required + 1;
+ for (size_t i = 0; i + ret.size() < required + 1; ++i) {
+ ret.push_back(valtype());
+ }
+ return ok;
+ }
case TX_WITNESS_V0_KEYHASH:
ret.push_back(vSolutions[0]);
return true;
case TX_WITNESS_V0_SCRIPTHASH:
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
- if (provider.GetCScript(h160, scriptRet)) {
+ if (GetCScript(provider, sigdata, h160, scriptRet)) {
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
return true;
}
@@ -139,9 +173,11 @@ static CScript PushAll(const std::vector<valtype>& values)
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
{
+ if (sigdata.complete) return true;
+
std::vector<valtype> result;
txnouttype whichType;
- bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE);
+ bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata);
bool P2SH = false;
CScript subscript;
sigdata.scriptWitness.stack.clear();
@@ -152,7 +188,8 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
// the final scriptSig is the signatures from that
// and then the serialized subscript:
subscript = CScript(result[0].begin(), result[0].end());
- solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE) && whichType != TX_SCRIPTHASH;
+ sigdata.redeem_script = subscript;
+ solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH;
P2SH = true;
}
@@ -161,15 +198,16 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
CScript witnessscript;
witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
txnouttype subType;
- solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0);
+ solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata);
sigdata.scriptWitness.stack = result;
result.clear();
}
else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH)
{
CScript witnessscript(result[0].begin(), result[0].end());
+ sigdata.witness_script = witnessscript;
txnouttype subType;
- solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
+ solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
sigdata.scriptWitness.stack = result;
result.clear();
@@ -181,99 +219,29 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
sigdata.scriptSig = PushAll(result);
// Test solution
- return solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
-}
-
-SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)
-{
- SignatureData data;
- assert(tx.vin.size() > nIn);
- data.scriptSig = tx.vin[nIn].scriptSig;
- data.scriptWitness = tx.vin[nIn].scriptWitness;
- return data;
+ sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
+ return sigdata.complete;
}
-void UpdateInput(CTxIn& input, const SignatureData& data)
+class SignatureExtractorChecker final : public BaseSignatureChecker
{
- input.scriptSig = data.scriptSig;
- input.scriptWitness = data.scriptWitness;
-}
+private:
+ SignatureData& sigdata;
+ BaseSignatureChecker& checker;
-bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
-{
- assert(nIn < txTo.vin.size());
-
- MutableTransactionSignatureCreator creator(&txTo, nIn, amount, nHashType);
-
- SignatureData sigdata;
- bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);
- UpdateInput(txTo.vin.at(nIn), sigdata);
- return ret;
-}
-
-bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
-{
- assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
- assert(txin.prevout.n < txFrom.vout.size());
- const CTxOut& txout = txFrom.vout[txin.prevout.n];
-
- return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
-}
+public:
+ SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
+};
-static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const std::vector<valtype>& vSolutions,
- const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion)
+bool SignatureExtractorChecker::CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
- // Combine all the signatures we've got:
- std::set<valtype> allsigs;
- for (const valtype& v : sigs1)
- {
- if (!v.empty())
- allsigs.insert(v);
- }
- for (const valtype& v : sigs2)
- {
- if (!v.empty())
- allsigs.insert(v);
- }
-
- // Build a map of pubkey -> signature by matching sigs to pubkeys:
- assert(vSolutions.size() > 1);
- unsigned int nSigsRequired = vSolutions.front()[0];
- unsigned int nPubKeys = vSolutions.size()-2;
- std::map<valtype, valtype> sigs;
- for (const valtype& sig : allsigs)
- {
- for (unsigned int i = 0; i < nPubKeys; i++)
- {
- const valtype& pubkey = vSolutions[i+1];
- if (sigs.count(pubkey))
- continue; // Already got a sig for this pubkey
-
- if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion))
- {
- sigs[pubkey] = sig;
- break;
- }
- }
- }
- // Now build a merged CScript:
- unsigned int nSigsHave = 0;
- std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround
- for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
- {
- if (sigs.count(vSolutions[i+1]))
- {
- result.push_back(sigs[vSolutions[i+1]]);
- ++nSigsHave;
- }
+ if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) {
+ CPubKey pubkey(vchPubKey);
+ sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
+ return true;
}
- // Fill any missing with OP_0:
- for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
- result.push_back(valtype());
-
- return result;
+ return false;
}
namespace
@@ -298,89 +266,115 @@ struct Stacks
};
}
-static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const txnouttype txType, const std::vector<valtype>& vSolutions,
- Stacks sigs1, Stacks sigs2, SigVersion sigversion)
+// Extracts signatures and scripts from incomplete scriptSigs. Please do not extend this, use PSBT instead
+SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout)
{
- switch (txType)
- {
- case TX_NONSTANDARD:
- case TX_NULL_DATA:
- case TX_WITNESS_UNKNOWN:
- // Don't know anything about this, assume bigger one is correct:
- if (sigs1.script.size() >= sigs2.script.size())
- return sigs1;
- return sigs2;
- case TX_PUBKEY:
- case TX_PUBKEYHASH:
- // Signatures are bigger than placeholders or empty scripts:
- if (sigs1.script.empty() || sigs1.script[0].empty())
- return sigs2;
- return sigs1;
- case TX_WITNESS_V0_KEYHASH:
- // Signatures are bigger than placeholders or empty scripts:
- if (sigs1.witness.empty() || sigs1.witness[0].empty())
- return sigs2;
- return sigs1;
- case TX_SCRIPTHASH:
- if (sigs1.script.empty() || sigs1.script.back().empty())
- return sigs2;
- else if (sigs2.script.empty() || sigs2.script.back().empty())
- return sigs1;
- else
- {
- // Recur to combine:
- valtype spk = sigs1.script.back();
- CScript pubKey2(spk.begin(), spk.end());
-
- txnouttype txType2;
- std::vector<std::vector<unsigned char> > vSolutions2;
- Solver(pubKey2, txType2, vSolutions2);
- sigs1.script.pop_back();
- sigs2.script.pop_back();
- Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion);
- result.script.push_back(spk);
- return result;
- }
- case TX_MULTISIG:
- return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion));
- case TX_WITNESS_V0_SCRIPTHASH:
- if (sigs1.witness.empty() || sigs1.witness.back().empty())
- return sigs2;
- else if (sigs2.witness.empty() || sigs2.witness.back().empty())
- return sigs1;
- else
- {
- // Recur to combine:
- CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end());
- txnouttype txType2;
- std::vector<valtype> vSolutions2;
- Solver(pubKey2, txType2, vSolutions2);
- sigs1.witness.pop_back();
- sigs1.script = sigs1.witness;
- sigs1.witness.clear();
- sigs2.witness.pop_back();
- sigs2.script = sigs2.witness;
- sigs2.witness.clear();
- Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SigVersion::WITNESS_V0);
- result.witness = result.script;
- result.script.clear();
- result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end()));
- return result;
+ SignatureData data;
+ assert(tx.vin.size() > nIn);
+ data.scriptSig = tx.vin[nIn].scriptSig;
+ data.scriptWitness = tx.vin[nIn].scriptWitness;
+ Stacks stack(data);
+
+ // Get signatures
+ MutableTransactionSignatureChecker tx_checker(&tx, nIn, txout.nValue);
+ SignatureExtractorChecker extractor_checker(data, tx_checker);
+ if (VerifyScript(data.scriptSig, txout.scriptPubKey, &data.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, extractor_checker)) {
+ data.complete = true;
+ return data;
+ }
+
+ // Get scripts
+ txnouttype script_type;
+ std::vector<std::vector<unsigned char>> solutions;
+ Solver(txout.scriptPubKey, script_type, solutions);
+ SigVersion sigversion = SigVersion::BASE;
+ CScript next_script = txout.scriptPubKey;
+
+ if (script_type == TX_SCRIPTHASH && !stack.script.empty() && !stack.script.back().empty()) {
+ // Get the redeemScript
+ CScript redeem_script(stack.script.back().begin(), stack.script.back().end());
+ data.redeem_script = redeem_script;
+ next_script = std::move(redeem_script);
+
+ // Get redeemScript type
+ Solver(next_script, script_type, solutions);
+ stack.script.pop_back();
+ }
+ if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
+ // Get the witnessScript
+ CScript witness_script(stack.witness.back().begin(), stack.witness.back().end());
+ data.witness_script = witness_script;
+ next_script = std::move(witness_script);
+
+ // Get witnessScript type
+ Solver(next_script, script_type, solutions);
+ stack.witness.pop_back();
+ stack.script = std::move(stack.witness);
+ stack.witness.clear();
+ sigversion = SigVersion::WITNESS_V0;
+ }
+ if (script_type == TX_MULTISIG && !stack.script.empty()) {
+ // Build a map of pubkey -> signature by matching sigs to pubkeys:
+ assert(solutions.size() > 1);
+ unsigned int num_pubkeys = solutions.size()-2;
+ unsigned int last_success_key = 0;
+ for (const valtype& sig : stack.script) {
+ for (unsigned int i = last_success_key; i < num_pubkeys; ++i) {
+ const valtype& pubkey = solutions[i+1];
+ // We either have a signature for this pubkey, or we have found a signature and it is valid
+ if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion)) {
+ last_success_key = i + 1;
+ break;
+ }
+ }
}
- default:
- return Stacks();
}
+
+ return data;
+}
+
+void UpdateInput(CTxIn& input, const SignatureData& data)
+{
+ input.scriptSig = data.scriptSig;
+ input.scriptWitness = data.scriptWitness;
+}
+
+void SignatureData::MergeSignatureData(SignatureData sigdata)
+{
+ if (complete) return;
+ if (sigdata.complete) {
+ *this = std::move(sigdata);
+ return;
+ }
+ if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
+ redeem_script = sigdata.redeem_script;
+ }
+ if (witness_script.empty() && !sigdata.witness_script.empty()) {
+ witness_script = sigdata.witness_script;
+ }
+ signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end()));
+}
+
+bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
+{
+ assert(nIn < txTo.vin.size());
+
+ MutableTransactionSignatureCreator creator(&txTo, nIn, amount, nHashType);
+
+ SignatureData sigdata;
+ bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);
+ UpdateInput(txTo.vin.at(nIn), sigdata);
+ return ret;
}
-SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const SignatureData& scriptSig1, const SignatureData& scriptSig2)
+bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
- txnouttype txType;
- std::vector<std::vector<unsigned char> > vSolutions;
- Solver(scriptPubKey, txType, vSolutions);
+ assert(nIn < txTo.vin.size());
+ CTxIn& txin = txTo.vin[nIn];
+ assert(txin.prevout.n < txFrom.vout.size());
+ const CTxOut& txout = txFrom.vout[txin.prevout.n];
- return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SigVersion::BASE).Output();
+ return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
}
namespace {
@@ -416,6 +410,7 @@ public:
}
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator();
+const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
bool IsSolvable(const SigningProvider& provider, const CScript& script)
{
diff --git a/src/script/sign.h b/src/script/sign.h
index 8ef0306bfe..3666859641 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -21,11 +21,13 @@ class SigningProvider
{
public:
virtual ~SigningProvider() {}
- virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const =0;
- virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const =0;
- virtual bool GetKey(const CKeyID &address, CKey& key) const =0;
+ virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
+ virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
+ virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
};
+extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
+
/** Interface for signature creators. */
class BaseSignatureCreator {
public:
@@ -53,12 +55,22 @@ public:
/** A signature creator that just produces 72-byte empty signatures. */
extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;
+typedef std::pair<CPubKey, std::vector<unsigned char>> SigPair;
+
+// This struct contains information from a transaction input and also contains signatures for that input.
+// The information contained here can be used to create a signature and is also filled by ProduceSignature
+// in order to construct final scriptSigs and scriptWitnesses.
struct SignatureData {
- CScript scriptSig;
- CScriptWitness scriptWitness;
+ bool complete = false; ///< Stores whether the scriptSig and scriptWitness are complete
+ CScript scriptSig; ///< The scriptSig of an input. Contains complete signatures or the traditional partial signatures format
+ CScript redeem_script; ///< The redeemScript (if any) for the input
+ CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs.
+ CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144.
+ std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness.
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
+ void MergeSignatureData(SignatureData sigdata);
};
/** Produce a script signature using a generic signature creator. */
@@ -68,11 +80,8 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
-/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
-SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2);
-
-/** Extract signature data from a transaction, and insert it. */
-SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
+/** Extract signature data from a transaction input, and insert it. */
+SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
void UpdateInput(CTxIn& input, const SignatureData& data);
/* Check whether we know how to sign for an output like this, assuming we
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index bebbd6c464..cc871726fd 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -54,7 +54,6 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
// work.
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
- std::atomic<bool> interruptDummy(false);
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -75,7 +74,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Test starts here
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ peerLogic->SendMessages(&dummyNode1); // should result in getheaders
}
{
LOCK2(cs_main, dummyNode1.cs_vSend);
@@ -88,7 +87,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
SetMockTime(nStartTime+21*60);
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ peerLogic->SendMessages(&dummyNode1); // should result in getheaders
}
{
LOCK2(cs_main, dummyNode1.cs_vSend);
@@ -98,7 +97,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
SetMockTime(nStartTime+24*60);
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in disconnect
+ peerLogic->SendMessages(&dummyNode1); // should result in disconnect
}
BOOST_CHECK(dummyNode1.fDisconnect == true);
SetMockTime(0);
@@ -192,7 +191,6 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_AUTO_TEST_CASE(DoS_banning)
{
- std::atomic<bool> interruptDummy(false);
connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -207,7 +205,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
}
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1);
}
BOOST_CHECK(connman->IsBanned(addr1));
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
@@ -224,7 +222,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
}
{
LOCK2(cs_main, dummyNode2.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode2, interruptDummy);
+ peerLogic->SendMessages(&dummyNode2);
}
BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
@@ -234,7 +232,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
}
{
LOCK2(cs_main, dummyNode2.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode2, interruptDummy);
+ peerLogic->SendMessages(&dummyNode2);
}
BOOST_CHECK(connman->IsBanned(addr2));
@@ -245,7 +243,6 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
- std::atomic<bool> interruptDummy(false);
connman->ClearBanned();
gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
@@ -261,7 +258,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
}
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1);
}
BOOST_CHECK(!connman->IsBanned(addr1));
{
@@ -270,7 +267,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
}
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1);
}
BOOST_CHECK(!connman->IsBanned(addr1));
{
@@ -279,7 +276,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
}
{
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode1, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1);
}
BOOST_CHECK(connman->IsBanned(addr1));
gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
@@ -290,7 +287,6 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
- std::atomic<bool> interruptDummy(false);
connman->ClearBanned();
int64_t nStartTime = GetTime();
@@ -309,7 +305,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
}
{
LOCK2(cs_main, dummyNode.cs_sendProcessing);
- peerLogic->SendMessages(&dummyNode, interruptDummy);
+ peerLogic->SendMessages(&dummyNode);
}
BOOST_CHECK(connman->IsBanned(addr));
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index c05e60996d..c7cdd7ca82 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1161,10 +1161,19 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
+/* Wrapper around ProduceSignature to combine two scriptsigs */
+SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction& tx, const SignatureData& scriptSig1, const SignatureData& scriptSig2)
+{
+ SignatureData data;
+ data.MergeSignatureData(scriptSig1);
+ data.MergeSignatureData(scriptSig2);
+ ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&tx, 0, txout.nValue), txout.scriptPubKey, data);
+ return data;
+}
+
BOOST_AUTO_TEST_CASE(script_combineSigs)
{
- // Test the CombineSignatures function
- CAmount amount = 0;
+ // Test the ProduceSignature's ability to combine signatures function
CBasicKeyStore keystore;
std::vector<CKey> keys;
std::vector<CPubKey> pubkeys;
@@ -1180,52 +1189,51 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom);
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
- CScript& scriptSig = txTo.vin[0].scriptSig;
+ SignatureData scriptSig;
SignatureData empty;
- SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty);
+ SignatureData combined = CombineSignatures(txFrom.vout[0], txTo, empty, empty);
BOOST_CHECK(combined.scriptSig.empty());
// Single signature case:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
- CScript scriptSigCopy = scriptSig;
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ SignatureData scriptSigCopy = scriptSig;
// Signing again will give a different, valid signature:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
// P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
keystore.AddCScript(pkSingle);
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
scriptSigCopy = scriptSig;
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
- // dummy scriptSigCopy with placeholder, should always choose non-placeholder:
- scriptSigCopy = CScript() << OP_0 << std::vector<unsigned char>(pkSingle.begin(), pkSingle.end());
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy));
- BOOST_CHECK(combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
// Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
// A couple of partially-signed versions:
std::vector<unsigned char> sig1;
@@ -1252,22 +1260,28 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript complete12 = CScript() << OP_0 << sig1 << sig2;
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
-
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b));
+ SignatureData partial1_sigs;
+ partial1_sigs.signatures.emplace(keys[0].GetPubKey().GetID(), SigPair(keys[0].GetPubKey(), sig1));
+ SignatureData partial2_sigs;
+ partial2_sigs.signatures.emplace(keys[1].GetPubKey().GetID(), SigPair(keys[1].GetPubKey(), sig2));
+ SignatureData partial3_sigs;
+ partial3_sigs.signatures.emplace(keys[2].GetPubKey().GetID(), SigPair(keys[2].GetPubKey(), sig3));
+
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial1_sigs);
BOOST_CHECK(combined.scriptSig == partial1a);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);
BOOST_CHECK(combined.scriptSig == complete12);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial1_sigs);
BOOST_CHECK(combined.scriptSig == complete12);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);
BOOST_CHECK(combined.scriptSig == complete12);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial1_sigs);
BOOST_CHECK(combined.scriptSig == complete13);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial3_sigs);
BOOST_CHECK(combined.scriptSig == complete23);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial2_sigs);
BOOST_CHECK(combined.scriptSig == complete23);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial3_sigs);
BOOST_CHECK(combined.scriptSig == partial3c);
}
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 65c5b8ea1d..45dc0e3571 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -494,6 +494,15 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
threadGroup.join_all();
}
+SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutableTransaction& input2, const CTransactionRef tx)
+{
+ SignatureData sigdata;
+ sigdata = DataFromTransaction(input1, 0, tx->vout[0]);
+ sigdata.MergeSignatureData(DataFromTransaction(input2, 0, tx->vout[0]));
+ ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&input1, 0, tx->vout[0].nValue), tx->vout[0].scriptPubKey, sigdata);
+ return sigdata;
+}
+
BOOST_AUTO_TEST_CASE(test_witness)
{
CBasicKeyStore keystore, keystore2;
@@ -629,7 +638,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
CreateCreditAndSpend(keystore2, scriptMulti, output2, input2, false);
CheckWithFlag(output2, input2, 0, false);
BOOST_CHECK(*output1 == *output2);
- UpdateInput(input1.vin[0], CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
// P2SH 2-of-2 multisig
@@ -640,7 +649,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output2, input2, 0, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false);
BOOST_CHECK(*output1 == *output2);
- UpdateInput(input1.vin[0], CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
@@ -652,7 +661,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output2, input2, 0, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
BOOST_CHECK(*output1 == *output2);
- UpdateInput(input1.vin[0], CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true);
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
@@ -664,7 +673,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
BOOST_CHECK(*output1 == *output2);
- UpdateInput(input1.vin[0], CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true);
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index c1f4c99851..b1d2532d86 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3091,6 +3091,12 @@ static UniValue loadwallet(const JSONRPCRequest& request)
fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
if (fs::symlink_status(wallet_path).type() == fs::file_not_found) {
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + wallet_file + " not found.");
+ } else if (fs::is_directory(wallet_path)) {
+ // The given filename is a directory. Check that there's a wallet.dat file.
+ fs::path wallet_dat_file = wallet_path / "wallet.dat";
+ if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + wallet_file + " does not contain a wallet.dat file.");
+ }
}
std::string warning;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index bffd05f821..adc48a8650 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3078,7 +3078,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
tx = MakeTransactionRef(std::move(txNew));
// Limit size
- if (GetTransactionWeight(*tx) >= MAX_STANDARD_TX_WEIGHT)
+ if (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT)
{
strFailReason = _("Transaction too large");
return false;
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 68b425fa08..8cbc969972 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2017 The Bitcoin Core developers
+// Copyright (c) 2015-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -29,6 +29,15 @@ CZMQNotificationInterface::~CZMQNotificationInterface()
}
}
+std::list<const CZMQAbstractNotifier*> CZMQNotificationInterface::GetActiveNotifiers() const
+{
+ std::list<const CZMQAbstractNotifier*> result;
+ for (const auto* n : notifiers) {
+ result.push_back(n);
+ }
+ return result;
+}
+
CZMQNotificationInterface* CZMQNotificationInterface::Create()
{
CZMQNotificationInterface* notificationInterface = nullptr;
@@ -180,3 +189,5 @@ void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CB
TransactionAddedToMempool(ptx);
}
}
+
+CZMQNotificationInterface* g_zmq_notification_interface = nullptr;
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index dee926ea5e..a0cc26a162 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2017 The Bitcoin Core developers
+// Copyright (c) 2015-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,8 @@ class CZMQNotificationInterface final : public CValidationInterface
public:
virtual ~CZMQNotificationInterface();
+ std::list<const CZMQAbstractNotifier*> GetActiveNotifiers() const;
+
static CZMQNotificationInterface* Create();
protected:
@@ -37,4 +39,6 @@ private:
std::list<CZMQAbstractNotifier*> notifiers;
};
+extern CZMQNotificationInterface* g_zmq_notification_interface;
+
#endif // BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
new file mode 100644
index 0000000000..4f88bf4eb9
--- /dev/null
+++ b/src/zmq/zmqrpc.cpp
@@ -0,0 +1,61 @@
+// 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 <zmq/zmqrpc.h>
+
+#include <rpc/server.h>
+#include <zmq/zmqabstractnotifier.h>
+#include <zmq/zmqnotificationinterface.h>
+
+#include <univalue.h>
+
+namespace {
+
+UniValue getzmqnotifications(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0) {
+ throw std::runtime_error(
+ "getzmqnotifications\n"
+ "\nReturns information about the active ZeroMQ notifications.\n"
+ "\nResult:\n"
+ "[\n"
+ " { (json object)\n"
+ " \"type\": \"pubhashtx\", (string) Type of notification\n"
+ " \"address\": \"...\" (string) Address of the publisher\n"
+ " },\n"
+ " ...\n"
+ "]\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getzmqnotifications", "")
+ + HelpExampleRpc("getzmqnotifications", "")
+ );
+ }
+
+ UniValue result(UniValue::VARR);
+ if (g_zmq_notification_interface != nullptr) {
+ for (const auto* n : g_zmq_notification_interface->GetActiveNotifiers()) {
+ UniValue obj(UniValue::VOBJ);
+ obj.pushKV("type", n->GetType());
+ obj.pushKV("address", n->GetAddress());
+ result.push_back(obj);
+ }
+ }
+
+ return result;
+}
+
+const CRPCCommand commands[] =
+{ // category name actor (function) argNames
+ // ----------------- ------------------------ ----------------------- ----------
+ { "zmq", "getzmqnotifications", &getzmqnotifications, {} },
+};
+
+} // anonymous namespace
+
+void RegisterZMQRPCCommands(CRPCTable& t)
+{
+ for (const auto& c : commands) {
+ t.appendCommand(c.name, &c);
+ }
+}
diff --git a/src/zmq/zmqrpc.h b/src/zmq/zmqrpc.h
new file mode 100644
index 0000000000..5a810a16fb
--- /dev/null
+++ b/src/zmq/zmqrpc.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_ZMQ_ZMQRPC_H
+#define BITCOIN_ZMQ_ZMQRPC_H
+
+class CRPCTable;
+
+void RegisterZMQRPCCommands(CRPCTable& t);
+
+#endif // BITCOIN_ZMQ_ZMRRPC_H
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index a2b86ff82d..727f2d1c6e 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -3,17 +3,84 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test segwit transactions and blocks on P2P network."""
+from binascii import hexlify
+import math
+import random
+import struct
+import time
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.script import *
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
from test_framework.key import CECKey, CPubKey
-import math
-import time
-import random
-from binascii import hexlify
+from test_framework.messages import (
+ BIP125_SEQUENCE_NUMBER,
+ CBlock,
+ CBlockHeader,
+ CInv,
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxInWitness,
+ CTxOut,
+ CTxWitness,
+ MAX_BLOCK_BASE_SIZE,
+ MSG_WITNESS_FLAG,
+ NODE_NETWORK,
+ NODE_WITNESS,
+ msg_block,
+ msg_getdata,
+ msg_headers,
+ msg_inv,
+ msg_tx,
+ msg_witness_block,
+ msg_witness_tx,
+ ser_uint256,
+ ser_vector,
+ sha256,
+ uint256_from_str,
+)
+from test_framework.mininode import (
+ P2PInterface,
+ mininode_lock,
+)
+from test_framework.script import (
+ CScript,
+ CScriptNum,
+ CScriptOp,
+ OP_0,
+ OP_1,
+ OP_16,
+ OP_2DROP,
+ OP_CHECKMULTISIG,
+ OP_CHECKSIG,
+ OP_DROP,
+ OP_DUP,
+ OP_ELSE,
+ OP_ENDIF,
+ OP_EQUAL,
+ OP_EQUALVERIFY,
+ OP_HASH160,
+ OP_IF,
+ OP_RETURN,
+ OP_TRUE,
+ SIGHASH_ALL,
+ SIGHASH_ANYONECANPAY,
+ SIGHASH_NONE,
+ SIGHASH_SINGLE,
+ SegwitVersion1SignatureHash,
+ SignatureHash,
+ hash160,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ connect_nodes,
+ disconnect_nodes,
+ get_bip9_status,
+ hex_str_to_bytes,
+ sync_blocks,
+ sync_mempools,
+)
# The versionbit bit used to signal activation of SegWit
VB_WITNESS_BIT = 1
@@ -22,14 +89,32 @@ VB_TOP_BITS = 0x20000000
MAX_SIGOP_COST = 80000
+class UTXO():
+ """Used to keep track of anyone-can-spend outputs that we can use in the tests."""
+ def __init__(self, sha256, n, value):
+ self.sha256 = sha256
+ self.n = n
+ self.nValue = value
+
+def get_p2pkh_script(pubkeyhash):
+ """Get the script associated with a P2PKH."""
+ return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
+
+def sign_p2pk_witness_input(script, tx_to, in_idx, hashtype, value, key):
+ """Add signature for a P2PK witness program."""
+ tx_hash = SegwitVersion1SignatureHash(script, tx_to, in_idx, hashtype, value)
+ signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
+ tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script]
+ tx_to.rehash()
-# Calculate the virtual size of a witness block:
-# (base + witness/4)
def get_virtual_size(witness_block):
+ """Calculate the virtual size of a witness block.
+
+ Virtual size is base + witness/4."""
base_size = len(witness_block.serialize(with_witness=False))
total_size = len(witness_block.serialize(with_witness=True))
# the "+3" is so we round up
- vsize = int((3*base_size + total_size + 3)/4)
+ vsize = int((3 * base_size + total_size + 3) / 4)
return vsize
def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=None):
@@ -43,7 +128,7 @@ def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=Non
p2p.send_message(tx_message)
p2p.sync_with_ping()
assert_equal(tx.hash in rpc.getrawmempool(), accepted)
- if (reason != None and not accepted):
+ if (reason is not None and not accepted):
# Check the rejection reason as well.
with mininode_lock:
assert_equal(p2p.last_message["reject"].reason, reason)
@@ -59,7 +144,7 @@ def test_witness_block(rpc, p2p, block, accepted, with_witness=True, reason=None
p2p.send_message(msg_block(block))
p2p.sync_with_ping()
assert_equal(rpc.getbestblockhash() == block.hash, accepted)
- if (reason != None and not accepted):
+ if (reason is not None and not accepted):
# Check the rejection reason as well.
with mininode_lock:
assert_equal(p2p.last_message["reject"].reason, reason)
@@ -88,7 +173,7 @@ class TestP2PConn(P2PInterface):
self.last_message.pop("getdata", None)
self.last_message.pop("getheaders", None)
msg = msg_headers()
- msg.headers = [ CBlockHeader(block) ]
+ msg.headers = [CBlockHeader(block)]
if use_header:
self.send_message(msg)
else:
@@ -104,25 +189,6 @@ class TestP2PConn(P2PInterface):
self.wait_for_block(blockhash, timeout)
return self.last_message["block"].block
-# Used to keep track of anyone-can-spend outputs that we can use in the tests
-class UTXO():
- def __init__(self, sha256, n, nValue):
- self.sha256 = sha256
- self.n = n
- self.nValue = nValue
-
-# Helper for getting the script associated with a P2PKH
-def GetP2PKHScript(pubkeyhash):
- return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
-
-# Add signature for a P2PK witness program.
-def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
- tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
- signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
- txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
- txTo.rehash()
-
-
class SegWitTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
@@ -136,43 +202,116 @@ class SegWitTest(BitcoinTestFramework):
connect_nodes(self.nodes[0], 2)
self.sync_all()
- ''' Helpers '''
- # Build a block on top of node0's tip.
- def build_next_block(self, nVersion=4):
+ # Helper functions
+
+ def build_next_block(self, version=4):
+ """Build a block on top of node0's tip."""
tip = self.nodes[0].getbestblockhash()
height = self.nodes[0].getblockcount() + 1
block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1
block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.nVersion = nVersion
+ block.version = version
block.rehash()
return block
- # Adds list of transactions to block, adds witness commitment, then solves.
def update_witness_block_with_transactions(self, block, tx_list, nonce=0):
+ """Add list of transactions to block, adds witness commitment, then solves."""
block.vtx.extend(tx_list)
add_witness_commitment(block, nonce)
block.solve()
- return
- ''' Individual tests '''
- def test_witness_services(self):
- self.log.info("Verifying NODE_WITNESS service bit")
- assert((self.test_node.nServices & NODE_WITNESS) != 0)
+ def run_test(self):
+ # Setup the p2p connections and start up the network thread.
+ # self.test_node sets NODE_WITNESS|NODE_NETWORK
+ self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
+ # self.old_node sets only NODE_NETWORK
+ self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
+ # self.std_node is for testing node1 (fRequireStandard=true)
+ self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
+
+ for conn in (self.test_node, self.old_node, self.std_node):
+ conn.wait_for_verack()
+
+ assert self.test_node.nServices & NODE_WITNESS != 0
+
+ # Keep a place to store utxo's that can be used in later tests
+ self.utxo = []
+
+ # Segwit status 'defined'
+ self.segwit_status = 'defined'
+
+ self.test_non_witness_transaction()
+ self.test_unnecessary_witness_before_segwit_activation()
+ self.test_v0_outputs_arent_spendable()
+ self.test_block_relay()
+ self.advance_to_segwit_started()
+
+ # Segwit status 'started'
+
+ self.test_getblocktemplate_before_lockin()
+ self.advance_to_segwit_lockin()
+
+ # Segwit status 'locked_in'
+
+ self.test_unnecessary_witness_before_segwit_activation()
+ self.test_witness_tx_relay_before_segwit_activation()
+ self.test_block_relay()
+ self.test_standardness_v0()
+ self.advance_to_segwit_active()
+
+ # Segwit status 'active'
+
+ self.test_p2sh_witness()
+ self.test_witness_commitments()
+ self.test_block_malleability()
+ self.test_witness_block_size()
+ self.test_submit_block()
+ self.test_extra_witness_data()
+ self.test_max_witness_push_length()
+ self.test_max_witness_program_length()
+ self.test_witness_input_length()
+ self.test_block_relay()
+ self.test_tx_relay_after_segwit_activation()
+ self.test_standardness_v0()
+ self.test_segwit_versions()
+ self.test_premature_coinbase_witness_spend()
+ self.test_uncompressed_pubkey()
+ self.test_signature_version_1()
+ self.test_non_standard_witness_blinding()
+ self.test_non_standard_witness()
+ self.test_upgrade_after_activation()
+ self.test_witness_sigops()
+
+ # Individual tests
+
+ def subtest(func): # noqa: N805
+ """Wraps the subtests for logging and state assertions."""
+ def func_wrapper(self, *args, **kwargs):
+ self.log.info("Subtest: {} (Segwit status = {})".format(func.__name__, self.segwit_status))
+ # Assert segwit status is as expected
+ assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
+ func(self, *args, **kwargs)
+ # Each subtest should leave some utxos for the next subtest
+ assert self.utxo
+ sync_blocks(self.nodes)
+ # Assert segwit status is as expected at end of subtest
+ assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
+ return func_wrapper
- # See if sending a regular transaction works, and create a utxo
- # to use in later tests.
+ @subtest
def test_non_witness_transaction(self):
+ """See if sending a regular transaction works, and create a utxo to use in later tests."""
# Mine a block with an anyone-can-spend coinbase,
# let it mature, then try to spend it.
- self.log.info("Testing non-witness transaction")
- block = self.build_next_block(nVersion=1)
+
+ block = self.build_next_block(version=1)
block.solve()
self.test_node.send_message(msg_block(block))
- self.test_node.sync_with_ping() # make sure the block was processed
+ self.test_node.sync_with_ping() # make sure the block was processed
txid = block.vtx[0].sha256
- self.nodes[0].generate(99) # let the block mature
+ self.nodes[0].generate(99) # let the block mature
# Create a transaction that spends the coinbase
tx = CTransaction()
@@ -185,24 +324,19 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(msg_tx(tx).serialize(), msg_witness_tx(tx).serialize())
self.test_node.send_message(msg_witness_tx(tx))
- self.test_node.sync_with_ping() # make sure the tx was processed
+ self.test_node.sync_with_ping() # make sure the tx was processed
assert(tx.hash in self.nodes[0].getrawmempool())
# Save this transaction for later
- self.utxo.append(UTXO(tx.sha256, 0, 49*100000000))
+ self.utxo.append(UTXO(tx.sha256, 0, 49 * 100000000))
self.nodes[0].generate(1)
-
- # Verify that blocks with witnesses are rejected before activation.
+ @subtest
def test_unnecessary_witness_before_segwit_activation(self):
- self.log.info("Testing behavior of unnecessary witnesses")
- # For now, rely on earlier tests to have created at least one utxo for
- # us to use
- assert(len(self.utxo) > 0)
- assert(get_bip9_status(self.nodes[0], 'segwit')['status'] != 'active')
+ """Verify that blocks with witnesses are rejected before activation."""
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, CScript([OP_TRUE])))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE])))
tx.wit.vtxinwit.append(CTxInWitness())
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)])]
@@ -212,7 +346,7 @@ class SegWitTest(BitcoinTestFramework):
assert(tx.sha256 != tx.calc_sha256(with_witness=True))
# Construct a segwit-signaling block that includes the transaction.
- block = self.build_next_block(nVersion=(VB_TOP_BITS|(1 << VB_WITNESS_BIT)))
+ block = self.build_next_block(version=(VB_TOP_BITS | (1 << VB_WITNESS_BIT)))
self.update_witness_block_with_transactions(block, [tx])
# Sending witness data before activation is not allowed (anti-spam
# rule).
@@ -220,7 +354,7 @@ class SegWitTest(BitcoinTestFramework):
# TODO: fix synchronization so we can test reject reason
# Right now, bitcoind delays sending reject messages for blocks
# until the future, making synchronization here difficult.
- #assert_equal(self.test_node.last_message["reject"].reason, "unexpected-witness")
+ # assert_equal(self.test_node.last_message["reject"].reason, "unexpected-witness")
# But it should not be permanently marked bad...
# Resend without witness information.
@@ -228,37 +362,136 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.sync_with_ping()
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
- sync_blocks(self.nodes)
-
# Update our utxo list; we spent the first entry.
self.utxo.pop(0)
self.utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
- # ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
- # backdated so that it applies to all blocks, going back to the genesis
- # block.
- #
- # Consequently, version 0 witness outputs are never spendable without
- # witness, and so can't be spent before segwit activation (the point at which
- # blocks are permitted to contain witnesses).
+ @subtest
+ def test_block_relay(self):
+ """Test that block requests to NODE_WITNESS peer are with MSG_WITNESS_FLAG.
+
+ This is true regardless of segwit activation.
+ Also test that we don't ask for blocks from unupgraded peers."""
+
+ blocktype = 2 | MSG_WITNESS_FLAG
+
+ # test_node has set NODE_WITNESS, so all getdata requests should be for
+ # witness blocks.
+ # Test announcing a block via inv results in a getdata, and that
+ # announcing a version 4 or random VB block with a header results in a getdata
+ block1 = self.build_next_block()
+ block1.solve()
+
+ self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ test_witness_block(self.nodes[0].rpc, self.test_node, block1, True)
+
+ block2 = self.build_next_block(version=4)
+ block2.solve()
+
+ self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ test_witness_block(self.nodes[0].rpc, self.test_node, block2, True)
+
+ block3 = self.build_next_block(version=(VB_TOP_BITS | (1 << 15)))
+ block3.solve()
+ self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ test_witness_block(self.nodes[0].rpc, self.test_node, block3, True)
+
+ # Check that we can getdata for witness blocks or regular blocks,
+ # and the right thing happens.
+ if self.segwit_status != 'active':
+ # Before activation, we should be able to request old blocks with
+ # or without witness, and they should be the same.
+ chain_height = self.nodes[0].getblockcount()
+ # Pick 10 random blocks on main chain, and verify that getdata's
+ # for MSG_BLOCK, MSG_WITNESS_BLOCK, and rpc getblock() are equal.
+ all_heights = list(range(chain_height + 1))
+ random.shuffle(all_heights)
+ all_heights = all_heights[0:10]
+ for height in all_heights:
+ block_hash = self.nodes[0].getblockhash(height)
+ rpc_block = self.nodes[0].getblock(block_hash, False)
+ block_hash = int(block_hash, 16)
+ block = self.test_node.request_block(block_hash, 2)
+ wit_block = self.test_node.request_block(block_hash, 2 | MSG_WITNESS_FLAG)
+ assert_equal(block.serialize(True), wit_block.serialize(True))
+ assert_equal(block.serialize(), hex_str_to_bytes(rpc_block))
+ else:
+ # After activation, witness blocks and non-witness blocks should
+ # be different. Verify rpc getblock() returns witness blocks, while
+ # getdata respects the requested type.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [])
+ # This gives us a witness commitment.
+ assert(len(block.vtx[0].wit.vtxinwit) == 1)
+ assert(len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1)
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ # Now try to retrieve it...
+ rpc_block = self.nodes[0].getblock(block.hash, False)
+ non_wit_block = self.test_node.request_block(block.sha256, 2)
+ wit_block = self.test_node.request_block(block.sha256, 2 | MSG_WITNESS_FLAG)
+ assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block))
+ assert_equal(wit_block.serialize(False), non_wit_block.serialize())
+ assert_equal(wit_block.serialize(True), block.serialize(True))
+
+ # Test size, vsize, weight
+ rpc_details = self.nodes[0].getblock(block.hash, True)
+ assert_equal(rpc_details["size"], len(block.serialize(True)))
+ assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
+ weight = 3 * len(block.serialize(False)) + len(block.serialize(True))
+ assert_equal(rpc_details["weight"], weight)
+
+ # Upgraded node should not ask for blocks from unupgraded
+ block4 = self.build_next_block(version=4)
+ block4.solve()
+ self.old_node.getdataset = set()
+
+ # Blocks can be requested via direct-fetch (immediately upon processing the announcement)
+ # or via parallel download (with an indeterminate delay from processing the announcement)
+ # so to test that a block is NOT requested, we could guess a time period to sleep for,
+ # and then check. We can avoid the sleep() by taking advantage of transaction getdata's
+ # being processed after block getdata's, and announce a transaction as well,
+ # and then check to see if that particular getdata has been received.
+ # Since 0.14, inv's will only be responded to with a getheaders, so send a header
+ # to announce this block.
+ msg = msg_headers()
+ msg.headers = [CBlockHeader(block4)]
+ self.old_node.send_message(msg)
+ self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
+ assert(block4.sha256 not in self.old_node.getdataset)
+
+ @subtest
def test_v0_outputs_arent_spendable(self):
- self.log.info("Testing that v0 witness program outputs aren't spendable before activation")
+ """Test that v0 outputs aren't spendable before segwit activation.
+
+ ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
+ backdated so that it applies to all blocks, going back to the genesis
+ block.
- assert len(self.utxo), "self.utxo is empty"
+ Consequently, version 0 witness outputs are never spendable without
+ witness, and so can't be spent before segwit activation (the point at which
+ blocks are permitted to contain witnesses)."""
+
+ # node2 doesn't need to be connected for this test.
+ # (If it's connected, node0 may propogate an invalid block to it over
+ # compact blocks and the nodes would have inconsistent tips.)
+ disconnect_nodes(self.nodes[0], 2)
# Create two outputs, a p2wsh and p2sh-p2wsh
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
- p2sh_pubkey = hash160(scriptPubKey)
- p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+ p2sh_pubkey = hash160(script_pubkey)
+ p2sh_script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
value = self.utxo[0].nValue // 3
tx = CTransaction()
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b'')]
- tx.vout = [CTxOut(value, scriptPubKey), CTxOut(value, p2sh_scriptPubKey)]
+ tx.vout = [CTxOut(value, script_pubkey), CTxOut(value, p2sh_script_pubkey)]
tx.vout.append(CTxOut(value, CScript([OP_TRUE])))
tx.rehash()
txid = tx.sha256
@@ -268,7 +501,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx])
# Verify that segwit isn't activated. A block serialized with witness
# should be rejected prior to activation.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason = b'unexpected-witness')
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
# Now send the block without witness. It should be accepted
test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)
@@ -281,7 +514,7 @@ class SegWitTest(BitcoinTestFramework):
p2wsh_tx.rehash()
p2sh_p2wsh_tx = CTransaction()
- p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([scriptPubKey]))]
+ p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([script_pubkey]))]
p2sh_p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
p2sh_p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
p2sh_p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
@@ -306,50 +539,288 @@ class SegWitTest(BitcoinTestFramework):
# TODO: support multiple acceptable reject reasons.
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
+ connect_nodes(self.nodes[0], 2)
+
self.utxo.pop(0)
self.utxo.append(UTXO(txid, 2, value))
- # Mine enough blocks for segwit's vb state to be 'started'.
+ @subtest
def advance_to_segwit_started(self):
+ """Mine enough blocks for segwit's vb state to be 'started'."""
height = self.nodes[0].getblockcount()
# Will need to rewrite the tests here if we are past the first period
assert(height < VB_PERIOD - 1)
- # Genesis block is 'defined'.
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'defined')
# Advance to end of period, status should now be 'started'
- self.nodes[0].generate(VB_PERIOD-height-1)
+ self.nodes[0].generate(VB_PERIOD - height - 1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
+ self.segwit_status = 'started'
+
+ @subtest
+ def test_getblocktemplate_before_lockin(self):
+ # Node0 is segwit aware, node2 is not.
+ for node in [self.nodes[0], self.nodes[2]]:
+ gbt_results = node.getblocktemplate()
+ block_version = gbt_results['version']
+ # If we're not indicating segwit support, we will still be
+ # signalling for segwit activation.
+ assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0])
+ # If we don't specify the segwit rule, then we won't get a default
+ # commitment.
+ assert('default_witness_commitment' not in gbt_results)
+
+ # Workaround:
+ # Can either change the tip, or change the mempool and wait 5 seconds
+ # to trigger a recomputation of getblocktemplate.
+ txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
+ # Using mocktime lets us avoid sleep()
+ sync_mempools(self.nodes)
+ self.nodes[0].setmocktime(int(time.time()) + 10)
+ self.nodes[2].setmocktime(int(time.time()) + 10)
+
+ for node in [self.nodes[0], self.nodes[2]]:
+ gbt_results = node.getblocktemplate({"rules": ["segwit"]})
+ block_version = gbt_results['version']
+ if node == self.nodes[2]:
+ # If this is a non-segwit node, we should still not get a witness
+ # commitment, nor a version bit signalling segwit.
+ assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
+ assert('default_witness_commitment' not in gbt_results)
+ else:
+ # For segwit-aware nodes, check the version bit and the witness
+ # commitment are correct.
+ assert(block_version & (1 << VB_WITNESS_BIT) != 0)
+ assert('default_witness_commitment' in gbt_results)
+ witness_commitment = gbt_results['default_witness_commitment']
- # Mine enough blocks to lock in segwit, but don't activate.
- # TODO: we could verify that lockin only happens at the right threshold of
- # signalling blocks, rather than just at the right period boundary.
+ # Check that default_witness_commitment is present.
+ witness_root = CBlock.get_merkle_root([ser_uint256(0),
+ ser_uint256(txid)])
+ script = get_witness_script(witness_root, 0)
+ assert_equal(witness_commitment, bytes_to_hex_str(script))
+
+ # undo mocktime
+ self.nodes[0].setmocktime(0)
+ self.nodes[2].setmocktime(0)
+
+ @subtest
def advance_to_segwit_lockin(self):
+ """Mine enough blocks to lock in segwit, but don't activate."""
+ # TODO: we could verify that lockin only happens at the right threshold of
+ # signalling blocks, rather than just at the right period boundary.
+
height = self.nodes[0].getblockcount()
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
# Advance to end of period, and verify lock-in happens at the end
- self.nodes[0].generate(VB_PERIOD-1)
+ self.nodes[0].generate(VB_PERIOD - 1)
height = self.nodes[0].getblockcount()
assert((height % VB_PERIOD) == VB_PERIOD - 2)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
self.nodes[0].generate(1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
+ self.segwit_status = 'locked_in'
+ @subtest
+ def test_witness_tx_relay_before_segwit_activation(self):
- # Mine enough blocks to activate segwit.
- # TODO: we could verify that activation only happens at the right threshold
- # of signalling blocks, rather than just at the right period boundary.
+ # Generate a transaction that doesn't require a witness, but send it
+ # with a witness. Should be rejected for premature-witness, but should
+ # not be added to recently rejected list.
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
+ tx.wit.vtxinwit.append(CTxInWitness())
+ tx.wit.vtxinwit[0].scriptWitness.stack = [b'a']
+ tx.rehash()
+
+ tx_hash = tx.sha256
+ tx_value = tx.vout[0].nValue
+
+ # Verify that if a peer doesn't set nServices to include NODE_WITNESS,
+ # the getdata is just for the non-witness portion.
+ self.old_node.announce_tx_and_wait_for_getdata(tx)
+ assert(self.old_node.last_message["getdata"].inv[0].type == 1)
+
+ # Since we haven't delivered the tx yet, inv'ing the same tx from
+ # a witness transaction ought not result in a getdata.
+ self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2, success=False)
+
+ # Delivering this transaction with witness should fail (no matter who
+ # its from)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+ test_transaction_acceptance(self.nodes[0].rpc, self.old_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=False)
+
+ # But eliminating the witness should fix it
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+
+ # Cleanup: mine the first transaction and update utxo
+ self.nodes[0].generate(1)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx_hash, 0, tx_value))
+
+ @subtest
+ def test_standardness_v0(self):
+ """Test V0 txout standardness.
+
+ V0 segwit outputs and inputs are always standard.
+ V0 segwit inputs may only be mined after activation, but not before."""
+
+ witness_program = CScript([OP_TRUE])
+ witness_hash = sha256(witness_program)
+ script_pubkey = CScript([OP_0, witness_hash])
+
+ p2sh_pubkey = hash160(witness_program)
+ p2sh_script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+
+ # First prepare a p2sh output (so that spending it will pass standardness)
+ p2sh_tx = CTransaction()
+ p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
+ p2sh_tx.vout = [CTxOut(self.utxo[0].nValue - 1000, p2sh_script_pubkey)]
+ p2sh_tx.rehash()
+
+ # Mine it on test_node to create the confirmed output.
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_tx, with_witness=True, accepted=True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # Now test standardness of v0 P2WSH outputs.
+ # Start by creating a transaction with two outputs.
+ tx = CTransaction()
+ tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
+ tx.vout = [CTxOut(p2sh_tx.vout[0].nValue - 10000, script_pubkey)]
+ tx.vout.append(CTxOut(8000, script_pubkey)) # Might burn this later
+ tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER # Just to have the option to bump this tx from the mempool
+ tx.rehash()
+
+ # This is always accepted, since the mempool policy is to consider segwit as always active
+ # and thus allow segwit outputs
+ test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=True)
+
+ # Now create something that looks like a P2PKH output. This won't be spendable.
+ script_pubkey = CScript([OP_0, hash160(witness_hash)])
+ tx2 = CTransaction()
+ # tx was accepted, so we spend the second output.
+ tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
+ tx2.vout = [CTxOut(7000, script_pubkey)]
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ tx2.rehash()
+
+ test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=True)
+
+ # Now update self.utxo for later tests.
+ tx3 = CTransaction()
+ # tx and tx2 were both accepted. Don't bother trying to reclaim the
+ # P2PKH output; just send tx's first output back to an anyone-can-spend.
+ sync_mempools([self.nodes[0], self.nodes[1]])
+ tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
+ tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ tx3.rehash()
+ if self.segwit_status != 'active':
+ # Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
+ # in blocks and the tx is impossible to mine right now.
+ assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ # Create the same output as tx3, but by replacing tx
+ tx3_out = tx3.vout[0]
+ tx3 = tx
+ tx3.vout = [tx3_out]
+ tx3.rehash()
+ assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
+
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+
+ @subtest
def advance_to_segwit_active(self):
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
+ """Mine enough blocks to activate segwit."""
+ # TODO: we could verify that activation only happens at the right threshold
+ # of signalling blocks, rather than just at the right period boundary.
+
height = self.nodes[0].getblockcount()
- self.nodes[0].generate(VB_PERIOD - (height%VB_PERIOD) - 2)
+ self.nodes[0].generate(VB_PERIOD - (height % VB_PERIOD) - 2)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
self.nodes[0].generate(1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'active')
+ self.segwit_status = 'active'
+
+ @subtest
+ def test_p2sh_witness(self):
+ """Test P2SH wrapped witness programs."""
+
+ # Prepare the p2sh-wrapped witness output
+ witness_program = CScript([OP_DROP, OP_TRUE])
+ witness_hash = sha256(witness_program)
+ p2wsh_pubkey = CScript([OP_0, witness_hash])
+ p2sh_witness_hash = hash160(p2wsh_pubkey)
+ script_pubkey = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
+ script_sig = CScript([p2wsh_pubkey]) # a push of the redeem script
+
+ # Fund the P2SH output
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
+ tx.rehash()
+ # Verify mempool acceptance and block validity
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True, with_witness=True)
+ sync_blocks(self.nodes)
+
+ # Now test attempts to spend the output.
+ spend_tx = CTransaction()
+ spend_tx.vin.append(CTxIn(COutPoint(tx.sha256, 0), script_sig))
+ spend_tx.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))
+ spend_tx.rehash()
- # This test can only be run after segwit has activated
+ # This transaction should not be accepted into the mempool pre- or
+ # post-segwit. Mempool acceptance will use SCRIPT_VERIFY_WITNESS which
+ # will require a witness to spend a witness program regardless of
+ # segwit activation. Note that older bitcoind's that are not
+ # segwit-aware would also reject this for failing CLEANSTACK.
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
+
+ # Try to put the witness script in the script_sig, should also fail.
+ spend_tx.vin[0].script_sig = CScript([p2wsh_pubkey, b'a'])
+ spend_tx.rehash()
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
+
+ # Now put the witness script in the witness, should succeed after
+ # segwit activates.
+ spend_tx.vin[0].scriptSig = script_sig
+ spend_tx.rehash()
+ spend_tx.wit.vtxinwit.append(CTxInWitness())
+ spend_tx.wit.vtxinwit[0].scriptWitness.stack = [b'a', witness_program]
+
+ # Verify mempool acceptance
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=True, accepted=True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [spend_tx])
+
+ # If we're after activation, then sending this with witnesses should be valid.
+ # This no longer works before activation, because SCRIPT_VERIFY_WITNESS
+ # is always set.
+ # TODO: rewrite this test to make clear that it only works after activation.
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+
+ # Update self.utxo
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(spend_tx.sha256, 0, spend_tx.vout[0].nValue))
+
+ @subtest
def test_witness_commitments(self):
- self.log.info("Testing witness commitments")
+ """Test witness commitments.
+
+ This test can only be run after segwit has activated."""
# First try a correct witness commitment.
block = self.build_next_block()
@@ -374,21 +845,20 @@ class SegWitTest(BitcoinTestFramework):
test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=True)
# Now test commitments with actual transactions
- assert (len(self.utxo) > 0)
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
# Let's construct a witness program
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
+ script_pubkey = CScript([OP_0, witness_hash])
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
# tx2 will spend tx1, and send back to a regular anyone-can-spend address
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, witness_program))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, witness_program))
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
@@ -416,7 +886,7 @@ class SegWitTest(BitcoinTestFramework):
block_3.vtx[0].rehash()
block_3.hashMerkleRoot = block_3.calc_merkle_root()
block_3.rehash()
- assert(len(block_3.vtx[0].vout) == 4) # 3 OP_returns
+ assert(len(block_3.vtx[0].vout) == 4) # 3 OP_returns
block_3.solve()
test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=True)
@@ -425,7 +895,7 @@ class SegWitTest(BitcoinTestFramework):
block_4 = self.build_next_block()
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
- tx3.vout.append(CTxOut(tx.vout[0].nValue-1000, witness_program))
+ tx3.vout.append(CTxOut(tx.vout[0].nValue - 1000, witness_program))
tx3.rehash()
block_4.vtx.append(tx3)
block_4.hashMerkleRoot = block_4.calc_merkle_root()
@@ -436,9 +906,8 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
-
+ @subtest
def test_block_malleability(self):
- self.log.info("Testing witness block malleability")
# Make sure that a block that has too big a virtual size
# because of a too-large coinbase witness is not permanently
@@ -447,7 +916,7 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a'*5000000)
+ block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 5000000)
assert(get_virtual_size(block) > MAX_BLOCK_BASE_SIZE)
# We can't send over the p2p network, because this is too big to relay
@@ -470,16 +939,15 @@ class SegWitTest(BitcoinTestFramework):
# Change the nonce -- should not cause the block to be permanently
# failed
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ ser_uint256(1) ]
+ block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(1)]
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
# Changing the witness reserved value doesn't change the block hash
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ ser_uint256(0) ]
+ block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
+ @subtest
def test_witness_block_size(self):
- self.log.info("Testing witness block size limit")
# TODO: Test that non-witness carrying blocks can't exceed 1MB
# Skipping this test for now; this is covered in p2p-fullblocktest.py
@@ -492,21 +960,21 @@ class SegWitTest(BitcoinTestFramework):
# The witness program will be a bunch of OP_2DROP's, followed by OP_TRUE.
# This should give us plenty of room to tweak the spending tx's
# virtual size.
- NUM_DROPS = 200 # 201 max ops per script!
+ NUM_DROPS = 200 # 201 max ops per script!
NUM_OUTPUTS = 50
- witness_program = CScript([OP_2DROP]*NUM_DROPS + [OP_TRUE])
+ witness_program = CScript([OP_2DROP] * NUM_DROPS + [OP_TRUE])
witness_hash = uint256_from_str(sha256(witness_program))
- scriptPubKey = CScript([OP_0, ser_uint256(witness_hash)])
+ script_pubkey = CScript([OP_0, ser_uint256(witness_hash)])
prevout = COutPoint(self.utxo[0].sha256, self.utxo[0].n)
value = self.utxo[0].nValue
parent_tx = CTransaction()
parent_tx.vin.append(CTxIn(prevout, b""))
- child_value = int(value/NUM_OUTPUTS)
+ child_value = int(value / NUM_OUTPUTS)
for i in range(NUM_OUTPUTS):
- parent_tx.vout.append(CTxOut(child_value, scriptPubKey))
+ parent_tx.vout.append(CTxOut(child_value, script_pubkey))
parent_tx.vout[0].nValue -= 50000
assert(parent_tx.vout[0].nValue > 0)
parent_tx.rehash()
@@ -517,17 +985,17 @@ class SegWitTest(BitcoinTestFramework):
child_tx.vout = [CTxOut(value - 100000, CScript([OP_TRUE]))]
for i in range(NUM_OUTPUTS):
child_tx.wit.vtxinwit.append(CTxInWitness())
- child_tx.wit.vtxinwit[-1].scriptWitness.stack = [b'a'*195]*(2*NUM_DROPS) + [witness_program]
+ child_tx.wit.vtxinwit[-1].scriptWitness.stack = [b'a' * 195] * (2 * NUM_DROPS) + [witness_program]
child_tx.rehash()
self.update_witness_block_with_transactions(block, [parent_tx, child_tx])
vsize = get_virtual_size(block)
- additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize)*4
+ additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize) * 4
i = 0
while additional_bytes > 0:
# Add some more bytes to each input until we hit MAX_BLOCK_BASE_SIZE+1
- extra_bytes = min(additional_bytes+1, 55)
- block.vtx[-1].wit.vtxinwit[int(i/(2*NUM_DROPS))].scriptWitness.stack[i%(2*NUM_DROPS)] = b'a'*(195+extra_bytes)
+ extra_bytes = min(additional_bytes + 1, 55)
+ block.vtx[-1].wit.vtxinwit[int(i / (2 * NUM_DROPS))].scriptWitness.stack[i % (2 * NUM_DROPS)] = b'a' * (195 + extra_bytes)
additional_bytes -= extra_bytes
i += 1
@@ -538,13 +1006,13 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)
# Make sure that our test case would exceed the old max-network-message
# limit
- assert(len(block.serialize(True)) > 2*1024*1024)
+ assert(len(block.serialize(True)) > 2 * 1024 * 1024)
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
# Now resize the second transaction to make the block fit.
cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])
- block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0] = b'a'*(cur_length-1)
+ block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (cur_length - 1)
block.vtx[0].vout.pop()
add_witness_commitment(block)
block.solve()
@@ -556,16 +1024,15 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
self.utxo.append(UTXO(block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue))
-
- # submitblock will try to add the nonce automatically, so that mining
- # software doesn't need to worry about doing so itself.
+ @subtest
def test_submit_block(self):
+ """Test that submitblock adds the nonce automatically when possible."""
block = self.build_next_block()
# Try using a custom nonce and then don't supply it.
# This shouldn't possibly work.
add_witness_commitment(block, nonce=1)
- block.vtx[0].wit = CTxWitness() # drop the nonce
+ block.vtx[0].wit = CTxWitness() # drop the nonce
block.solve()
self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
assert(self.nodes[0].getbestblockhash() != block.hash)
@@ -593,24 +1060,21 @@ class SegWitTest(BitcoinTestFramework):
# Tip should not advance!
assert(self.nodes[0].getbestblockhash() != block_2.hash)
-
- # Consensus tests of extra witness data in a transaction.
+ @subtest
def test_extra_witness_data(self):
- self.log.info("Testing extra witness data in tx")
-
- assert(len(self.utxo) > 0)
+ """Test extra witness data in a transaction."""
block = self.build_next_block()
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
# First try extra witness data on a tx that doesn't require a witness
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-2000, scriptPubKey))
- tx.vout.append(CTxOut(1000, CScript([OP_TRUE]))) # non-witness output
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 2000, script_pubkey))
+ tx.vout.append(CTxOut(1000, CScript([OP_TRUE]))) # non-witness output
tx.wit.vtxinwit.append(CTxInWitness())
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([])]
tx.rehash()
@@ -631,12 +1095,12 @@ class SegWitTest(BitcoinTestFramework):
# Now try extra witness/signature data on an input that DOES require a
# witness
tx2 = CTransaction()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b"")) # witness output
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 1), b"")) # non-witness
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b"")) # witness output
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 1), b"")) # non-witness
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
tx2.wit.vtxinwit.extend([CTxInWitness(), CTxInWitness()])
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ CScript([CScriptNum(1)]), CScript([CScriptNum(1)]), witness_program ]
- tx2.wit.vtxinwit[1].scriptWitness.stack = [ CScript([OP_TRUE]) ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), CScript([CScriptNum(1)]), witness_program]
+ tx2.wit.vtxinwit[1].scriptWitness.stack = [CScript([OP_TRUE])]
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2])
@@ -669,37 +1133,36 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
-
+ @subtest
def test_max_witness_push_length(self):
- ''' Should only allow up to 520 byte pushes in witness stack '''
- self.log.info("Testing maximum witness push size")
+ """Test that witness stack can only allow up to 520 byte pushes."""
+
MAX_SCRIPT_ELEMENT_SIZE = 520
- assert(len(self.utxo))
block = self.build_next_block()
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE])))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))
tx2.wit.vtxinwit.append(CTxInWitness())
# First try a 521-byte stack element
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ b'a'*(MAX_SCRIPT_ELEMENT_SIZE+1), witness_program ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * (MAX_SCRIPT_ELEMENT_SIZE + 1), witness_program]
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx, tx2])
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
# Now reduce the length of the stack element
- tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a'*(MAX_SCRIPT_ELEMENT_SIZE)
+ tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (MAX_SCRIPT_ELEMENT_SIZE)
add_witness_commitment(block)
block.solve()
@@ -709,31 +1172,30 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
+ @subtest
def test_max_witness_program_length(self):
- # Can create witness outputs that are long, but can't be greater than
- # 10k bytes to successfully spend
- self.log.info("Testing maximum witness program length")
- assert(len(self.utxo))
+ """Test that witness outputs greater than 10kB can't be spent."""
+
MAX_PROGRAM_LENGTH = 10000
# This program is 19 max pushes (9937 bytes), then 64 more opcode-bytes.
- long_witness_program = CScript([b'a'*520]*19 + [OP_DROP]*63 + [OP_TRUE])
- assert(len(long_witness_program) == MAX_PROGRAM_LENGTH+1)
+ long_witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 63 + [OP_TRUE])
+ assert(len(long_witness_program) == MAX_PROGRAM_LENGTH + 1)
long_witness_hash = sha256(long_witness_program)
- long_scriptPubKey = CScript([OP_0, long_witness_hash])
+ long_script_pubkey = CScript([OP_0, long_witness_hash])
block = self.build_next_block()
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, long_scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, long_script_pubkey))
tx.rehash()
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE])))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))
tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a']*44 + [long_witness_program]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a'] * 44 + [long_witness_program]
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx, tx2])
@@ -741,15 +1203,15 @@ class SegWitTest(BitcoinTestFramework):
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
# Try again with one less byte in the witness program
- witness_program = CScript([b'a'*520]*19 + [OP_DROP]*62 + [OP_TRUE])
+ witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 62 + [OP_TRUE])
assert(len(witness_program) == MAX_PROGRAM_LENGTH)
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
- tx.vout[0] = CTxOut(tx.vout[0].nValue, scriptPubKey)
+ tx.vout[0] = CTxOut(tx.vout[0].nValue, script_pubkey)
tx.rehash()
tx2.vin[0].prevout.hash = tx.sha256
- tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a']*43 + [witness_program]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a'] * 43 + [witness_program]
tx2.rehash()
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx, tx2])
@@ -758,22 +1220,20 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
-
+ @subtest
def test_witness_input_length(self):
- ''' Ensure that vin length must match vtxinwit length '''
- self.log.info("Testing witness input length")
- assert(len(self.utxo))
+ """Test that vin length must match vtxinwit length."""
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
# Create a transaction that splits our utxo into many outputs
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- nValue = self.utxo[0].nValue
+ value = self.utxo[0].nValue
for i in range(10):
- tx.vout.append(CTxOut(int(nValue/10), scriptPubKey))
+ tx.vout.append(CTxOut(int(value / 10), script_pubkey))
tx.vout[0].nValue -= 1000
assert(tx.vout[0].nValue >= 0)
@@ -805,7 +1265,7 @@ class SegWitTest(BitcoinTestFramework):
tx2 = BrokenCTransaction()
for i in range(10):
tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b""))
- tx2.vout.append(CTxOut(nValue-3000, CScript([OP_TRUE])))
+ tx2.vout.append(CTxOut(value - 3000, CScript([OP_TRUE])))
# First try using a too long vtxinwit
for i in range(11):
@@ -827,7 +1287,7 @@ class SegWitTest(BitcoinTestFramework):
# Now make one of the intermediate witnesses be incorrect
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[-1].scriptWitness.stack = [b'a', witness_program]
- tx2.wit.vtxinwit[5].scriptWitness.stack = [ witness_program ]
+ tx2.wit.vtxinwit[5].scriptWitness.stack = [witness_program]
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
@@ -842,65 +1302,23 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
+ @subtest
+ def test_tx_relay_after_segwit_activation(self):
+ """Test transaction relay after segwit activation.
- def test_witness_tx_relay_before_segwit_activation(self):
- self.log.info("Testing relay of witness transactions")
- # Generate a transaction that doesn't require a witness, but send it
- # with a witness. Should be rejected for premature-witness, but should
- # not be added to recently rejected list.
- assert(len(self.utxo))
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
- tx.wit.vtxinwit.append(CTxInWitness())
- tx.wit.vtxinwit[0].scriptWitness.stack = [ b'a' ]
- tx.rehash()
-
- tx_hash = tx.sha256
- tx_value = tx.vout[0].nValue
-
- # Verify that if a peer doesn't set nServices to include NODE_WITNESS,
- # the getdata is just for the non-witness portion.
- self.old_node.announce_tx_and_wait_for_getdata(tx)
- assert(self.old_node.last_message["getdata"].inv[0].type == 1)
-
- # Since we haven't delivered the tx yet, inv'ing the same tx from
- # a witness transaction ought not result in a getdata.
- self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2, success=False)
-
- # Delivering this transaction with witness should fail (no matter who
- # its from)
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
- assert_equal(len(self.nodes[1].getrawmempool()), 0)
- test_transaction_acceptance(self.nodes[0].rpc, self.old_node, tx, with_witness=True, accepted=False)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=False)
-
- # But eliminating the witness should fix it
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
-
- # Cleanup: mine the first transaction and update utxo
- self.nodes[0].generate(1)
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
-
- self.utxo.pop(0)
- self.utxo.append(UTXO(tx_hash, 0, tx_value))
-
+ After segwit activates, verify that mempool:
+ - rejects transactions with unnecessary/extra witnesses
+ - accepts transactions with valid witnesses
+ and that witness transactions are relayed to non-upgraded peers."""
- # After segwit activates, verify that mempool:
- # - rejects transactions with unnecessary/extra witnesses
- # - accepts transactions with valid witnesses
- # and that witness transactions are relayed to non-upgraded peers.
- def test_tx_relay_after_segwit_activation(self):
- self.log.info("Testing relay of witness transactions")
# Generate a transaction that doesn't require a witness, but send it
# with a witness. Should be rejected because we can't use a witness
# when spending a non-witness output.
- assert(len(self.utxo))
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
tx.wit.vtxinwit.append(CTxInWitness())
- tx.wit.vtxinwit[0].scriptWitness.stack = [ b'a' ]
+ tx.wit.vtxinwit[0].scriptWitness.stack = [b'a']
tx.rehash()
tx_hash = tx.sha256
@@ -917,10 +1335,10 @@ class SegWitTest(BitcoinTestFramework):
# Now try to add extra witness data to a valid witness tx.
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx_hash, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptPubKey))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))
tx2.rehash()
tx3 = CTransaction()
@@ -930,8 +1348,8 @@ class SegWitTest(BitcoinTestFramework):
# Add too-large for IsStandard witness and check that it does not enter reject filter
p2sh_program = CScript([OP_TRUE])
p2sh_pubkey = hash160(p2sh_program)
- witness_program2 = CScript([b'a'*400000])
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))
+ witness_program2 = CScript([b'a' * 400000])
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))
tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program2]
tx3.rehash()
@@ -943,17 +1361,17 @@ class SegWitTest(BitcoinTestFramework):
# Remove witness stuffing, instead add extra witness push on stack
tx3.vout[0] = CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))
- tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program ]
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program]
tx3.rehash()
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, with_witness=True, accepted=True)
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=False)
# Get rid of the extra witness, and verify acceptance.
- tx3.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
# Also check that old_node gets a tx announcement, even though this is
# a witness transaction.
- self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
+ self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
self.old_node.wait_for_inv([CInv(1, tx3.sha256)])
@@ -962,7 +1380,7 @@ class SegWitTest(BitcoinTestFramework):
raw_tx = self.nodes[0].getrawtransaction(tx3.hash, 1)
assert_equal(int(raw_tx["hash"], 16), tx3.calc_sha256(True))
assert_equal(raw_tx["size"], len(tx3.serialize_with_witness()))
- weight = len(tx3.serialize_with_witness()) + 3*len(tx3.serialize_without_witness())
+ weight = len(tx3.serialize_with_witness()) + 3 * len(tx3.serialize_without_witness())
vsize = math.ceil(weight / 4)
assert_equal(raw_tx["vsize"], vsize)
assert_equal(raw_tx["weight"], weight)
@@ -972,202 +1390,31 @@ class SegWitTest(BitcoinTestFramework):
# Cleanup: mine the transactions and update utxo for next test
self.nodes[0].generate(1)
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ @subtest
+ def test_segwit_versions(self):
+ """Test validity of future segwit version transactions.
- # Test that block requests to NODE_WITNESS peer are with MSG_WITNESS_FLAG
- # This is true regardless of segwit activation.
- # Also test that we don't ask for blocks from unupgraded peers
- def test_block_relay(self, segwit_activated):
- self.log.info("Testing block relay")
-
- blocktype = 2|MSG_WITNESS_FLAG
-
- # test_node has set NODE_WITNESS, so all getdata requests should be for
- # witness blocks.
- # Test announcing a block via inv results in a getdata, and that
- # announcing a version 4 or random VB block with a header results in a getdata
- block1 = self.build_next_block()
- block1.solve()
-
- self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block1, True)
-
- block2 = self.build_next_block(nVersion=4)
- block2.solve()
-
- self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, True)
-
- block3 = self.build_next_block(nVersion=(VB_TOP_BITS | (1<<15)))
- block3.solve()
- self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block3, True)
-
- # Check that we can getdata for witness blocks or regular blocks,
- # and the right thing happens.
- if segwit_activated == False:
- # Before activation, we should be able to request old blocks with
- # or without witness, and they should be the same.
- chain_height = self.nodes[0].getblockcount()
- # Pick 10 random blocks on main chain, and verify that getdata's
- # for MSG_BLOCK, MSG_WITNESS_BLOCK, and rpc getblock() are equal.
- all_heights = list(range(chain_height+1))
- random.shuffle(all_heights)
- all_heights = all_heights[0:10]
- for height in all_heights:
- block_hash = self.nodes[0].getblockhash(height)
- rpc_block = self.nodes[0].getblock(block_hash, False)
- block_hash = int(block_hash, 16)
- block = self.test_node.request_block(block_hash, 2)
- wit_block = self.test_node.request_block(block_hash, 2|MSG_WITNESS_FLAG)
- assert_equal(block.serialize(True), wit_block.serialize(True))
- assert_equal(block.serialize(), hex_str_to_bytes(rpc_block))
- else:
- # After activation, witness blocks and non-witness blocks should
- # be different. Verify rpc getblock() returns witness blocks, while
- # getdata respects the requested type.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [])
- # This gives us a witness commitment.
- assert(len(block.vtx[0].wit.vtxinwit) == 1)
- assert(len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
- # Now try to retrieve it...
- rpc_block = self.nodes[0].getblock(block.hash, False)
- non_wit_block = self.test_node.request_block(block.sha256, 2)
- wit_block = self.test_node.request_block(block.sha256, 2|MSG_WITNESS_FLAG)
- assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block))
- assert_equal(wit_block.serialize(False), non_wit_block.serialize())
- assert_equal(wit_block.serialize(True), block.serialize(True))
-
- # Test size, vsize, weight
- rpc_details = self.nodes[0].getblock(block.hash, True)
- assert_equal(rpc_details["size"], len(block.serialize(True)))
- assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
- weight = 3*len(block.serialize(False)) + len(block.serialize(True))
- assert_equal(rpc_details["weight"], weight)
-
- # Upgraded node should not ask for blocks from unupgraded
- block4 = self.build_next_block(nVersion=4)
- block4.solve()
- self.old_node.getdataset = set()
-
- # Blocks can be requested via direct-fetch (immediately upon processing the announcement)
- # or via parallel download (with an indeterminate delay from processing the announcement)
- # so to test that a block is NOT requested, we could guess a time period to sleep for,
- # and then check. We can avoid the sleep() by taking advantage of transaction getdata's
- # being processed after block getdata's, and announce a transaction as well,
- # and then check to see if that particular getdata has been received.
- # Since 0.14, inv's will only be responded to with a getheaders, so send a header
- # to announce this block.
- msg = msg_headers()
- msg.headers = [ CBlockHeader(block4) ]
- self.old_node.send_message(msg)
- self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
- assert(block4.sha256 not in self.old_node.getdataset)
-
- # V0 segwit outputs and inputs are always standard. V0 segwit inputs may only be mined after activation, but not before.
- def test_standardness_v0(self, segwit_activated):
- self.log.info("Testing standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before"))
- assert(len(self.utxo))
-
- witness_program = CScript([OP_TRUE])
- witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
-
- p2sh_pubkey = hash160(witness_program)
- p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
-
- # First prepare a p2sh output (so that spending it will pass standardness)
- p2sh_tx = CTransaction()
- p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
- p2sh_tx.vout = [CTxOut(self.utxo[0].nValue-1000, p2sh_scriptPubKey)]
- p2sh_tx.rehash()
-
- # Mine it on test_node to create the confirmed output.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_tx, with_witness=True, accepted=True)
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
-
- # Now test standardness of v0 P2WSH outputs.
- # Start by creating a transaction with two outputs.
- tx = CTransaction()
- tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
- tx.vout = [CTxOut(p2sh_tx.vout[0].nValue-10000, scriptPubKey)]
- tx.vout.append(CTxOut(8000, scriptPubKey)) # Might burn this later
- tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER # Just to have the option to bump this tx from the mempool
- tx.rehash()
-
- # This is always accepted, since the mempool policy is to consider segwit as always active
- # and thus allow segwit outputs
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=True)
-
- # Now create something that looks like a P2PKH output. This won't be spendable.
- scriptPubKey = CScript([OP_0, hash160(witness_hash)])
- tx2 = CTransaction()
- # tx was accepted, so we spend the second output.
- tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
- tx2.vout = [CTxOut(7000, scriptPubKey)]
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
- tx2.rehash()
-
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=True)
-
- # Now update self.utxo for later tests.
- tx3 = CTransaction()
- # tx and tx2 were both accepted. Don't bother trying to reclaim the
- # P2PKH output; just send tx's first output back to an anyone-can-spend.
- sync_mempools([self.nodes[0], self.nodes[1]])
- tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
- tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
- tx3.wit.vtxinwit.append(CTxInWitness())
- tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
- tx3.rehash()
- if not segwit_activated:
- # Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
- # in blocks and the tx is impossible to mine right now.
- assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
- # Create the same output as tx3, but by replacing tx
- tx3_out = tx3.vout[0]
- tx3 = tx
- tx3.vout = [tx3_out]
- tx3.rehash()
- assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
-
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
- self.utxo.pop(0)
- self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
- assert_equal(len(self.nodes[1].getrawmempool()), 0)
-
+ Future segwit version transactions are non-standard, but valid in blocks.
+ Can run this before and after segwit activation."""
- # Verify that future segwit upgraded transactions are non-standard,
- # but valid in blocks. Can run this before and after segwit activation.
- def test_segwit_versions(self):
- self.log.info("Testing standardness/consensus for segwit versions (0-16)")
- assert(len(self.utxo))
- NUM_TESTS = 17 # will test OP_0, OP1, ..., OP_16
- if (len(self.utxo) < NUM_TESTS):
+ num_tests = 17 # will test OP_0, OP1, ..., OP_16
+ if (len(self.utxo) < num_tests):
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- split_value = (self.utxo[0].nValue - 4000) // NUM_TESTS
- for i in range(NUM_TESTS):
+ split_value = (self.utxo[0].nValue - 4000) // num_tests
+ for i in range(num_tests):
tx.vout.append(CTxOut(split_value, CScript([OP_TRUE])))
tx.rehash()
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
self.utxo.pop(0)
- for i in range(NUM_TESTS):
+ for i in range(num_tests):
self.utxo.append(UTXO(tx.sha256, i, split_value))
sync_blocks(self.nodes)
@@ -1177,36 +1424,36 @@ class SegWitTest(BitcoinTestFramework):
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
assert_equal(len(self.nodes[1].getrawmempool()), 0)
- for version in list(range(OP_1, OP_16+1)) + [OP_0]:
+ for version in list(range(OP_1, OP_16 + 1)) + [OP_0]:
count += 1
- # First try to spend to a future version segwit scriptPubKey.
- scriptPubKey = CScript([CScriptOp(version), witness_hash])
+ # First try to spend to a future version segwit script_pubkey.
+ script_pubkey = CScript([CScriptOp(version), witness_hash])
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
- tx.vout = [CTxOut(self.utxo[0].nValue-1000, scriptPubKey)]
+ tx.vout = [CTxOut(self.utxo[0].nValue - 1000, script_pubkey)]
tx.rehash()
test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=False)
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=True)
self.utxo.pop(0)
temp_utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
- self.nodes[0].generate(1) # Mine all the transactions
+ self.nodes[0].generate(1) # Mine all the transactions
sync_blocks(self.nodes)
assert(len(self.nodes[0].getrawmempool()) == 0)
# Finally, verify that version 0 -> version 1 transactions
# are non-standard
- scriptPubKey = CScript([CScriptOp(OP_1), witness_hash])
+ script_pubkey = CScript([CScriptOp(OP_1), witness_hash])
tx2 = CTransaction()
tx2.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
- tx2.vout = [CTxOut(tx.vout[0].nValue-1000, scriptPubKey)]
+ tx2.vout = [CTxOut(tx.vout[0].nValue - 1000, script_pubkey)]
tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
# Gets accepted to test_node, because standardness of outputs isn't
# checked with fRequireStandard
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, with_witness=True, accepted=True)
test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=False)
- temp_utxo.pop() # last entry in temp_utxo was the output we just spent
+ temp_utxo.pop() # last entry in temp_utxo was the output we just spent
temp_utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
# Spend everything in temp_utxo back to an OP_TRUE output.
@@ -1235,15 +1482,15 @@ class SegWitTest(BitcoinTestFramework):
# Add utxo to our list
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
-
+ @subtest
def test_premature_coinbase_witness_spend(self):
- self.log.info("Testing premature coinbase witness spend")
+
block = self.build_next_block()
# Change the output of the block to be a witness output.
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
- block.vtx[0].vout[0].scriptPubKey = scriptPubKey
+ script_pubkey = CScript([OP_0, witness_hash])
+ block.vtx[0].vout[0].scriptPubKey = script_pubkey
# This next line will rehash the coinbase and update the merkle
# root, and solve.
self.update_witness_block_with_transactions(block, [])
@@ -1253,7 +1500,7 @@ class SegWitTest(BitcoinTestFramework):
spend_tx.vin = [CTxIn(COutPoint(block.vtx[0].sha256, 0), b"")]
spend_tx.vout = [CTxOut(block.vtx[0].vout[0].nValue, witness_program)]
spend_tx.wit.vtxinwit.append(CTxInWitness())
- spend_tx.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
+ spend_tx.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
spend_tx.rehash()
# Now test a premature spend.
@@ -1270,22 +1517,127 @@ class SegWitTest(BitcoinTestFramework):
test_witness_block(self.nodes[0].rpc, self.test_node, block2, accepted=True)
sync_blocks(self.nodes)
+ @subtest
+ def test_uncompressed_pubkey(self):
+ """Test uncompressed pubkey validity in segwit transactions.
+
+ Uncompressed pubkeys are no longer supported in default relay policy,
+ but (for now) are still valid in blocks."""
+
+ # Segwit transactions using uncompressed pubkeys are not accepted
+ # under default policy, but should still pass consensus.
+ key = CECKey()
+ key.set_secretbytes(b"9")
+ key.set_compressed(False)
+ pubkey = CPubKey(key.get_pubkey())
+ assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
+
+ utxo = self.utxo.pop(0)
+
+ # Test 1: P2WPKH
+ # First create a P2WPKH output that uses an uncompressed pubkey
+ pubkeyhash = hash160(pubkey)
+ script_pkh = CScript([OP_0, pubkeyhash])
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
+ tx.vout.append(CTxOut(utxo.nValue - 1000, script_pkh))
+ tx.rehash()
+
+ # Confirm it in a block.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+
+ # Now try to spend it. Send it to a P2WSH output, which we'll
+ # use in the next test.
+ witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
+ witness_hash = sha256(witness_program)
+ script_wsh = CScript([OP_0, witness_hash])
+
+ tx2 = CTransaction()
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_wsh))
+ script = get_p2pkh_script(pubkeyhash)
+ sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [signature, pubkey]
+ tx2.rehash()
+ # Should fail policy test.
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ # But passes consensus.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx2])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+
+ # Test 2: P2WSH
+ # Try to spend the P2WSH output created in last test.
+ # Send it to a P2SH(P2WSH) output, which we'll use in the next test.
+ p2sh_witness_hash = hash160(script_wsh)
+ script_p2sh = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
+ script_sig = CScript([script_wsh])
+
+ tx3 = CTransaction()
+ tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, script_p2sh))
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ sign_p2pk_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
+
+ # Should fail policy test.
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ # But passes consensus.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx3])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+
+ # Test 3: P2SH(P2WSH)
+ # Try to spend the P2SH output created in the last test.
+ # Send it to a P2PKH output, which we'll use in the next test.
+ script_pubkey = get_p2pkh_script(pubkeyhash)
+ tx4 = CTransaction()
+ tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), script_sig))
+ tx4.vout.append(CTxOut(tx3.vout[0].nValue - 1000, script_pubkey))
+ tx4.wit.vtxinwit.append(CTxInWitness())
+ sign_p2pk_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
+
+ # Should fail policy test.
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx4])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+
+ # Test 4: Uncompressed pubkeys should still be valid in non-segwit
+ # transactions.
+ tx5 = CTransaction()
+ tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
+ tx5.vout.append(CTxOut(tx4.vout[0].nValue - 1000, CScript([OP_TRUE])))
+ (sig_hash, err) = SignatureHash(script_pubkey, tx5, 0, SIGHASH_ALL)
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx5.vin[0].scriptSig = CScript([signature, pubkey])
+ tx5.rehash()
+ # Should pass policy and consensus.
+ test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx5, True, True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx5])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
+
+ @subtest
def test_signature_version_1(self):
- self.log.info("Testing segwit signature hash version 1")
+
key = CECKey()
key.set_secretbytes(b"9")
pubkey = CPubKey(key.get_pubkey())
witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
# First create a witness output for use in the tests.
- assert(len(self.utxo))
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=True)
@@ -1298,27 +1650,27 @@ class SegWitTest(BitcoinTestFramework):
# Test each hashtype
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
- for sigflag in [ 0, SIGHASH_ANYONECANPAY ]:
+ for sigflag in [0, SIGHASH_ANYONECANPAY]:
for hashtype in [SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE]:
hashtype |= sigflag
block = self.build_next_block()
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(prev_utxo.sha256, prev_utxo.n), b""))
- tx.vout.append(CTxOut(prev_utxo.nValue - 1000, scriptPubKey))
+ tx.vout.append(CTxOut(prev_utxo.nValue - 1000, script_pubkey))
tx.wit.vtxinwit.append(CTxInWitness())
# Too-large input value
- sign_P2PK_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue+1, key)
+ sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue + 1, key)
self.update_witness_block_with_transactions(block, [tx])
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
# Too-small input value
- sign_P2PK_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue-1, key)
- block.vtx.pop() # remove last tx
+ sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue - 1, key)
+ block.vtx.pop() # remove last tx
self.update_witness_block_with_transactions(block, [tx])
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
# Now try correct value
- sign_P2PK_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue, key)
block.vtx.pop()
self.update_witness_block_with_transactions(block, [tx])
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
@@ -1328,19 +1680,19 @@ class SegWitTest(BitcoinTestFramework):
# Test combinations of signature hashes.
# Split the utxo into a lot of outputs.
# Randomly choose up to 10 to spend, sign with different hashtypes, and
- # output to a random number of outputs. Repeat NUM_TESTS times.
+ # output to a random number of outputs. Repeat num_tests times.
# Ensure that we've tested a situation where we use SIGHASH_SINGLE with
# an input index > number of outputs.
- NUM_TESTS = 500
+ num_tests = 500
temp_utxos = []
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(prev_utxo.sha256, prev_utxo.n), b""))
- split_value = prev_utxo.nValue // NUM_TESTS
- for i in range(NUM_TESTS):
- tx.vout.append(CTxOut(split_value, scriptPubKey))
+ split_value = prev_utxo.nValue // num_tests
+ for i in range(num_tests):
+ tx.vout.append(CTxOut(split_value, script_pubkey))
tx.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx, 0, SIGHASH_ALL, prev_utxo.nValue, key)
- for i in range(NUM_TESTS):
+ sign_p2pk_witness_input(witness_program, tx, 0, SIGHASH_ALL, prev_utxo.nValue, key)
+ for i in range(num_tests):
temp_utxos.append(UTXO(tx.sha256, i, split_value))
block = self.build_next_block()
@@ -1349,7 +1701,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
used_sighash_single_out_of_bounds = False
- for i in range(NUM_TESTS):
+ for i in range(num_tests):
# Ping regularly to keep the connection alive
if (not i % 100):
self.test_node.sync_with_ping()
@@ -1367,14 +1719,14 @@ class SegWitTest(BitcoinTestFramework):
total_value += temp_utxos[i].nValue
split_value = total_value // num_outputs
for i in range(num_outputs):
- tx.vout.append(CTxOut(split_value, scriptPubKey))
+ tx.vout.append(CTxOut(split_value, script_pubkey))
for i in range(num_inputs):
# Now try to sign each input, using a random hashtype.
anyonecanpay = 0
if random.randint(0, 1):
anyonecanpay = SIGHASH_ANYONECANPAY
hashtype = random.randint(1, 3) | anyonecanpay
- sign_P2PK_witness_input(witness_program, tx, i, hashtype, temp_utxos[i].nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, i, hashtype, temp_utxos[i].nValue, key)
if (hashtype == SIGHASH_SINGLE and i >= num_outputs):
used_sighash_single_out_of_bounds = True
tx.rehash()
@@ -1399,19 +1751,19 @@ class SegWitTest(BitcoinTestFramework):
# Now test witness version 0 P2PKH transactions
pubkeyhash = hash160(pubkey)
- scriptPKH = CScript([OP_0, pubkeyhash])
+ script_pkh = CScript([OP_0, pubkeyhash])
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(temp_utxos[0].sha256, temp_utxos[0].n), b""))
- tx.vout.append(CTxOut(temp_utxos[0].nValue, scriptPKH))
+ tx.vout.append(CTxOut(temp_utxos[0].nValue, script_pkh))
tx.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx, 0, SIGHASH_ALL, temp_utxos[0].nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, 0, SIGHASH_ALL, temp_utxos[0].nValue, key)
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
- script = GetP2PKHScript(pubkeyhash)
+ script = get_p2pkh_script(pubkeyhash)
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
# Check that we can't have a scriptSig
tx2.vin[0].scriptSig = CScript([signature, pubkey])
@@ -1444,7 +1796,7 @@ class SegWitTest(BitcoinTestFramework):
# the signatures as we go.
tx.vin.append(CTxIn(COutPoint(i.sha256, i.n), b""))
tx.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx, index, SIGHASH_ALL|SIGHASH_ANYONECANPAY, i.nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, index, SIGHASH_ALL | SIGHASH_ANYONECANPAY, i.nValue, key)
index += 1
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
@@ -1453,379 +1805,22 @@ class SegWitTest(BitcoinTestFramework):
for i in range(len(tx.vout)):
self.utxo.append(UTXO(tx.sha256, i, tx.vout[i].nValue))
-
- # Test P2SH wrapped witness programs.
- def test_p2sh_witness(self, segwit_activated):
- self.log.info("Testing P2SH witness transactions")
-
- assert(len(self.utxo))
-
- # Prepare the p2sh-wrapped witness output
- witness_program = CScript([OP_DROP, OP_TRUE])
- witness_hash = sha256(witness_program)
- p2wsh_pubkey = CScript([OP_0, witness_hash])
- p2sh_witness_hash = hash160(p2wsh_pubkey)
- scriptPubKey = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
- scriptSig = CScript([p2wsh_pubkey]) # a push of the redeem script
-
- # Fund the P2SH output
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
- tx.rehash()
-
- # Verify mempool acceptance and block validity
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True, with_witness=segwit_activated)
- sync_blocks(self.nodes)
-
- # Now test attempts to spend the output.
- spend_tx = CTransaction()
- spend_tx.vin.append(CTxIn(COutPoint(tx.sha256, 0), scriptSig))
- spend_tx.vout.append(CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE])))
- spend_tx.rehash()
-
- # This transaction should not be accepted into the mempool pre- or
- # post-segwit. Mempool acceptance will use SCRIPT_VERIFY_WITNESS which
- # will require a witness to spend a witness program regardless of
- # segwit activation. Note that older bitcoind's that are not
- # segwit-aware would also reject this for failing CLEANSTACK.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
-
- # Try to put the witness script in the scriptSig, should also fail.
- spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a'])
- spend_tx.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
-
- # Now put the witness script in the witness, should succeed after
- # segwit activates.
- spend_tx.vin[0].scriptSig = scriptSig
- spend_tx.rehash()
- spend_tx.wit.vtxinwit.append(CTxInWitness())
- spend_tx.wit.vtxinwit[0].scriptWitness.stack = [ b'a', witness_program ]
-
- # Verify mempool acceptance
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=True, accepted=segwit_activated)
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [spend_tx])
-
- # If we're after activation, then sending this with witnesses should be valid.
- # This no longer works before activation, because SCRIPT_VERIFY_WITNESS
- # is always set.
- # TODO: rewrite this test to make clear that it only works after activation.
- if segwit_activated:
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
- else:
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True, with_witness=False)
-
- # Update self.utxo
- self.utxo.pop(0)
- self.utxo.append(UTXO(spend_tx.sha256, 0, spend_tx.vout[0].nValue))
-
- # Test the behavior of starting up a segwit-aware node after the softfork
- # has activated. As segwit requires different block data than pre-segwit
- # nodes would have stored, this requires special handling.
- # To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to
- # the test.
- def test_upgrade_after_activation(self, node_id):
- self.log.info("Testing software upgrade after softfork activation")
-
- assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind
-
- # Make sure the nodes are all up
- sync_blocks(self.nodes)
-
- # Restart with the new binary
- self.stop_node(node_id)
- self.start_node(node_id, extra_args=["-vbparams=segwit:0:999999999999"])
- connect_nodes(self.nodes[0], node_id)
-
- sync_blocks(self.nodes)
-
- # Make sure that this peer thinks segwit has activated.
- assert(get_bip9_status(self.nodes[node_id], 'segwit')['status'] == "active")
-
- # Make sure this peer's blocks match those of node0.
- height = self.nodes[node_id].getblockcount()
- while height >= 0:
- block_hash = self.nodes[node_id].getblockhash(height)
- assert_equal(block_hash, self.nodes[0].getblockhash(height))
- assert_equal(self.nodes[0].getblock(block_hash), self.nodes[node_id].getblock(block_hash))
- height -= 1
-
-
- def test_witness_sigops(self):
- '''Ensure sigop counting is correct inside witnesses.'''
- self.log.info("Testing sigops limit")
-
- assert(len(self.utxo))
-
- # Keep this under MAX_OPS_PER_SCRIPT (201)
- witness_program = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKMULTISIG]*5 + [OP_CHECKSIG]*193 + [OP_ENDIF])
- witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
-
- sigops_per_script = 20*5 + 193*1
- # We'll produce 2 extra outputs, one with a program that would take us
- # over max sig ops, and one with a program that would exactly reach max
- # sig ops
- outputs = (MAX_SIGOP_COST // sigops_per_script) + 2
- extra_sigops_available = MAX_SIGOP_COST % sigops_per_script
-
- # We chose the number of checkmultisigs/checksigs to make this work:
- assert(extra_sigops_available < 100) # steer clear of MAX_OPS_PER_SCRIPT
-
- # This script, when spent with the first
- # N(=MAX_SIGOP_COST//sigops_per_script) outputs of our transaction,
- # would push us just over the block sigop limit.
- witness_program_toomany = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG]*(extra_sigops_available + 1) + [OP_ENDIF])
- witness_hash_toomany = sha256(witness_program_toomany)
- scriptPubKey_toomany = CScript([OP_0, witness_hash_toomany])
-
- # If we spend this script instead, we would exactly reach our sigop
- # limit (for witness sigops).
- witness_program_justright = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG]*(extra_sigops_available) + [OP_ENDIF])
- witness_hash_justright = sha256(witness_program_justright)
- scriptPubKey_justright = CScript([OP_0, witness_hash_justright])
-
- # First split our available utxo into a bunch of outputs
- split_value = self.utxo[0].nValue // outputs
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- for i in range(outputs):
- tx.vout.append(CTxOut(split_value, scriptPubKey))
- tx.vout[-2].scriptPubKey = scriptPubKey_toomany
- tx.vout[-1].scriptPubKey = scriptPubKey_justright
- tx.rehash()
-
- block_1 = self.build_next_block()
- self.update_witness_block_with_transactions(block_1, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_1, accepted=True)
-
- tx2 = CTransaction()
- # If we try to spend the first n-1 outputs from tx, that should be
- # too many sigops.
- total_value = 0
- for i in range(outputs-1):
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b""))
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[-1].scriptWitness.stack = [ witness_program ]
- total_value += tx.vout[i].nValue
- tx2.wit.vtxinwit[-1].scriptWitness.stack = [ witness_program_toomany ]
- tx2.vout.append(CTxOut(total_value, CScript([OP_TRUE])))
- tx2.rehash()
-
- block_2 = self.build_next_block()
- self.update_witness_block_with_transactions(block_2, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=False)
-
- # Try dropping the last input in tx2, and add an output that has
- # too many sigops (contributing to legacy sigop count).
- checksig_count = (extra_sigops_available // 4) + 1
- scriptPubKey_checksigs = CScript([OP_CHECKSIG]*checksig_count)
- tx2.vout.append(CTxOut(0, scriptPubKey_checksigs))
- tx2.vin.pop()
- tx2.wit.vtxinwit.pop()
- tx2.vout[0].nValue -= tx.vout[-2].nValue
- tx2.rehash()
- block_3 = self.build_next_block()
- self.update_witness_block_with_transactions(block_3, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=False)
-
- # If we drop the last checksig in this output, the tx should succeed.
- block_4 = self.build_next_block()
- tx2.vout[-1].scriptPubKey = CScript([OP_CHECKSIG]*(checksig_count-1))
- tx2.rehash()
- self.update_witness_block_with_transactions(block_4, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_4, accepted=True)
-
- # Reset the tip back down for the next test
- sync_blocks(self.nodes)
- for x in self.nodes:
- x.invalidateblock(block_4.hash)
-
- # Try replacing the last input of tx2 to be spending the last
- # output of tx
- block_5 = self.build_next_block()
- tx2.vout.pop()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, outputs-1), b""))
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[-1].scriptWitness.stack = [ witness_program_justright ]
- tx2.rehash()
- self.update_witness_block_with_transactions(block_5, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_5, accepted=True)
-
- # TODO: test p2sh sigop counting
-
- def test_getblocktemplate_before_lockin(self):
- self.log.info("Testing getblocktemplate setting of segwit versionbit (before lockin)")
- # Node0 is segwit aware, node2 is not.
- for node in [self.nodes[0], self.nodes[2]]:
- gbt_results = node.getblocktemplate()
- block_version = gbt_results['version']
- # If we're not indicating segwit support, we will still be
- # signalling for segwit activation.
- assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0])
- # If we don't specify the segwit rule, then we won't get a default
- # commitment.
- assert('default_witness_commitment' not in gbt_results)
-
- # Workaround:
- # Can either change the tip, or change the mempool and wait 5 seconds
- # to trigger a recomputation of getblocktemplate.
- txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
- # Using mocktime lets us avoid sleep()
- sync_mempools(self.nodes)
- self.nodes[0].setmocktime(int(time.time())+10)
- self.nodes[2].setmocktime(int(time.time())+10)
-
- for node in [self.nodes[0], self.nodes[2]]:
- gbt_results = node.getblocktemplate({"rules" : ["segwit"]})
- block_version = gbt_results['version']
- if node == self.nodes[2]:
- # If this is a non-segwit node, we should still not get a witness
- # commitment, nor a version bit signalling segwit.
- assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
- assert('default_witness_commitment' not in gbt_results)
- else:
- # For segwit-aware nodes, check the version bit and the witness
- # commitment are correct.
- assert(block_version & (1 << VB_WITNESS_BIT) != 0)
- assert('default_witness_commitment' in gbt_results)
- witness_commitment = gbt_results['default_witness_commitment']
-
- # Check that default_witness_commitment is present.
- witness_root = CBlock.get_merkle_root([ser_uint256(0),
- ser_uint256(txid)])
- script = get_witness_script(witness_root, 0)
- assert_equal(witness_commitment, bytes_to_hex_str(script))
-
- # undo mocktime
- self.nodes[0].setmocktime(0)
- self.nodes[2].setmocktime(0)
-
- # Uncompressed pubkeys are no longer supported in default relay policy,
- # but (for now) are still valid in blocks.
- def test_uncompressed_pubkey(self):
- self.log.info("Testing uncompressed pubkeys")
- # Segwit transactions using uncompressed pubkeys are not accepted
- # under default policy, but should still pass consensus.
- key = CECKey()
- key.set_secretbytes(b"9")
- key.set_compressed(False)
- pubkey = CPubKey(key.get_pubkey())
- assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
-
- assert(len(self.utxo) > 0)
- utxo = self.utxo.pop(0)
-
- # Test 1: P2WPKH
- # First create a P2WPKH output that uses an uncompressed pubkey
- pubkeyhash = hash160(pubkey)
- scriptPKH = CScript([OP_0, pubkeyhash])
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
- tx.vout.append(CTxOut(utxo.nValue-1000, scriptPKH))
- tx.rehash()
-
- # Confirm it in a block.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Now try to spend it. Send it to a P2WSH output, which we'll
- # use in the next test.
- witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
- witness_hash = sha256(witness_program)
- scriptWSH = CScript([OP_0, witness_hash])
-
- tx2 = CTransaction()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptWSH))
- script = GetP2PKHScript(pubkeyhash)
- sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ signature, pubkey ]
- tx2.rehash()
-
- # Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
- # But passes consensus.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Test 2: P2WSH
- # Try to spend the P2WSH output created in last test.
- # Send it to a P2SH(P2WSH) output, which we'll use in the next test.
- p2sh_witness_hash = hash160(scriptWSH)
- scriptP2SH = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
- scriptSig = CScript([scriptWSH])
-
- tx3 = CTransaction()
- tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptP2SH))
- tx3.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
-
- # Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
- # But passes consensus.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx3])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Test 3: P2SH(P2WSH)
- # Try to spend the P2SH output created in the last test.
- # Send it to a P2PKH output, which we'll use in the next test.
- scriptPubKey = GetP2PKHScript(pubkeyhash)
- tx4 = CTransaction()
- tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), scriptSig))
- tx4.vout.append(CTxOut(tx3.vout[0].nValue-1000, scriptPubKey))
- tx4.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
-
- # Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx4])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Test 4: Uncompressed pubkeys should still be valid in non-segwit
- # transactions.
- tx5 = CTransaction()
- tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
- tx5.vout.append(CTxOut(tx4.vout[0].nValue-1000, CScript([OP_TRUE])))
- (sig_hash, err) = SignatureHash(scriptPubKey, tx5, 0, SIGHASH_ALL)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
- tx5.vin[0].scriptSig = CScript([signature, pubkey])
- tx5.rehash()
- # Should pass policy and consensus.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx5, True, True)
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx5])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
- self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
-
+ @subtest
def test_non_standard_witness_blinding(self):
- self.log.info("Testing behavior of unnecessary witnesses in transactions does not blind the node for the transaction")
- assert (len(self.utxo) > 0)
+ """Test behavior of unnecessary witnesses in transactions does not blind the node for the transaction"""
# Create a p2sh output -- this is so we can pass the standardness
# rules (an anyone-can-spend OP_TRUE would be rejected, if not wrapped
# in P2SH).
p2sh_program = CScript([OP_TRUE])
p2sh_pubkey = hash160(p2sh_program)
- scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+ script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
# Now check that unnecessary witnesses can't be used to blind a node
# to a transaction, eg by violating standardness checks.
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, False, True)
self.nodes[0].generate(1)
@@ -1838,7 +1833,7 @@ class SegWitTest(BitcoinTestFramework):
# to the rejection cache.
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), CScript([p2sh_program])))
- tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, scriptPubKey))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * 400]
tx2.rehash()
@@ -1864,8 +1859,9 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ @subtest
def test_non_standard_witness(self):
- self.log.info("Testing detection of non-standard P2WSH witness")
+ """Test detection of non-standard P2WSH witness"""
pad = chr(1).encode('latin-1')
# Create scripts for tests
@@ -1877,7 +1873,6 @@ class SegWitTest(BitcoinTestFramework):
p2wsh_scripts = []
- assert(len(self.utxo))
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
@@ -1901,13 +1896,13 @@ class SegWitTest(BitcoinTestFramework):
p2sh_txs = []
for i in range(len(scripts)):
p2wsh_tx = CTransaction()
- p2wsh_tx.vin.append(CTxIn(COutPoint(txid,i*2)))
+ p2wsh_tx.vin.append(CTxIn(COutPoint(txid, i * 2)))
p2wsh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
p2wsh_tx.rehash()
p2wsh_txs.append(p2wsh_tx)
p2sh_tx = CTransaction()
- p2sh_tx.vin.append(CTxIn(COutPoint(txid,i*2+1), CScript([p2wsh_scripts[i]])))
+ p2sh_tx.vin.append(CTxIn(COutPoint(txid, i * 2 + 1), CScript([p2wsh_scripts[i]])))
p2sh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
p2sh_tx.wit.vtxinwit.append(CTxInWitness())
p2sh_tx.rehash()
@@ -1964,77 +1959,128 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
- def run_test(self):
- # Setup the p2p connections
- # self.test_node sets NODE_WITNESS|NODE_NETWORK
- self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
- # self.old_node sets only NODE_NETWORK
- self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
- # self.std_node is for testing node1 (fRequireStandard=true)
- self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
+ @subtest
+ def test_upgrade_after_activation(self):
+ """Test the behavior of starting up a segwit-aware node after the softfork has activated."""
- # Keep a place to store utxo's that can be used in later tests
- self.utxo = []
+ # Restart with the new binary
+ self.stop_node(2)
+ self.start_node(2, extra_args=["-vbparams=segwit:0:999999999999"])
+ connect_nodes(self.nodes[0], 2)
- # Test logic begins here
- self.test_node.wait_for_verack()
+ sync_blocks(self.nodes)
- self.log.info("Starting tests before segwit lock in:")
+ # Make sure that this peer thinks segwit has activated.
+ assert(get_bip9_status(self.nodes[2], 'segwit')['status'] == "active")
- self.test_witness_services() # Verifies NODE_WITNESS
- self.test_non_witness_transaction() # non-witness tx's are accepted
- self.test_unnecessary_witness_before_segwit_activation()
- self.test_v0_outputs_arent_spendable()
- self.test_block_relay(segwit_activated=False)
+ # Make sure this peer's blocks match those of node0.
+ height = self.nodes[2].getblockcount()
+ while height >= 0:
+ block_hash = self.nodes[2].getblockhash(height)
+ assert_equal(block_hash, self.nodes[0].getblockhash(height))
+ assert_equal(self.nodes[0].getblock(block_hash), self.nodes[2].getblock(block_hash))
+ height -= 1
- # Advance to segwit being 'started'
- self.advance_to_segwit_started()
- sync_blocks(self.nodes)
- self.test_getblocktemplate_before_lockin()
+ @subtest
+ def test_witness_sigops(self):
+ """Test sigop counting is correct inside witnesses."""
- sync_blocks(self.nodes)
+ # Keep this under MAX_OPS_PER_SCRIPT (201)
+ witness_program = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKMULTISIG] * 5 + [OP_CHECKSIG] * 193 + [OP_ENDIF])
+ witness_hash = sha256(witness_program)
+ script_pubkey = CScript([OP_0, witness_hash])
- # At lockin, nothing should change.
- self.log.info("Testing behavior post lockin, pre-activation")
- self.advance_to_segwit_lockin()
+ sigops_per_script = 20 * 5 + 193 * 1
+ # We'll produce 2 extra outputs, one with a program that would take us
+ # over max sig ops, and one with a program that would exactly reach max
+ # sig ops
+ outputs = (MAX_SIGOP_COST // sigops_per_script) + 2
+ extra_sigops_available = MAX_SIGOP_COST % sigops_per_script
- # Retest unnecessary witnesses
- self.test_unnecessary_witness_before_segwit_activation()
- self.test_witness_tx_relay_before_segwit_activation()
- self.test_block_relay(segwit_activated=False)
- self.test_standardness_v0(segwit_activated=False)
+ # We chose the number of checkmultisigs/checksigs to make this work:
+ assert(extra_sigops_available < 100) # steer clear of MAX_OPS_PER_SCRIPT
- sync_blocks(self.nodes)
+ # This script, when spent with the first
+ # N(=MAX_SIGOP_COST//sigops_per_script) outputs of our transaction,
+ # would push us just over the block sigop limit.
+ witness_program_toomany = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG] * (extra_sigops_available + 1) + [OP_ENDIF])
+ witness_hash_toomany = sha256(witness_program_toomany)
+ script_pubkey_toomany = CScript([OP_0, witness_hash_toomany])
- # Now activate segwit
- self.log.info("Testing behavior after segwit activation")
- self.advance_to_segwit_active()
+ # If we spend this script instead, we would exactly reach our sigop
+ # limit (for witness sigops).
+ witness_program_justright = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG] * (extra_sigops_available) + [OP_ENDIF])
+ witness_hash_justright = sha256(witness_program_justright)
+ script_pubkey_justright = CScript([OP_0, witness_hash_justright])
- sync_blocks(self.nodes)
+ # First split our available utxo into a bunch of outputs
+ split_value = self.utxo[0].nValue // outputs
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ for i in range(outputs):
+ tx.vout.append(CTxOut(split_value, script_pubkey))
+ tx.vout[-2].scriptPubKey = script_pubkey_toomany
+ tx.vout[-1].scriptPubKey = script_pubkey_justright
+ tx.rehash()
- # Test P2SH witness handling again
- self.test_p2sh_witness(segwit_activated=True)
- self.test_witness_commitments()
- self.test_block_malleability()
- self.test_witness_block_size()
- self.test_submit_block()
- self.test_extra_witness_data()
- self.test_max_witness_push_length()
- self.test_max_witness_program_length()
- self.test_witness_input_length()
- self.test_block_relay(segwit_activated=True)
- self.test_tx_relay_after_segwit_activation()
- self.test_standardness_v0(segwit_activated=True)
- self.test_segwit_versions()
- self.test_premature_coinbase_witness_spend()
- self.test_uncompressed_pubkey()
- self.test_signature_version_1()
- self.test_non_standard_witness_blinding()
- self.test_non_standard_witness()
+ block_1 = self.build_next_block()
+ self.update_witness_block_with_transactions(block_1, [tx])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block_1, accepted=True)
+
+ tx2 = CTransaction()
+ # If we try to spend the first n-1 outputs from tx, that should be
+ # too many sigops.
+ total_value = 0
+ for i in range(outputs - 1):
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b""))
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program]
+ total_value += tx.vout[i].nValue
+ tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_toomany]
+ tx2.vout.append(CTxOut(total_value, CScript([OP_TRUE])))
+ tx2.rehash()
+
+ block_2 = self.build_next_block()
+ self.update_witness_block_with_transactions(block_2, [tx2])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=False)
+
+ # Try dropping the last input in tx2, and add an output that has
+ # too many sigops (contributing to legacy sigop count).
+ checksig_count = (extra_sigops_available // 4) + 1
+ script_pubkey_checksigs = CScript([OP_CHECKSIG] * checksig_count)
+ tx2.vout.append(CTxOut(0, script_pubkey_checksigs))
+ tx2.vin.pop()
+ tx2.wit.vtxinwit.pop()
+ tx2.vout[0].nValue -= tx.vout[-2].nValue
+ tx2.rehash()
+ block_3 = self.build_next_block()
+ self.update_witness_block_with_transactions(block_3, [tx2])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=False)
+
+ # If we drop the last checksig in this output, the tx should succeed.
+ block_4 = self.build_next_block()
+ tx2.vout[-1].scriptPubKey = CScript([OP_CHECKSIG] * (checksig_count - 1))
+ tx2.rehash()
+ self.update_witness_block_with_transactions(block_4, [tx2])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block_4, accepted=True)
+
+ # Reset the tip back down for the next test
sync_blocks(self.nodes)
- self.test_upgrade_after_activation(node_id=2)
- self.test_witness_sigops()
+ for x in self.nodes:
+ x.invalidateblock(block_4.hash)
+
+ # Try replacing the last input of tx2 to be spending the last
+ # output of tx
+ block_5 = self.build_next_block()
+ tx2.vout.pop()
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, outputs - 1), b""))
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_justright]
+ tx2.rehash()
+ self.update_witness_block_with_transactions(block_5, [tx2])
+ test_witness_block(self.nodes[0].rpc, self.test_node, block_5, accepted=True)
+ # TODO: test p2sh sigop counting
if __name__ == '__main__':
SegWitTest().main()
diff --git a/test/functional/rpc_zmq.py b/test/functional/rpc_zmq.py
new file mode 100755
index 0000000000..eb789face2
--- /dev/null
+++ b/test/functional/rpc_zmq.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+# 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.
+"""Test for the ZMQ RPC methods."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class RPCZMQTest(BitcoinTestFramework):
+
+ address = "tcp://127.0.0.1:28332"
+
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def run_test(self):
+ self._test_getzmqnotifications()
+
+ def _test_getzmqnotifications(self):
+ self.restart_node(0, extra_args=[])
+ assert_equal(self.nodes[0].getzmqnotifications(), [])
+
+ self.restart_node(0, extra_args=["-zmqpubhashtx=%s" % self.address])
+ assert_equal(self.nodes[0].getzmqnotifications(), [
+ {"type": "pubhashtx", "address": self.address},
+ ])
+
+
+if __name__ == '__main__':
+ RPCZMQTest().main()
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 36101d9f57..c3a5468296 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -116,6 +116,7 @@ BASE_SCRIPTS = [
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
'wallet_importprunedfunds.py',
+ 'rpc_zmq.py',
'rpc_signmessage.py',
'feature_nulldummy.py',
'mempool_accept.py',
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 3cefd83459..fa5a2154a4 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -211,6 +211,10 @@ class MultiWalletTest(BitcoinTestFramework):
# Fail to load if wallet file is a symlink
assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
+ # Fail to load if a directory is specified that doesn't contain a wallet
+ os.mkdir(wallet_dir('empty_wallet_dir'))
+ assert_raises_rpc_error(-18, "Directory empty_wallet_dir does not contain a wallet.dat file", self.nodes[0].loadwallet, 'empty_wallet_dir')
+
self.log.info("Test dynamic wallet creation.")
# Fail to create a wallet if it already exists.