mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32: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)
|
See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort)
|
||||||
for how to properly configure Tor.
|
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
|
## 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
|
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).
|
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
|
-externalip=X You can tell Dash Core about its publicly reachable addresses using
|
||||||
this option, and this can be a .onion address. Given the above
|
this option, and this can be an onion address. Given the above
|
||||||
configuration, you can find your .onion address in
|
configuration, you can find your onion address in
|
||||||
/var/lib/tor/dashcore-service/hostname. For connections
|
/var/lib/tor/dashcore-service/hostname. For connections
|
||||||
coming from unroutable addresses (such as 127.0.0.1, where the
|
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.
|
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
|
-listen You'll need to enable listening for incoming connections, as this
|
||||||
is off by default behind a proxy.
|
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:
|
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
|
(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
|
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
|
If you only want to use Tor to reach .onion addresses, but not use it as a proxy
|
||||||
for normal IPv4/IPv6 communication, use:
|
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
|
## 3.1. List of known Dash Core Tor relays
|
||||||
|
@ -15,24 +15,49 @@
|
|||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
static void BlockToJsonVerbose(benchmark::Bench& bench) {
|
namespace {
|
||||||
|
|
||||||
|
struct TestBlockAndIndex {
|
||||||
TestingSetup test_setup{};
|
TestingSetup test_setup{};
|
||||||
|
CBlock block{};
|
||||||
|
uint256 blockHash{};
|
||||||
|
CBlockIndex blockindex{};
|
||||||
|
|
||||||
CDataStream stream(benchmark::data::block813851, SER_NETWORK, PROTOCOL_VERSION);
|
TestBlockAndIndex()
|
||||||
char a = '\0';
|
{
|
||||||
stream.write(&a, 1); // Prevent compaction
|
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;
|
blockHash = block.GetHash();
|
||||||
const uint256 blockHash = block.GetHash();
|
blockindex.phashBlock = &blockHash;
|
||||||
blockindex.phashBlock = &blockHash;
|
blockindex.nBits = 403014710;
|
||||||
blockindex.nBits = 403014710;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static void BlockToJsonVerbose(benchmark::Bench& bench)
|
||||||
|
{
|
||||||
|
TestBlockAndIndex data;
|
||||||
bench.run([&] {
|
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);
|
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
|
// core_read.cpp
|
||||||
CScript ParseScript(const std::string& s);
|
CScript ParseScript(const std::string& s);
|
||||||
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
|
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);
|
[[nodiscard]] bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
|
||||||
bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
|
bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
|
||||||
/**
|
/**
|
||||||
|
@ -100,25 +100,31 @@ CScript ParseScript(const std::string& s)
|
|||||||
return result;
|
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))
|
CDataStream ssData(tx_data, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
return false;
|
|
||||||
|
|
||||||
std::vector<unsigned char> txData(ParseHex(strHexTx));
|
|
||||||
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
|
|
||||||
try {
|
try {
|
||||||
ssData >> tx;
|
ssData >> tx;
|
||||||
if (!ssData.empty())
|
if (!ssData.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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)
|
bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
|
||||||
{
|
{
|
||||||
if (!IsHex(hex_header)) return false;
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
|
||||||
|
{
|
||||||
|
return FindNode(addr.ToStringIPPort());
|
||||||
|
}
|
||||||
|
|
||||||
bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
||||||
{
|
{
|
||||||
LOCK(cs_vNodes);
|
LOCK(cs_vNodes);
|
||||||
@ -2397,11 +2402,30 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
|||||||
if (nTries > 100)
|
if (nTries > 100)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
CAddrInfo addr = addrman.SelectTriedCollision();
|
CAddrInfo addr;
|
||||||
|
|
||||||
// SelectTriedCollision returns an invalid address if it is empty.
|
if (fFeeler) {
|
||||||
if (!fFeeler || !addr.IsValid()) {
|
// First, try to get a tried table collision address. This returns
|
||||||
addr = addrman.Select(fFeeler);
|
// 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);
|
auto dmn = mnList.GetMNByService(addr);
|
||||||
@ -2768,7 +2792,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
|||||||
|
|
||||||
if (!pszDest) {
|
if (!pszDest) {
|
||||||
// banned, discouraged or exact match?
|
// 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;
|
return;
|
||||||
// local and not a connection to itself?
|
// local and not a connection to itself?
|
||||||
bool fAllowLocal = Params().AllowMultiplePorts() && addrConnect.GetPort() != GetListenPort();
|
bool fAllowLocal = Params().AllowMultiplePorts() && addrConnect.GetPort() != GetListenPort();
|
||||||
|
@ -625,6 +625,12 @@ private:
|
|||||||
CNode* FindNode(const std::string& addrName, bool fExcludeDisconnecting = true);
|
CNode* FindNode(const std::string& addrName, bool fExcludeDisconnecting = true);
|
||||||
CNode* FindNode(const CService& addr, 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();
|
bool AttemptToEvictConnection();
|
||||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = nullptr, bool fCountFailure = false, ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY);
|
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;
|
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
|
// empty and no one will know who we are, so these mechanisms are
|
||||||
// important to help us connect to the network.
|
// important to help us connect to the network.
|
||||||
//
|
//
|
||||||
// We also update the addrman to record connection success for
|
// We skip this for BLOCK_RELAY peers to avoid potentially leaking
|
||||||
// these peers (which include OUTBOUND_FULL_RELAY and FEELER
|
// information about our BLOCK_RELAY connections via address relay.
|
||||||
// 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.
|
|
||||||
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
|
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
|
||||||
{
|
{
|
||||||
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
|
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
|
||||||
@ -3043,11 +3037,24 @@ void PeerManagerImpl::ProcessMessage(
|
|||||||
// Get recent addresses
|
// Get recent addresses
|
||||||
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
|
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
|
||||||
pfrom.fGetAddr = true;
|
pfrom.fGetAddr = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Moves address from New to Tried table in Addrman, resolves
|
if (!pfrom.IsInboundConn()) {
|
||||||
// tried-table collisions, etc.
|
// 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);
|
m_addrman.Good(pfrom.addr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string remoteAddr;
|
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)
|
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!
|
UniValue result = blockheaderToJSON(tip, blockindex, clhandler, isman);
|
||||||
AssertLockNotHeld(cs_main); // For performance reasons
|
|
||||||
|
|
||||||
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("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);
|
UniValue txs(UniValue::VARR);
|
||||||
for(const auto& tx : block.vtx)
|
for(const auto& tx : block.vtx)
|
||||||
{
|
{
|
||||||
@ -236,7 +225,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
|
|||||||
UniValue objTx(UniValue::VOBJ);
|
UniValue objTx(UniValue::VOBJ);
|
||||||
TxToUniv(*tx, uint256(), objTx, true);
|
TxToUniv(*tx, uint256(), objTx, true);
|
||||||
bool fLocked = isman.IsLocked(tx->GetHash());
|
bool fLocked = isman.IsLocked(tx->GetHash());
|
||||||
objTx.pushKV("instantlock", fLocked || chainLock);
|
objTx.pushKV("instantlock", fLocked || result["chainlock"].get_bool());
|
||||||
objTx.pushKV("instantlock_internal", fLocked);
|
objTx.pushKV("instantlock_internal", fLocked);
|
||||||
txs.push_back(objTx);
|
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("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;
|
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::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, "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, "height", "The block height or index"},
|
||||||
{RPCResult::Type::NUM, "version", "The block version"},
|
{RPCResult::Type::NUM, "version", "The block version"},
|
||||||
{RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
|
{RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
|
||||||
{RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
|
{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::ARR, "tx", "The transaction ids",
|
||||||
{{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
|
{{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
|
||||||
{RPCResult::Type::OBJ, "cbTx", "The coinbase special transaction",
|
{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, "merkleRootMNList", "The merkle root of the masternode list"},
|
||||||
{RPCResult::Type::STR_HEX, "merkleRootQuorums", "The merkle root of the quorum 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{"for verbosity = 2",
|
||||||
RPCResult::Type::OBJ, "", "",
|
RPCResult::Type::OBJ, "", "",
|
||||||
|
@ -188,21 +188,60 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||||||
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
||||||
std::string pszDest;
|
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->IsFullOutboundConn() == true);
|
||||||
BOOST_CHECK(pnode1->IsManualConn() == false);
|
BOOST_CHECK(pnode1->IsManualConn() == false);
|
||||||
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
||||||
BOOST_CHECK(pnode1->IsFeelerConn() == false);
|
BOOST_CHECK(pnode1->IsFeelerConn() == false);
|
||||||
BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
|
BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
|
||||||
BOOST_CHECK(pnode1->IsInboundConn() == 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->IsFullOutboundConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsManualConn() == false);
|
BOOST_CHECK(pnode2->IsManualConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsFeelerConn() == false);
|
BOOST_CHECK(pnode2->IsFeelerConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
|
BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsInboundConn() == true);
|
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)
|
BOOST_AUTO_TEST_CASE(PoissonNextSend)
|
||||||
|
@ -51,6 +51,7 @@ namespace {
|
|||||||
//! Construct wallet tx struct.
|
//! Construct wallet tx struct.
|
||||||
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
||||||
{
|
{
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
WalletTx result;
|
WalletTx result;
|
||||||
bool fInputDenomFound{false}, fOutputDenomFound{false};
|
bool fInputDenomFound{false}, fOutputDenomFound{false};
|
||||||
result.tx = wtx.tx;
|
result.tx = wtx.tx;
|
||||||
@ -172,8 +173,16 @@ public:
|
|||||||
{
|
{
|
||||||
return m_wallet->SignMessage(message, pkhash, str_sig);
|
return m_wallet->SignMessage(message, pkhash, str_sig);
|
||||||
}
|
}
|
||||||
bool isSpendable(const CScript& script) override { return m_wallet->IsMine(script) & ISMINE_SPENDABLE; }
|
bool isSpendable(const CScript& script) override
|
||||||
bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
|
{
|
||||||
|
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
|
bool haveWatchOnly() override
|
||||||
{
|
{
|
||||||
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
||||||
|
@ -361,7 +361,7 @@ std::string COutput::ToString() const
|
|||||||
|
|
||||||
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) 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);
|
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
|
||||||
if (it == mapWallet.end())
|
if (it == mapWallet.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1326,15 +1326,13 @@ void CWallet::BlockUntilSyncedToCurrentChain() const {
|
|||||||
|
|
||||||
isminetype CWallet::IsMine(const CTxIn &txin) 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);
|
const CWalletTx& prev = (*mi).second;
|
||||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
|
if (txin.prevout.n < prev.tx->vout.size())
|
||||||
if (mi != mapWallet.end())
|
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;
|
return ISMINE_NO;
|
||||||
}
|
}
|
||||||
@ -1487,16 +1485,19 @@ bool CWallet::IsFullyMixed(const COutPoint& outpoint) const
|
|||||||
|
|
||||||
isminetype CWallet::IsMine(const CTxOut& txout) const
|
isminetype CWallet::IsMine(const CTxOut& txout) const
|
||||||
{
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
return IsMine(txout.scriptPubKey);
|
return IsMine(txout.scriptPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
isminetype CWallet::IsMine(const CTxDestination& dest) const
|
isminetype CWallet::IsMine(const CTxDestination& dest) const
|
||||||
{
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
return IsMine(GetScriptForDestination(dest));
|
return IsMine(GetScriptForDestination(dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
isminetype CWallet::IsMine(const CScript& script) const
|
isminetype CWallet::IsMine(const CScript& script) const
|
||||||
{
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
isminetype result = ISMINE_NO;
|
isminetype result = ISMINE_NO;
|
||||||
for (const auto& spk_man_pair : m_spk_managers) {
|
for (const auto& spk_man_pair : m_spk_managers) {
|
||||||
result = std::max(result, spk_man_pair.second->IsMine(script));
|
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))
|
if (!MoneyRange(txout.nValue))
|
||||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||||
|
LOCK(cs_wallet);
|
||||||
return ((IsMine(txout) & filter) ? txout.nValue : 0);
|
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
|
// 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
|
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
|
||||||
// which output, if any, was change).
|
// which output, if any, was change).
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
if (IsMine(script))
|
if (IsMine(script))
|
||||||
{
|
{
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
if (!ExtractDestination(script, address))
|
if (!ExtractDestination(script, address))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
LOCK(cs_wallet);
|
|
||||||
if (!FindAddressBookEntry(address)) {
|
if (!FindAddressBookEntry(address)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1541,6 +1542,7 @@ bool CWallet::IsChange(const CScript& script) const
|
|||||||
|
|
||||||
CAmount CWallet::GetChange(const CTxOut& txout) const
|
CAmount CWallet::GetChange(const CTxOut& txout) const
|
||||||
{
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
if (!MoneyRange(txout.nValue))
|
if (!MoneyRange(txout.nValue))
|
||||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||||
return (IsChange(txout) ? txout.nValue : 0);
|
return (IsChange(txout) ? txout.nValue : 0);
|
||||||
@ -1548,6 +1550,7 @@ CAmount CWallet::GetChange(const CTxOut& txout) const
|
|||||||
|
|
||||||
bool CWallet::IsMine(const CTransaction& tx) const
|
bool CWallet::IsMine(const CTransaction& tx) const
|
||||||
{
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
for (const CTxOut& txout : tx.vout)
|
for (const CTxOut& txout : tx.vout)
|
||||||
if (IsMine(txout))
|
if (IsMine(txout))
|
||||||
return true;
|
return true;
|
||||||
@ -1606,6 +1609,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
|
|||||||
|
|
||||||
CAmount CWallet::GetChange(const CTransaction& tx) const
|
CAmount CWallet::GetChange(const CTransaction& tx) const
|
||||||
{
|
{
|
||||||
|
LOCK(cs_wallet);
|
||||||
CAmount nChange = 0;
|
CAmount nChange = 0;
|
||||||
for (const CTxOut& txout : tx.vout)
|
for (const CTxOut& txout : tx.vout)
|
||||||
{
|
{
|
||||||
@ -1846,6 +1850,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
|||||||
nFee = nDebit - nValueOut;
|
nFee = nDebit - nValueOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOCK(pwallet->cs_wallet);
|
||||||
// Sent/received.
|
// Sent/received.
|
||||||
for (unsigned int i = 0; i < tx->vout.size(); ++i)
|
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;
|
if (!InMempool()) return false;
|
||||||
|
|
||||||
// Trusted if all inputs are from us and are in the mempool:
|
// Trusted if all inputs are from us and are in the mempool:
|
||||||
|
LOCK(pwallet->cs_wallet);
|
||||||
for (const CTxIn& txin : tx->vin)
|
for (const CTxIn& txin : tx->vin)
|
||||||
{
|
{
|
||||||
// Transactions not sent by us: not trusted
|
// 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 CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
|
||||||
{
|
{
|
||||||
bool fUpdated = false;
|
bool fUpdated = false;
|
||||||
|
bool is_mine;
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
|
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);
|
m_address_book[address].SetLabel(strName);
|
||||||
if (!strPurpose.empty()) /* update purpose only if requested */
|
if (!strPurpose.empty()) /* update purpose only if requested */
|
||||||
m_address_book[address].purpose = strPurpose;
|
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) );
|
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
||||||
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
|
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
|
||||||
return false;
|
return false;
|
||||||
@ -3980,18 +3988,17 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
|
|||||||
|
|
||||||
bool CWallet::DelAddressBook(const CTxDestination& address)
|
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)
|
bool is_mine;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletBatch batch(GetDatabase());
|
WalletBatch batch(GetDatabase());
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
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
|
// Delete destdata tuples associated with address
|
||||||
std::string strAddress = EncodeDestination(address);
|
std::string strAddress = EncodeDestination(address);
|
||||||
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
|
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);
|
batch.EraseDestData(strAddress, item.first);
|
||||||
}
|
}
|
||||||
m_address_book.erase(address);
|
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));
|
batch.ErasePurpose(EncodeDestination(address));
|
||||||
return batch.EraseName(EncodeDestination(address));
|
return batch.EraseName(EncodeDestination(address));
|
||||||
|
@ -885,7 +885,7 @@ public:
|
|||||||
/** Interface for accessing CoinJoin state. */
|
/** Interface for accessing CoinJoin state. */
|
||||||
interfaces::CoinJoin::Loader& coinjoin_loader() { assert(m_coinjoin_loader); return *m_coinjoin_loader; }
|
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
|
//! 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; }
|
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 GetNewDestination(const std::string label, CTxDestination& dest, std::string& error);
|
||||||
bool GetNewChangeDestination(CTxDestination& dest, std::string& error);
|
bool GetNewChangeDestination(CTxDestination& dest, std::string& error);
|
||||||
|
|
||||||
isminetype IsMine(const CTxDestination& dest) const;
|
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
isminetype IsMine(const CScript& script) const;
|
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
isminetype IsMine(const CTxIn& txin) const;
|
isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
/**
|
/**
|
||||||
* Returns amount of debit if the input matches the
|
* Returns amount of debit if the input matches the
|
||||||
* filter, otherwise returns 0
|
* filter, otherwise returns 0
|
||||||
*/
|
*/
|
||||||
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
|
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;
|
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
|
||||||
bool IsChange(const CTxOut& txout) const;
|
bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
bool IsChange(const CScript& script) const;
|
bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
CAmount GetChange(const CTxOut& txout) const;
|
CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
bool IsMine(const CTransaction& tx) const;
|
bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
/** should probably be renamed to IsRelevantToMe */
|
/** should probably be renamed to IsRelevantToMe */
|
||||||
bool IsFromMe(const CTransaction& tx) const;
|
bool IsFromMe(const CTransaction& tx) const;
|
||||||
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) 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.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
"""Test BIP68 implementation."""
|
"""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.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
@ -270,6 +270,8 @@ class BIP68Test(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Advance the time on the node so that we can test timelocks
|
# Advance the time on the node so that we can test timelocks
|
||||||
self.nodes[0].setmocktime(cur_time+600)
|
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)
|
self.nodes[0].generate(1)
|
||||||
assert tx2.hash not in self.nodes[0].getrawmempool()
|
assert tx2.hash not in self.nodes[0].getrawmempool()
|
||||||
|
|
||||||
@ -313,16 +315,15 @@ class BIP68Test(BitcoinTestFramework):
|
|||||||
# diagram above).
|
# diagram above).
|
||||||
# This would cause tx2 to be added back to the mempool, which in turn causes
|
# This would cause tx2 to be added back to the mempool, which in turn causes
|
||||||
# tx3 to be removed.
|
# 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):
|
for i in range(2):
|
||||||
block = create_block(tip, create_coinbase(height), cur_time)
|
block = create_block(tmpl=tmpl, ntime=cur_time)
|
||||||
block.nVersion = 3
|
|
||||||
block.rehash()
|
block.rehash()
|
||||||
block.solve()
|
block.solve()
|
||||||
tip = block.sha256
|
tip = block.sha256
|
||||||
height += 1
|
|
||||||
assert_equal(None if i == 1 else 'inconclusive', self.nodes[0].submitblock(ToHex(block)))
|
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
|
cur_time += 1
|
||||||
|
|
||||||
mempool = self.nodes[0].getrawmempool()
|
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))
|
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
|
# make a block that violates bip68; ensure that the tip updates
|
||||||
tip = int(self.nodes[0].getbestblockhash(), 16)
|
block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
|
||||||
block = create_block(tip, create_coinbase(self.nodes[0].getblockcount()+1), self.mocktime + 600)
|
|
||||||
block.nVersion = 3
|
|
||||||
block.vtx.extend([tx1, tx2, tx3])
|
block.vtx.extend([tx1, tx2, tx3])
|
||||||
block.hashMerkleRoot = block.calc_merkle_root()
|
block.hashMerkleRoot = block.calc_merkle_root()
|
||||||
block.rehash()
|
block.rehash()
|
||||||
|
@ -1273,7 +1273,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||||||
blocks = []
|
blocks = []
|
||||||
spend = out[32]
|
spend = out[32]
|
||||||
for i in range(89, LARGE_REORG_SIZE + 89):
|
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()
|
tx = CTransaction()
|
||||||
script_length = MAX_BLOCK_SIZE - len(b.serialize()) - 69
|
script_length = MAX_BLOCK_SIZE - len(b.serialize()) - 69
|
||||||
script_output = CScript([b'\x00' * script_length])
|
script_output = CScript([b'\x00' * script_length])
|
||||||
@ -1292,18 +1292,18 @@ class FullBlockTest(BitcoinTestFramework):
|
|||||||
self.move_tip(88)
|
self.move_tip(88)
|
||||||
blocks2 = []
|
blocks2 = []
|
||||||
for i in range(89, LARGE_REORG_SIZE + 89):
|
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)
|
self.send_blocks(blocks2, False, force_send=True)
|
||||||
|
|
||||||
# extend alt chain to trigger re-org
|
# 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)
|
self.send_blocks([block], True, timeout=2440)
|
||||||
|
|
||||||
# ... and re-org back to the first chain
|
# ... and re-org back to the first chain
|
||||||
self.move_tip(chain1_tip)
|
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)
|
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.send_blocks([block], True, timeout=2440)
|
||||||
|
|
||||||
self.log.info("Reject a block with an invalid block header version")
|
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.send_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)', reconnect=True)
|
||||||
|
|
||||||
self.move_tip(chain1_tip + 2)
|
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].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1]
|
||||||
b_cb34.vtx[0].rehash()
|
b_cb34.vtx[0].rehash()
|
||||||
b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()
|
b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()
|
||||||
@ -1345,7 +1345,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||||||
tx.rehash()
|
tx.rehash()
|
||||||
return tx
|
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:
|
if self.tip is None:
|
||||||
base_block_hash = self.genesis_hash
|
base_block_hash = self.genesis_hash
|
||||||
block_time = self.mocktime + 1
|
block_time = self.mocktime + 1
|
||||||
|
@ -151,7 +151,6 @@ class BIP68_112_113Test(BitcoinTestFramework):
|
|||||||
# and '-dip3params=2000:2000' to create pre-dip3 blocks only
|
# and '-dip3params=2000:2000' to create pre-dip3 blocks only
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
'-whitelist=noban@127.0.0.1',
|
'-whitelist=noban@127.0.0.1',
|
||||||
'-blockversion=4',
|
|
||||||
'-maxtipage=600100', '-dip3params=2000:2000',
|
'-maxtipage=600100', '-dip3params=2000:2000',
|
||||||
'-par=1', # Use only one script thread to get the exact reject reason for testing
|
'-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
|
# -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("-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[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("-rescan")
|
||||||
self.extra_args[1].append("-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))))
|
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.
|
[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.messages import CTransaction
|
||||||
from test_framework.script import CScript
|
from test_framework.script import CScript
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
@ -37,9 +37,10 @@ def trueDummy(tx):
|
|||||||
class NULLDUMMYTest(BitcoinTestFramework):
|
class NULLDUMMYTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def set_test_params(self):
|
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.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):
|
def skip_test_if_missing_module(self):
|
||||||
self.skip_if_no_wallet()
|
self.skip_if_no_wallet()
|
||||||
@ -54,7 +55,6 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
|||||||
coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
|
coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
|
||||||
self.nodes[0].generate(427) # Block 429
|
self.nodes[0].generate(427) # Block 429
|
||||||
self.lastblockhash = self.nodes[0].getbestblockhash()
|
self.lastblockhash = self.nodes[0].getbestblockhash()
|
||||||
self.tip = int("0x" + self.lastblockhash, 0)
|
|
||||||
self.lastblockheight = 429
|
self.lastblockheight = 429
|
||||||
self.lastblocktime = self.mocktime + 429
|
self.lastblocktime = self.mocktime + 429
|
||||||
|
|
||||||
@ -88,8 +88,10 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
def block_submit(self, node, txs, accept = False):
|
def block_submit(self, node, txs, accept = False):
|
||||||
dip4_activated = self.lastblockheight + 1 >= 432
|
dip4_activated = self.lastblockheight + 1 >= 432
|
||||||
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, dip4_activated=dip4_activated), self.lastblocktime + 1)
|
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
|
||||||
block.nVersion = 4
|
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:
|
for tx in txs:
|
||||||
tx.rehash()
|
tx.rehash()
|
||||||
block.vtx.append(tx)
|
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()))
|
assert_equal(None if accept else 'block-validation-failed', node.submitblock(block.serialize().hex()))
|
||||||
if (accept):
|
if (accept):
|
||||||
assert_equal(node.getbestblockhash(), block.hash)
|
assert_equal(node.getbestblockhash(), block.hash)
|
||||||
self.tip = block.sha256
|
|
||||||
self.lastblockhash = block.hash
|
self.lastblockhash = block.hash
|
||||||
self.lastblocktime += 1
|
self.lastblocktime += 1
|
||||||
self.lastblockheight += 1
|
self.lastblockheight += 1
|
||||||
|
@ -13,6 +13,8 @@ from decimal import Decimal
|
|||||||
|
|
||||||
from test_framework.blocktools import (
|
from test_framework.blocktools import (
|
||||||
create_coinbase,
|
create_coinbase,
|
||||||
|
NORMAL_GBT_REQUEST_PARAMS,
|
||||||
|
TIME_GENESIS_BLOCK,
|
||||||
)
|
)
|
||||||
from test_framework.messages import (
|
from test_framework.messages import (
|
||||||
CBlock,
|
CBlock,
|
||||||
@ -26,6 +28,8 @@ from test_framework.util import (
|
|||||||
assert_raises_rpc_error,
|
assert_raises_rpc_error,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
VERSIONBITS_TOP_BITS = 0x20000000
|
||||||
|
VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
|
||||||
|
|
||||||
def assert_template(node, block, expect, rehash=True):
|
def assert_template(node, block, expect, rehash=True):
|
||||||
if rehash:
|
if rehash:
|
||||||
@ -45,14 +49,23 @@ class MiningTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
def mine_chain(self):
|
def mine_chain(self):
|
||||||
self.log.info('Create some old blocks')
|
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.bump_mocktime(156)
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
mining_info = self.nodes[0].getmininginfo()
|
mining_info = self.nodes[0].getmininginfo()
|
||||||
assert_equal(mining_info['blocks'], 200)
|
assert_equal(mining_info['blocks'], 200)
|
||||||
assert_equal(mining_info['currentblocktx'], 0)
|
assert_equal(mining_info['currentblocktx'], 0)
|
||||||
assert_equal(mining_info['currentblocksize'], 1000)
|
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)
|
self.restart_node(0)
|
||||||
|
# TODO: replace with connect_nodes_bi
|
||||||
self.connect_nodes(0, 1)
|
self.connect_nodes(0, 1)
|
||||||
self.connect_nodes(1, 0)
|
self.connect_nodes(1, 0)
|
||||||
|
|
||||||
@ -78,7 +91,7 @@ class MiningTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Mine a block to leave initial block download
|
# Mine a block to leave initial block download
|
||||||
node.generatetoaddress(1, node.get_deterministic_priv_key().address)
|
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")
|
self.log.info("getblocktemplate: Test capability advertised")
|
||||||
assert 'proposal' in tmpl['capabilities']
|
assert 'proposal' in tmpl['capabilities']
|
||||||
assert 'coinbasetxn' not in tmpl
|
assert 'coinbasetxn' not in tmpl
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import random
|
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.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.p2p import p2p_lock, P2PInterface
|
||||||
from test_framework.script import CScript, OP_TRUE, OP_DROP
|
from test_framework.script import CScript, OP_TRUE, OP_DROP
|
||||||
@ -103,10 +103,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
self.skip_if_no_wallet()
|
self.skip_if_no_wallet()
|
||||||
|
|
||||||
def build_block_on_tip(self, node):
|
def build_block_on_tip(self, node):
|
||||||
height = node.getblockcount()
|
block = create_block(tmpl=node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
|
||||||
tip = node.getbestblockhash()
|
|
||||||
mtp = node.getblockheader(tip)['mediantime']
|
|
||||||
block = create_block(int(tip, 16), create_coinbase(height + 1), mtp + 1)
|
|
||||||
block.solve()
|
block.solve()
|
||||||
return block
|
return block
|
||||||
|
|
||||||
@ -718,6 +715,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
|
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
# Get the nodes out of IBD
|
||||||
|
self.nodes[0].generate(1)
|
||||||
|
|
||||||
# Setup the p2p connections
|
# Setup the p2p connections
|
||||||
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=1))
|
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)
|
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.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
"""Utilities for manipulating blocks and transactions."""
|
"""Utilities for manipulating blocks and transactions."""
|
||||||
|
|
||||||
|
from binascii import a2b_hex
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
import io
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from .messages import (
|
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 transaction outputs can only be spent after this number of new blocks (network rule)
|
||||||
COINBASE_MATURITY = 100
|
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)."""
|
"""Create a block (with regtest difficulty)."""
|
||||||
block = CBlock()
|
block = CBlock()
|
||||||
block.nVersion = version
|
if tmpl is None:
|
||||||
if ntime is None:
|
tmpl = {}
|
||||||
import time
|
block.nVersion = version or tmpl.get('version') or 1
|
||||||
block.nTime = int(time.time() + 600)
|
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:
|
else:
|
||||||
block.nTime = ntime
|
block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams
|
||||||
block.hashPrevBlock = hashprev
|
if coinbase is None:
|
||||||
block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams
|
coinbase = create_coinbase(height=tmpl['height'], dip4_activated=dip4_activated, v20_activated=v20_activated)
|
||||||
block.vtx.append(coinbase)
|
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.hashMerkleRoot = block.calc_merkle_root()
|
||||||
block.calc_sha256()
|
block.calc_sha256()
|
||||||
return block
|
return block
|
||||||
|
Loading…
Reference in New Issue
Block a user