mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge pull request #5842 from kwvg/bps_jan_03
backport: merge bitcoin#19289, #19998, #17775, #19401, #20167, #20187, #19961, #21114, #21170 (auxiliary backports: part 12)
This commit is contained in:
commit
9c38b355ae
27
doc/tor.md
27
doc/tor.md
@ -8,6 +8,16 @@ may not. In particular, the Tor Browser Bundle defaults to listening on port 915
|
||||
See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort)
|
||||
for how to properly configure Tor.
|
||||
|
||||
## How to see information about your Tor configuration via Dash Core
|
||||
|
||||
There are several ways to see your local onion address in Dash Core:
|
||||
- in the debug log (grep for "tor:" or "AddLocal")
|
||||
- in the output of RPC `getnetworkinfo` in the "localaddresses" section
|
||||
- in the output of the CLI `-netinfo` peer connections dashboard
|
||||
|
||||
You may set the `-debug=tor` config logging option to have additional
|
||||
information in the debug log about your Tor configuration.
|
||||
|
||||
|
||||
## 1. Run Dash Core behind a Tor proxy
|
||||
|
||||
@ -160,14 +170,19 @@ The directory can be different of course, but virtual port numbers should be equ
|
||||
your dashd's P2P listen port (9999 by default), and target addresses and ports
|
||||
should be equal to binding address and port for inbound Tor connections (127.0.0.1:9996 by default).
|
||||
|
||||
-externalip=X You can tell Dash Core about its publicly reachable address using
|
||||
this option, and this can be a .onion address. Given the above
|
||||
configuration, you can find your .onion address in
|
||||
-externalip=X You can tell Dash Core about its publicly reachable addresses using
|
||||
this option, and this can be an onion address. Given the above
|
||||
configuration, you can find your onion address in
|
||||
/var/lib/tor/dashcore-service/hostname. For connections
|
||||
coming from unroutable addresses (such as 127.0.0.1, where the
|
||||
Tor proxy typically runs), .onion addresses are given
|
||||
Tor proxy typically runs), onion addresses are given
|
||||
preference for your node to advertise itself with.
|
||||
|
||||
You can set multiple local addresses with -externalip. The
|
||||
one that will be rumoured to a particular peer is the most
|
||||
compatible one and also using heuristics, e.g. the address
|
||||
with the most incoming connections, etc.
|
||||
|
||||
-listen You'll need to enable listening for incoming connections, as this
|
||||
is off by default behind a proxy.
|
||||
|
||||
@ -180,7 +195,7 @@ should be equal to binding address and port for inbound Tor connections (127.0.0
|
||||
|
||||
In a typical situation, where you're only reachable via Tor, this should suffice:
|
||||
|
||||
./dashd -proxy=127.0.0.1:9050 -externalip=ssapp53tmftyjmjb.onion -listen
|
||||
./dashd -proxy=127.0.0.1:9050 -externalip=7zvj7a2imdgkdbg4f2dryd5rgtrn7upivr5eeij4cicjh65pooxeshid.onion -listen
|
||||
|
||||
(obviously, replace the .onion address with your own). It should be noted that you still
|
||||
listen on all devices and another node could establish a clearnet connection, when knowing
|
||||
@ -198,7 +213,7 @@ and open port 9999 on your firewall (or use port mapping, i.e., `-upnp` or `-nat
|
||||
If you only want to use Tor to reach .onion addresses, but not use it as a proxy
|
||||
for normal IPv4/IPv6 communication, use:
|
||||
|
||||
./dashd -onion=127.0.0.1:9050 -externalip=ssapp53tmftyjmjb.onion -discover
|
||||
./dashd -onion=127.0.0.1:9050 -externalip=7zvj7a2imdgkdbg4f2dryd5rgtrn7upivr5eeij4cicjh65pooxeshid.onion -discover
|
||||
|
||||
|
||||
## 3.1. List of known Dash Core Tor relays
|
||||
|
@ -15,24 +15,49 @@
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
static void BlockToJsonVerbose(benchmark::Bench& bench) {
|
||||
namespace {
|
||||
|
||||
struct TestBlockAndIndex {
|
||||
TestingSetup test_setup{};
|
||||
CBlock block{};
|
||||
uint256 blockHash{};
|
||||
CBlockIndex blockindex{};
|
||||
|
||||
CDataStream stream(benchmark::data::block813851, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
TestBlockAndIndex()
|
||||
{
|
||||
CDataStream stream(benchmark::data::block813851, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
CBlock block;
|
||||
stream >> block;
|
||||
stream >> block;
|
||||
|
||||
CBlockIndex blockindex;
|
||||
const uint256 blockHash = block.GetHash();
|
||||
blockindex.phashBlock = &blockHash;
|
||||
blockindex.nBits = 403014710;
|
||||
blockHash = block.GetHash();
|
||||
blockindex.phashBlock = &blockHash;
|
||||
blockindex.nBits = 403014710;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void BlockToJsonVerbose(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
bench.run([&] {
|
||||
(void)blockToJSON(block, &blockindex, &blockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, /*verbose*/ true);
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, /*verbose*/ true);
|
||||
ankerl::nanobench::doNotOptimizeAway(univalue);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BlockToJsonVerbose);
|
||||
|
||||
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, /*verbose*/ true);
|
||||
bench.run([&] {
|
||||
auto str = univalue.write();
|
||||
ankerl::nanobench::doNotOptimizeAway(str);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BlockToJsonVerboseWrite);
|
||||
|
@ -24,7 +24,7 @@ struct CSpentIndexTxInfo;
|
||||
// core_read.cpp
|
||||
CScript ParseScript(const std::string& s);
|
||||
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
|
||||
[[nodiscard]] bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx);
|
||||
[[nodiscard]] bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx);
|
||||
[[nodiscard]] bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
|
||||
bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
|
||||
/**
|
||||
|
@ -100,25 +100,31 @@ CScript ParseScript(const std::string& s)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx)
|
||||
static bool DecodeTx(CMutableTransaction& tx, const std::vector<unsigned char>& tx_data)
|
||||
{
|
||||
if (!IsHex(strHexTx))
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> txData(ParseHex(strHexTx));
|
||||
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
|
||||
CDataStream ssData(tx_data, SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ssData >> tx;
|
||||
if (!ssData.empty())
|
||||
if (!ssData.empty()) {
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx)
|
||||
{
|
||||
if (!IsHex(hex_tx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> txData(ParseHex(hex_tx));
|
||||
return DecodeTx(tx, txData);
|
||||
}
|
||||
|
||||
bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
|
||||
{
|
||||
if (!IsHex(hex_header)) return false;
|
||||
|
34
src/net.cpp
34
src/net.cpp
@ -385,6 +385,11 @@ CNode* CConnman::FindNode(const CService& addr, bool fExcludeDisconnecting)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
|
||||
{
|
||||
return FindNode(addr.ToStringIPPort());
|
||||
}
|
||||
|
||||
bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
@ -2397,11 +2402,30 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||
if (nTries > 100)
|
||||
break;
|
||||
|
||||
CAddrInfo addr = addrman.SelectTriedCollision();
|
||||
CAddrInfo addr;
|
||||
|
||||
// SelectTriedCollision returns an invalid address if it is empty.
|
||||
if (!fFeeler || !addr.IsValid()) {
|
||||
addr = addrman.Select(fFeeler);
|
||||
if (fFeeler) {
|
||||
// First, try to get a tried table collision address. This returns
|
||||
// an empty (invalid) address if there are no collisions to try.
|
||||
addr = addrman.SelectTriedCollision();
|
||||
|
||||
if (!addr.IsValid()) {
|
||||
// No tried table collisions. Select a new table address
|
||||
// for our feeler.
|
||||
addr = addrman.Select(true);
|
||||
} else if (AlreadyConnectedToAddress(addr)) {
|
||||
// If test-before-evict logic would have us connect to a
|
||||
// peer that we're already connected to, just mark that
|
||||
// address as Good(). We won't be able to initiate the
|
||||
// connection anyway, so this avoids inadvertently evicting
|
||||
// a currently-connected peer.
|
||||
addrman.Good(addr);
|
||||
// Select a new table address for our feeler instead.
|
||||
addr = addrman.Select(true);
|
||||
}
|
||||
} else {
|
||||
// Not a feeler
|
||||
addr = addrman.Select();
|
||||
}
|
||||
|
||||
auto dmn = mnList.GetMNByService(addr);
|
||||
@ -2768,7 +2792,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||
|
||||
if (!pszDest) {
|
||||
// banned, discouraged or exact match?
|
||||
if ((m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect))) || FindNode(addrConnect.ToStringIPPort()))
|
||||
if ((m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect))) || AlreadyConnectedToAddress(addrConnect))
|
||||
return;
|
||||
// local and not a connection to itself?
|
||||
bool fAllowLocal = Params().AllowMultiplePorts() && addrConnect.GetPort() != GetListenPort();
|
||||
|
@ -625,6 +625,12 @@ private:
|
||||
CNode* FindNode(const std::string& addrName, bool fExcludeDisconnecting = true);
|
||||
CNode* FindNode(const CService& addr, bool fExcludeDisconnecting = true);
|
||||
|
||||
/**
|
||||
* Determine whether we're already connected to a given address, in order to
|
||||
* avoid initiating duplicate connections.
|
||||
*/
|
||||
bool AlreadyConnectedToAddress(const CAddress& addr);
|
||||
|
||||
bool AttemptToEvictConnection();
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = nullptr, bool fCountFailure = false, ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY);
|
||||
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
|
||||
|
@ -3017,14 +3017,8 @@ void PeerManagerImpl::ProcessMessage(
|
||||
// empty and no one will know who we are, so these mechanisms are
|
||||
// important to help us connect to the network.
|
||||
//
|
||||
// We also update the addrman to record connection success for
|
||||
// these peers (which include OUTBOUND_FULL_RELAY and FEELER
|
||||
// connections) so that addrman will have an up-to-date notion of
|
||||
// which peers are online and available.
|
||||
//
|
||||
// We skip these operations for BLOCK_RELAY peers to avoid
|
||||
// potentially leaking information about our BLOCK_RELAY
|
||||
// connections via the addrman or address relay.
|
||||
// We skip this for BLOCK_RELAY peers to avoid potentially leaking
|
||||
// information about our BLOCK_RELAY connections via address relay.
|
||||
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
|
||||
{
|
||||
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
|
||||
@ -3043,11 +3037,24 @@ void PeerManagerImpl::ProcessMessage(
|
||||
// Get recent addresses
|
||||
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
|
||||
pfrom.fGetAddr = true;
|
||||
}
|
||||
|
||||
// Moves address from New to Tried table in Addrman, resolves
|
||||
// tried-table collisions, etc.
|
||||
if (!pfrom.IsInboundConn()) {
|
||||
// For non-inbound connections, we update the addrman to record
|
||||
// connection success so that addrman will have an up-to-date
|
||||
// notion of which peers are online and available.
|
||||
//
|
||||
// While we strive to not leak information about block-relay-only
|
||||
// connections via the addrman, not moving an address to the tried
|
||||
// table is also potentially detrimental because new-table entries
|
||||
// are subject to eviction in the event of addrman collisions. We
|
||||
// mitigate the information-leak by never calling
|
||||
// CAddrMan::Connected() on block-relay-only peers; see
|
||||
// FinalizeNode().
|
||||
//
|
||||
// This moves an address from New to Tried table in Addrman,
|
||||
// resolves tried-table collisions, etc.
|
||||
m_addrman.Good(pfrom.addr);
|
||||
|
||||
}
|
||||
|
||||
std::string remoteAddr;
|
||||
|
@ -214,20 +214,9 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
|
||||
|
||||
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails)
|
||||
{
|
||||
// Serialize passed information without accessing chain state of the active chain!
|
||||
AssertLockNotHeld(cs_main); // For performance reasons
|
||||
UniValue result = blockheaderToJSON(tip, blockindex, clhandler, isman);
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
|
||||
const CBlockIndex* pnext;
|
||||
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
|
||||
result.pushKV("confirmations", confirmations);
|
||||
result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
|
||||
result.pushKV("height", blockindex->nHeight);
|
||||
result.pushKV("version", block.nVersion);
|
||||
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
|
||||
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
|
||||
bool chainLock = clhandler.HasChainLock(blockindex->nHeight, blockindex->GetBlockHash());
|
||||
UniValue txs(UniValue::VARR);
|
||||
for(const auto& tx : block.vtx)
|
||||
{
|
||||
@ -236,7 +225,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
|
||||
UniValue objTx(UniValue::VOBJ);
|
||||
TxToUniv(*tx, uint256(), objTx, true);
|
||||
bool fLocked = isman.IsLocked(tx->GetHash());
|
||||
objTx.pushKV("instantlock", fLocked || chainLock);
|
||||
objTx.pushKV("instantlock", fLocked || result["chainlock"].get_bool());
|
||||
objTx.pushKV("instantlock_internal", fLocked);
|
||||
txs.push_back(objTx);
|
||||
}
|
||||
@ -249,20 +238,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
|
||||
result.pushKV("cbTx", opt_cbTx->ToJson());
|
||||
}
|
||||
}
|
||||
result.pushKV("time", block.GetBlockTime());
|
||||
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
|
||||
result.pushKV("nonce", (uint64_t)block.nNonce);
|
||||
result.pushKV("bits", strprintf("%08x", block.nBits));
|
||||
result.pushKV("difficulty", GetDifficulty(blockindex));
|
||||
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
|
||||
result.pushKV("nTx", (uint64_t)blockindex->nTx);
|
||||
|
||||
if (blockindex->pprev)
|
||||
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
|
||||
if (pnext)
|
||||
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
|
||||
|
||||
result.pushKV("chainlock", chainLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1168,11 +1143,20 @@ static UniValue getblock(const JSONRPCRequest& request)
|
||||
{
|
||||
{RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
|
||||
{RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
|
||||
{RPCResult::Type::NUM, "size", "The block size"},
|
||||
{RPCResult::Type::NUM, "height", "The block height or index"},
|
||||
{RPCResult::Type::NUM, "version", "The block version"},
|
||||
{RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
|
||||
{RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
|
||||
{RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
|
||||
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
|
||||
{RPCResult::Type::NUM, "nonce", "The nonce"},
|
||||
{RPCResult::Type::STR_HEX, "bits", "The bits"},
|
||||
{RPCResult::Type::NUM, "difficulty", "The difficulty"},
|
||||
{RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
|
||||
{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
|
||||
{RPCResult::Type::STR_HEX, "previousblockhash", /* optional */ true, "The hash of the previous block (if available)"},
|
||||
{RPCResult::Type::STR_HEX, "nextblockhash", /* optional */ true, "The hash of the next block (if available)"},
|
||||
{RPCResult::Type::NUM, "size", "The block size"},
|
||||
{RPCResult::Type::ARR, "tx", "The transaction ids",
|
||||
{{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
|
||||
{RPCResult::Type::OBJ, "cbTx", "The coinbase special transaction",
|
||||
@ -1182,15 +1166,6 @@ static UniValue getblock(const JSONRPCRequest& request)
|
||||
{RPCResult::Type::STR_HEX, "merkleRootMNList", "The merkle root of the masternode list"},
|
||||
{RPCResult::Type::STR_HEX, "merkleRootQuorums", "The merkle root of the quorum list"},
|
||||
}},
|
||||
{RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
|
||||
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
|
||||
{RPCResult::Type::NUM, "nonce", "The nonce"},
|
||||
{RPCResult::Type::STR_HEX, "bits", "The bits"},
|
||||
{RPCResult::Type::NUM, "difficulty", "The difficulty"},
|
||||
{RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
|
||||
{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
|
||||
{RPCResult::Type::STR_HEX, "previousblockhash", "The hash of the previous block"},
|
||||
{RPCResult::Type::STR_HEX, "nextblockhash", "The hash of the next block"},
|
||||
}},
|
||||
RPCResult{"for verbosity = 2",
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
|
@ -188,21 +188,60 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
||||
std::string pszDest;
|
||||
|
||||
std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(id++, NODE_NETWORK, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY);
|
||||
std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(
|
||||
id++, NODE_NETWORK, hSocket, addr,
|
||||
/* nKeyedNetGroupIn = */ 0,
|
||||
/* nLocalHostNonceIn = */ 0,
|
||||
CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY);
|
||||
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
||||
BOOST_CHECK(pnode1->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
||||
BOOST_CHECK(pnode1->IsFeelerConn() == false);
|
||||
BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
|
||||
BOOST_CHECK(pnode1->IsInboundConn() == false);
|
||||
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
|
||||
|
||||
std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(id++, NODE_NETWORK, hSocket, addr, 1, 1, CAddress(), pszDest, ConnectionType::INBOUND);
|
||||
std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(
|
||||
id++, NODE_NETWORK, hSocket, addr,
|
||||
/* nKeyedNetGroupIn = */ 1,
|
||||
/* nLocalHostNonceIn = */ 1,
|
||||
CAddress(), pszDest, ConnectionType::INBOUND,
|
||||
/* inbound_onion = */ false);
|
||||
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
||||
BOOST_CHECK(pnode2->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
||||
BOOST_CHECK(pnode2->IsFeelerConn() == false);
|
||||
BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
|
||||
BOOST_CHECK(pnode2->IsInboundConn() == true);
|
||||
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
|
||||
|
||||
std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(
|
||||
id++, NODE_NETWORK, hSocket, addr,
|
||||
/* nKeyedNetGroupIn = */ 0,
|
||||
/* nLocalHostNonceIn = */ 0,
|
||||
CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/* inbound_onion = */ true);
|
||||
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
||||
BOOST_CHECK(pnode3->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
||||
BOOST_CHECK(pnode3->IsFeelerConn() == false);
|
||||
BOOST_CHECK(pnode3->IsAddrFetchConn() == false);
|
||||
BOOST_CHECK(pnode3->IsInboundConn() == false);
|
||||
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
|
||||
|
||||
std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(
|
||||
id++, NODE_NETWORK, hSocket, addr,
|
||||
/* nKeyedNetGroupIn = */ 1,
|
||||
/* nLocalHostNonceIn = */ 1,
|
||||
CAddress(), pszDest, ConnectionType::INBOUND,
|
||||
/* inbound_onion = */ true);
|
||||
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
||||
BOOST_CHECK(pnode4->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
||||
BOOST_CHECK(pnode4->IsFeelerConn() == false);
|
||||
BOOST_CHECK(pnode4->IsAddrFetchConn() == false);
|
||||
BOOST_CHECK(pnode4->IsInboundConn() == true);
|
||||
BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PoissonNextSend)
|
||||
|
@ -51,6 +51,7 @@ namespace {
|
||||
//! Construct wallet tx struct.
|
||||
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
WalletTx result;
|
||||
bool fInputDenomFound{false}, fOutputDenomFound{false};
|
||||
result.tx = wtx.tx;
|
||||
@ -172,8 +173,16 @@ public:
|
||||
{
|
||||
return m_wallet->SignMessage(message, pkhash, str_sig);
|
||||
}
|
||||
bool isSpendable(const CScript& script) override { return m_wallet->IsMine(script) & ISMINE_SPENDABLE; }
|
||||
bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
|
||||
bool isSpendable(const CScript& script) override
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
return m_wallet->IsMine(script) & ISMINE_SPENDABLE;
|
||||
}
|
||||
bool isSpendable(const CTxDestination& dest) override
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
return m_wallet->IsMine(dest) & ISMINE_SPENDABLE;
|
||||
}
|
||||
bool haveWatchOnly() override
|
||||
{
|
||||
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
||||
|
@ -361,7 +361,7 @@ std::string COutput::ToString() const
|
||||
|
||||
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
AssertLockHeld(cs_wallet);
|
||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
|
||||
if (it == mapWallet.end())
|
||||
return nullptr;
|
||||
@ -1326,15 +1326,13 @@ void CWallet::BlockUntilSyncedToCurrentChain() const {
|
||||
|
||||
isminetype CWallet::IsMine(const CTxIn &txin) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
|
||||
if (mi != mapWallet.end())
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
|
||||
if (mi != mapWallet.end())
|
||||
{
|
||||
const CWalletTx& prev = (*mi).second;
|
||||
if (txin.prevout.n < prev.tx->vout.size())
|
||||
return IsMine(prev.tx->vout[txin.prevout.n]);
|
||||
}
|
||||
const CWalletTx& prev = (*mi).second;
|
||||
if (txin.prevout.n < prev.tx->vout.size())
|
||||
return IsMine(prev.tx->vout[txin.prevout.n]);
|
||||
}
|
||||
return ISMINE_NO;
|
||||
}
|
||||
@ -1487,16 +1485,19 @@ bool CWallet::IsFullyMixed(const COutPoint& outpoint) const
|
||||
|
||||
isminetype CWallet::IsMine(const CTxOut& txout) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
return IsMine(txout.scriptPubKey);
|
||||
}
|
||||
|
||||
isminetype CWallet::IsMine(const CTxDestination& dest) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
return IsMine(GetScriptForDestination(dest));
|
||||
}
|
||||
|
||||
isminetype CWallet::IsMine(const CScript& script) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
isminetype result = ISMINE_NO;
|
||||
for (const auto& spk_man_pair : m_spk_managers) {
|
||||
result = std::max(result, spk_man_pair.second->IsMine(script));
|
||||
@ -1508,6 +1509,7 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons
|
||||
{
|
||||
if (!MoneyRange(txout.nValue))
|
||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||
LOCK(cs_wallet);
|
||||
return ((IsMine(txout) & filter) ? txout.nValue : 0);
|
||||
}
|
||||
|
||||
@ -1525,13 +1527,12 @@ bool CWallet::IsChange(const CScript& script) const
|
||||
// a better way of identifying which outputs are 'the send' and which are
|
||||
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
|
||||
// which output, if any, was change).
|
||||
AssertLockHeld(cs_wallet);
|
||||
if (IsMine(script))
|
||||
{
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(script, address))
|
||||
return true;
|
||||
|
||||
LOCK(cs_wallet);
|
||||
if (!FindAddressBookEntry(address)) {
|
||||
return true;
|
||||
}
|
||||
@ -1541,6 +1542,7 @@ bool CWallet::IsChange(const CScript& script) const
|
||||
|
||||
CAmount CWallet::GetChange(const CTxOut& txout) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
if (!MoneyRange(txout.nValue))
|
||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||
return (IsChange(txout) ? txout.nValue : 0);
|
||||
@ -1548,6 +1550,7 @@ CAmount CWallet::GetChange(const CTxOut& txout) const
|
||||
|
||||
bool CWallet::IsMine(const CTransaction& tx) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
for (const CTxOut& txout : tx.vout)
|
||||
if (IsMine(txout))
|
||||
return true;
|
||||
@ -1606,6 +1609,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
|
||||
|
||||
CAmount CWallet::GetChange(const CTransaction& tx) const
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
CAmount nChange = 0;
|
||||
for (const CTxOut& txout : tx.vout)
|
||||
{
|
||||
@ -1846,6 +1850,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
||||
nFee = nDebit - nValueOut;
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
// Sent/received.
|
||||
for (unsigned int i = 0; i < tx->vout.size(); ++i)
|
||||
{
|
||||
@ -2340,6 +2345,7 @@ bool CWalletTx::IsTrusted(std::set<uint256>& trusted_parents) const
|
||||
if (!InMempool()) return false;
|
||||
|
||||
// Trusted if all inputs are from us and are in the mempool:
|
||||
LOCK(pwallet->cs_wallet);
|
||||
for (const CTxIn& txin : tx->vin)
|
||||
{
|
||||
// Transactions not sent by us: not trusted
|
||||
@ -3957,6 +3963,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
|
||||
bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
|
||||
{
|
||||
bool fUpdated = false;
|
||||
bool is_mine;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
|
||||
@ -3964,8 +3971,9 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
|
||||
m_address_book[address].SetLabel(strName);
|
||||
if (!strPurpose.empty()) /* update purpose only if requested */
|
||||
m_address_book[address].purpose = strPurpose;
|
||||
is_mine = IsMine(address) != ISMINE_NO;
|
||||
}
|
||||
NotifyAddressBookChanged(this, address, strName, IsMine(address) != ISMINE_NO,
|
||||
NotifyAddressBookChanged(this, address, strName, is_mine,
|
||||
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
||||
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
|
||||
return false;
|
||||
@ -3980,18 +3988,17 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
|
||||
|
||||
bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||
{
|
||||
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
|
||||
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
|
||||
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
|
||||
if (IsMine(address)) {
|
||||
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_mine;
|
||||
WalletBatch batch(GetDatabase());
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
|
||||
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
|
||||
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
|
||||
if (IsMine(address)) {
|
||||
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
|
||||
return false;
|
||||
}
|
||||
// Delete destdata tuples associated with address
|
||||
std::string strAddress = EncodeDestination(address);
|
||||
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
|
||||
@ -3999,9 +4006,10 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||
batch.EraseDestData(strAddress, item.first);
|
||||
}
|
||||
m_address_book.erase(address);
|
||||
is_mine = IsMine(address) != ISMINE_NO;
|
||||
}
|
||||
|
||||
NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, "", CT_DELETED);
|
||||
NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED);
|
||||
|
||||
batch.ErasePurpose(EncodeDestination(address));
|
||||
return batch.EraseName(EncodeDestination(address));
|
||||
|
@ -885,7 +885,7 @@ public:
|
||||
/** Interface for accessing CoinJoin state. */
|
||||
interfaces::CoinJoin::Loader& coinjoin_loader() { assert(m_coinjoin_loader); return *m_coinjoin_loader; }
|
||||
|
||||
const CWalletTx* GetWalletTx(const uint256& hash) const;
|
||||
const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
//! check whether we are allowed to upgrade (or already support) to the named feature
|
||||
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
|
||||
@ -1146,20 +1146,20 @@ public:
|
||||
bool GetNewDestination(const std::string label, CTxDestination& dest, std::string& error);
|
||||
bool GetNewChangeDestination(CTxDestination& dest, std::string& error);
|
||||
|
||||
isminetype IsMine(const CTxDestination& dest) const;
|
||||
isminetype IsMine(const CScript& script) const;
|
||||
isminetype IsMine(const CTxIn& txin) const;
|
||||
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
/**
|
||||
* Returns amount of debit if the input matches the
|
||||
* filter, otherwise returns 0
|
||||
*/
|
||||
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
|
||||
isminetype IsMine(const CTxOut& txout) const;
|
||||
isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
|
||||
bool IsChange(const CTxOut& txout) const;
|
||||
bool IsChange(const CScript& script) const;
|
||||
CAmount GetChange(const CTxOut& txout) const;
|
||||
bool IsMine(const CTransaction& tx) const;
|
||||
bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
/** should probably be renamed to IsRelevantToMe */
|
||||
bool IsFromMe(const CTransaction& tx) const;
|
||||
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
|
||||
|
@ -4,7 +4,7 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test BIP68 implementation."""
|
||||
|
||||
from test_framework.blocktools import create_block, create_coinbase
|
||||
from test_framework.blocktools import create_block, NORMAL_GBT_REQUEST_PARAMS
|
||||
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
@ -270,6 +270,8 @@ class BIP68Test(BitcoinTestFramework):
|
||||
|
||||
# Advance the time on the node so that we can test timelocks
|
||||
self.nodes[0].setmocktime(cur_time+600)
|
||||
# Save block template now to use for the reorg later
|
||||
tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
|
||||
self.nodes[0].generate(1)
|
||||
assert tx2.hash not in self.nodes[0].getrawmempool()
|
||||
|
||||
@ -313,16 +315,15 @@ class BIP68Test(BitcoinTestFramework):
|
||||
# diagram above).
|
||||
# This would cause tx2 to be added back to the mempool, which in turn causes
|
||||
# tx3 to be removed.
|
||||
tip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount()-1), 16)
|
||||
height = self.nodes[0].getblockcount()
|
||||
for i in range(2):
|
||||
block = create_block(tip, create_coinbase(height), cur_time)
|
||||
block.nVersion = 3
|
||||
block = create_block(tmpl=tmpl, ntime=cur_time)
|
||||
block.rehash()
|
||||
block.solve()
|
||||
tip = block.sha256
|
||||
height += 1
|
||||
assert_equal(None if i == 1 else 'inconclusive', self.nodes[0].submitblock(ToHex(block)))
|
||||
tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
|
||||
tmpl['previousblockhash'] = '%x' % tip
|
||||
tmpl['transactions'] = []
|
||||
cur_time += 1
|
||||
|
||||
mempool = self.nodes[0].getrawmempool()
|
||||
@ -370,9 +371,7 @@ class BIP68Test(BitcoinTestFramework):
|
||||
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))
|
||||
|
||||
# make a block that violates bip68; ensure that the tip updates
|
||||
tip = int(self.nodes[0].getbestblockhash(), 16)
|
||||
block = create_block(tip, create_coinbase(self.nodes[0].getblockcount()+1), self.mocktime + 600)
|
||||
block.nVersion = 3
|
||||
block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
|
||||
block.vtx.extend([tx1, tx2, tx3])
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
|
@ -1273,7 +1273,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
blocks = []
|
||||
spend = out[32]
|
||||
for i in range(89, LARGE_REORG_SIZE + 89):
|
||||
b = self.next_block(i, spend, version=4)
|
||||
b = self.next_block(i, spend)
|
||||
tx = CTransaction()
|
||||
script_length = MAX_BLOCK_SIZE - len(b.serialize()) - 69
|
||||
script_output = CScript([b'\x00' * script_length])
|
||||
@ -1292,18 +1292,18 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.move_tip(88)
|
||||
blocks2 = []
|
||||
for i in range(89, LARGE_REORG_SIZE + 89):
|
||||
blocks2.append(self.next_block("alt" + str(i), version=4))
|
||||
blocks2.append(self.next_block("alt" + str(i)))
|
||||
self.send_blocks(blocks2, False, force_send=True)
|
||||
|
||||
# extend alt chain to trigger re-org
|
||||
block = self.next_block("alt" + str(chain1_tip + 1), version=4)
|
||||
block = self.next_block("alt" + str(chain1_tip + 1))
|
||||
self.send_blocks([block], True, timeout=2440)
|
||||
|
||||
# ... and re-org back to the first chain
|
||||
self.move_tip(chain1_tip)
|
||||
block = self.next_block(chain1_tip + 1, version=4)
|
||||
block = self.next_block(chain1_tip + 1)
|
||||
self.send_blocks([block], False, force_send=True)
|
||||
block = self.next_block(chain1_tip + 2, version=4)
|
||||
block = self.next_block(chain1_tip + 2)
|
||||
self.send_blocks([block], True, timeout=2440)
|
||||
|
||||
self.log.info("Reject a block with an invalid block header version")
|
||||
@ -1311,7 +1311,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.send_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)', reconnect=True)
|
||||
|
||||
self.move_tip(chain1_tip + 2)
|
||||
b_cb34 = self.next_block('b_cb34', version=4)
|
||||
b_cb34 = self.next_block('b_cb34')
|
||||
b_cb34.vtx[0].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1]
|
||||
b_cb34.vtx[0].rehash()
|
||||
b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()
|
||||
@ -1345,7 +1345,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx.rehash()
|
||||
return tx
|
||||
|
||||
def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), *, version=1):
|
||||
def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), *, version=4):
|
||||
if self.tip is None:
|
||||
base_block_hash = self.genesis_hash
|
||||
block_time = self.mocktime + 1
|
||||
|
@ -151,7 +151,6 @@ class BIP68_112_113Test(BitcoinTestFramework):
|
||||
# and '-dip3params=2000:2000' to create pre-dip3 blocks only
|
||||
self.extra_args = [[
|
||||
'-whitelist=noban@127.0.0.1',
|
||||
'-blockversion=4',
|
||||
'-maxtipage=600100', '-dip3params=2000:2000',
|
||||
'-par=1', # Use only one script thread to get the exact reject reason for testing
|
||||
]]
|
||||
|
@ -44,7 +44,6 @@ class NotificationsTest(DashTestFramework):
|
||||
# -alertnotify and -blocknotify on node0, walletnotify on node1
|
||||
self.extra_args[0].append("-alertnotify=echo > {}".format(os.path.join(self.alertnotify_dir, '%s')))
|
||||
self.extra_args[0].append("-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s')))
|
||||
self.extra_args[1].append("-blockversion=211")
|
||||
self.extra_args[1].append("-rescan")
|
||||
self.extra_args[1].append("-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))))
|
||||
|
||||
|
@ -13,7 +13,7 @@ Generate 427 more blocks.
|
||||
[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.
|
||||
"""
|
||||
|
||||
from test_framework.blocktools import create_coinbase, create_block, create_transaction
|
||||
from test_framework.blocktools import NORMAL_GBT_REQUEST_PARAMS, create_block, create_transaction
|
||||
from test_framework.messages import CTransaction
|
||||
from test_framework.script import CScript
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
@ -37,9 +37,10 @@ def trueDummy(tx):
|
||||
class NULLDUMMYTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
# Need two nodes only so GBT doesn't complain that it's not connected
|
||||
self.num_nodes = 2
|
||||
self.setup_clean_chain = True
|
||||
self.extra_args = [['-whitelist=127.0.0.1']]
|
||||
self.extra_args = [['-whitelist=127.0.0.1']] * 2
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
@ -54,7 +55,6 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
||||
coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
|
||||
self.nodes[0].generate(427) # Block 429
|
||||
self.lastblockhash = self.nodes[0].getbestblockhash()
|
||||
self.tip = int("0x" + self.lastblockhash, 0)
|
||||
self.lastblockheight = 429
|
||||
self.lastblocktime = self.mocktime + 429
|
||||
|
||||
@ -88,8 +88,10 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
||||
|
||||
def block_submit(self, node, txs, accept = False):
|
||||
dip4_activated = self.lastblockheight + 1 >= 432
|
||||
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, dip4_activated=dip4_activated), self.lastblocktime + 1)
|
||||
block.nVersion = 4
|
||||
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
|
||||
assert_equal(tmpl['previousblockhash'], self.lastblockhash)
|
||||
assert_equal(tmpl['height'], self.lastblockheight + 1)
|
||||
block = create_block(tmpl=tmpl, ntime=self.lastblocktime + 1, dip4_activated=dip4_activated)
|
||||
for tx in txs:
|
||||
tx.rehash()
|
||||
block.vtx.append(tx)
|
||||
@ -99,7 +101,6 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
||||
assert_equal(None if accept else 'block-validation-failed', node.submitblock(block.serialize().hex()))
|
||||
if (accept):
|
||||
assert_equal(node.getbestblockhash(), block.hash)
|
||||
self.tip = block.sha256
|
||||
self.lastblockhash = block.hash
|
||||
self.lastblocktime += 1
|
||||
self.lastblockheight += 1
|
||||
|
@ -13,6 +13,8 @@ from decimal import Decimal
|
||||
|
||||
from test_framework.blocktools import (
|
||||
create_coinbase,
|
||||
NORMAL_GBT_REQUEST_PARAMS,
|
||||
TIME_GENESIS_BLOCK,
|
||||
)
|
||||
from test_framework.messages import (
|
||||
CBlock,
|
||||
@ -26,6 +28,8 @@ from test_framework.util import (
|
||||
assert_raises_rpc_error,
|
||||
)
|
||||
|
||||
VERSIONBITS_TOP_BITS = 0x20000000
|
||||
VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
|
||||
|
||||
def assert_template(node, block, expect, rehash=True):
|
||||
if rehash:
|
||||
@ -45,14 +49,23 @@ class MiningTest(BitcoinTestFramework):
|
||||
|
||||
def mine_chain(self):
|
||||
self.log.info('Create some old blocks')
|
||||
for _ in range(200):
|
||||
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 156, 156):
|
||||
self.bump_mocktime(156)
|
||||
self.nodes[0].generate(1)
|
||||
mining_info = self.nodes[0].getmininginfo()
|
||||
assert_equal(mining_info['blocks'], 200)
|
||||
assert_equal(mining_info['currentblocktx'], 0)
|
||||
assert_equal(mining_info['currentblocksize'], 1000)
|
||||
|
||||
self.log.info('test blockversion')
|
||||
self.restart_node(0, extra_args=['-mocktime={}'.format(t), '-blockversion=1337'])
|
||||
self.connect_nodes(0, 1)
|
||||
assert_equal(1337, self.nodes[0].getblocktemplate()['version'])
|
||||
self.restart_node(0, extra_args=['-mocktime={}'.format(t)])
|
||||
self.connect_nodes(0, 1)
|
||||
assert_equal(VERSIONBITS_TOP_BITS + (1 << VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT), self.nodes[0].getblocktemplate()['version'])
|
||||
self.restart_node(0)
|
||||
# TODO: replace with connect_nodes_bi
|
||||
self.connect_nodes(0, 1)
|
||||
self.connect_nodes(1, 0)
|
||||
|
||||
@ -78,7 +91,7 @@ class MiningTest(BitcoinTestFramework):
|
||||
|
||||
# Mine a block to leave initial block download
|
||||
node.generatetoaddress(1, node.get_deterministic_priv_key().address)
|
||||
tmpl = node.getblocktemplate()
|
||||
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
|
||||
self.log.info("getblocktemplate: Test capability advertised")
|
||||
assert 'proposal' in tmpl['capabilities']
|
||||
assert 'coinbasetxn' not in tmpl
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
import random
|
||||
|
||||
from test_framework.blocktools import COINBASE_MATURITY, create_block, create_coinbase
|
||||
from test_framework.blocktools import COINBASE_MATURITY, create_block, NORMAL_GBT_REQUEST_PARAMS
|
||||
from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, HeaderAndShortIDs, msg_block, msg_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, MSG_BLOCK, MSG_CMPCT_BLOCK, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ToHex, NODE_HEADERS_COMPRESSED
|
||||
from test_framework.p2p import p2p_lock, P2PInterface
|
||||
from test_framework.script import CScript, OP_TRUE, OP_DROP
|
||||
@ -103,10 +103,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def build_block_on_tip(self, node):
|
||||
height = node.getblockcount()
|
||||
tip = node.getbestblockhash()
|
||||
mtp = node.getblockheader(tip)['mediantime']
|
||||
block = create_block(int(tip, 16), create_coinbase(height + 1), mtp + 1)
|
||||
block = create_block(tmpl=node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
|
||||
block.solve()
|
||||
return block
|
||||
|
||||
@ -718,6 +715,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
||||
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
|
||||
|
||||
def run_test(self):
|
||||
# Get the nodes out of IBD
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
# Setup the p2p connections
|
||||
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=1))
|
||||
self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=1), services=NODE_NETWORK | NODE_HEADERS_COMPRESSED)
|
||||
|
@ -4,7 +4,11 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Utilities for manipulating blocks and transactions."""
|
||||
|
||||
from binascii import a2b_hex
|
||||
from decimal import Decimal
|
||||
import io
|
||||
import struct
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from .messages import (
|
||||
@ -30,18 +34,30 @@ TIME_GENESIS_BLOCK = 1417713337
|
||||
# Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
|
||||
COINBASE_MATURITY = 100
|
||||
|
||||
def create_block(hashprev, coinbase, ntime=None, *, version=1):
|
||||
NORMAL_GBT_REQUEST_PARAMS = {"rules": []} # type: ignore[var-annotated]
|
||||
|
||||
def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl=None, txlist=None, dip4_activated=False, v20_activated=False):
|
||||
"""Create a block (with regtest difficulty)."""
|
||||
block = CBlock()
|
||||
block.nVersion = version
|
||||
if ntime is None:
|
||||
import time
|
||||
block.nTime = int(time.time() + 600)
|
||||
if tmpl is None:
|
||||
tmpl = {}
|
||||
block.nVersion = version or tmpl.get('version') or 1
|
||||
block.nTime = ntime or tmpl.get('curtime') or int(time.time() + 600)
|
||||
block.hashPrevBlock = hashprev or int(tmpl['previousblockhash'], 0x10)
|
||||
if tmpl and not tmpl.get('bits') is None:
|
||||
block.nBits = struct.unpack('>I', a2b_hex(tmpl['bits']))[0]
|
||||
else:
|
||||
block.nTime = ntime
|
||||
block.hashPrevBlock = hashprev
|
||||
block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams
|
||||
block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams
|
||||
if coinbase is None:
|
||||
coinbase = create_coinbase(height=tmpl['height'], dip4_activated=dip4_activated, v20_activated=v20_activated)
|
||||
block.vtx.append(coinbase)
|
||||
if txlist:
|
||||
for tx in txlist:
|
||||
if not hasattr(tx, 'calc_sha256'):
|
||||
txo = CTransaction()
|
||||
txo.deserialize(io.BytesIO(tx))
|
||||
tx = txo
|
||||
block.vtx.append(tx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.calc_sha256()
|
||||
return block
|
||||
|
Loading…
Reference in New Issue
Block a user