Merge #18267: BIP-325: Signet [consensus]
8258c4c007test: some sanity checks for consensus logic (Anthony Towns)e47ad375bftest: basic signet tests (Karl-Johan Alm)4c189abdc4test: add small signet fuzzer (practicalswift)ec9b25d046test: signet network selection tests (Karl-Johan Alm)3efe298dccsignet: hard-coded parameters for Signet Global Network VI (2020-09-07) (Karl-Johan Alm)c7898bca4eqt: update QT to support signet network (Karl-Johan Alm)a8de47a1c9consensus: add signet validation (Karl-Johan Alm)e8990f1214add signet chain and accompanying parameters (Karl-Johan Alm)404682b7cdadd signet basic support (signet.cpp) (Karl-Johan Alm)a2147d7dadvalidation: move GetWitnessCommitmentIndex to consensus/validation (Karl-Johan Alm) Pull request description: This PR is a part of BIP-325 (https://github.com/bitcoin/bips/blob/master/bip-0325.mediawiki), and is a sub-PR of #16411. * Signet consensus (this) * Signet RPC tools (pending) * Signet utility scripts (contrib/signet) (pending) ACKs for top commit: jonatack: re-ACK8258c4c007per `git diff dbeea65 8258c4c`, only change since last review is updated `-signet*` config option naming. fjahr: re-ACK8258c4claanwj: ACK8258c4c007MarcoFalke: Approach ACK8258c4c007🌵 Tree-SHA512: 5d158add96755910837feafa8214e13695b769a6aec3a2da753cf672618bef377fac43b0f4b772a87b25dd9f0c1c9b29f2789785d7a7d47a155cdcf48f7c975d
This commit is contained in:
21 files changed
+532
-44
No files matched your search
@@ -202,6 +202,7 @@ BITCOIN_CORE_H = \
|
|||||||
script/signingprovider.h \
|
script/signingprovider.h \
|
||||||
script/standard.h \
|
script/standard.h \
|
||||||
shutdown.h \
|
shutdown.h \
|
||||||
|
signet.h \
|
||||||
streams.h \
|
streams.h \
|
||||||
support/allocators/secure.h \
|
support/allocators/secure.h \
|
||||||
support/allocators/zeroafterfree.h \
|
support/allocators/zeroafterfree.h \
|
||||||
@@ -322,6 +323,7 @@ libbitcoin_server_a_SOURCES = \
|
|||||||
rpc/server.cpp \
|
rpc/server.cpp \
|
||||||
script/sigcache.cpp \
|
script/sigcache.cpp \
|
||||||
shutdown.cpp \
|
shutdown.cpp \
|
||||||
|
signet.cpp \
|
||||||
timedata.cpp \
|
timedata.cpp \
|
||||||
torcontrol.cpp \
|
torcontrol.cpp \
|
||||||
txdb.cpp \
|
txdb.cpp \
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ FUZZ_TARGETS = \
|
|||||||
test/fuzz/secp256k1_ecdsa_signature_parse_der_lax \
|
test/fuzz/secp256k1_ecdsa_signature_parse_der_lax \
|
||||||
test/fuzz/service_deserialize \
|
test/fuzz/service_deserialize \
|
||||||
test/fuzz/signature_checker \
|
test/fuzz/signature_checker \
|
||||||
|
test/fuzz/signet \
|
||||||
test/fuzz/snapshotmetadata_deserialize \
|
test/fuzz/snapshotmetadata_deserialize \
|
||||||
test/fuzz/span \
|
test/fuzz/span \
|
||||||
test/fuzz/spanparsing \
|
test/fuzz/spanparsing \
|
||||||
@@ -1129,6 +1130,12 @@ test_fuzz_signature_checker_LDADD = $(FUZZ_SUITE_LD_COMMON)
|
|||||||
test_fuzz_signature_checker_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
|
test_fuzz_signature_checker_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
|
||||||
test_fuzz_signature_checker_SOURCES = test/fuzz/signature_checker.cpp
|
test_fuzz_signature_checker_SOURCES = test/fuzz/signature_checker.cpp
|
||||||
|
|
||||||
|
test_fuzz_signet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||||
|
test_fuzz_signet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
|
test_fuzz_signet_LDADD = $(FUZZ_SUITE_LD_COMMON)
|
||||||
|
test_fuzz_signet_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
test_fuzz_signet_SOURCES = test/fuzz/signet.cpp
|
||||||
|
|
||||||
test_fuzz_snapshotmetadata_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSNAPSHOTMETADATA_DESERIALIZE=1
|
test_fuzz_snapshotmetadata_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSNAPSHOTMETADATA_DESERIALIZE=1
|
||||||
test_fuzz_snapshotmetadata_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
test_fuzz_snapshotmetadata_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
test_fuzz_snapshotmetadata_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
|
test_fuzz_snapshotmetadata_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
|
||||||
|
|||||||
+102
-3
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <chainparamsseeds.h>
|
#include <chainparamsseeds.h>
|
||||||
#include <consensus/merkle.h>
|
#include <consensus/merkle.h>
|
||||||
|
#include <hash.h> // for signet block challenge hash
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
@@ -63,6 +64,8 @@ class CMainParams : public CChainParams {
|
|||||||
public:
|
public:
|
||||||
CMainParams() {
|
CMainParams() {
|
||||||
strNetworkID = CBaseChainParams::MAIN;
|
strNetworkID = CBaseChainParams::MAIN;
|
||||||
|
consensus.signet_blocks = false;
|
||||||
|
consensus.signet_challenge.clear();
|
||||||
consensus.nSubsidyHalvingInterval = 210000;
|
consensus.nSubsidyHalvingInterval = 210000;
|
||||||
consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
|
consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
|
||||||
consensus.BIP34Height = 227931;
|
consensus.BIP34Height = 227931;
|
||||||
@@ -172,6 +175,8 @@ class CTestNetParams : public CChainParams {
|
|||||||
public:
|
public:
|
||||||
CTestNetParams() {
|
CTestNetParams() {
|
||||||
strNetworkID = CBaseChainParams::TESTNET;
|
strNetworkID = CBaseChainParams::TESTNET;
|
||||||
|
consensus.signet_blocks = false;
|
||||||
|
consensus.signet_challenge.clear();
|
||||||
consensus.nSubsidyHalvingInterval = 210000;
|
consensus.nSubsidyHalvingInterval = 210000;
|
||||||
consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
|
consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
|
||||||
consensus.BIP34Height = 21111;
|
consensus.BIP34Height = 21111;
|
||||||
@@ -250,6 +255,95 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signet
|
||||||
|
*/
|
||||||
|
class SigNetParams : public CChainParams {
|
||||||
|
public:
|
||||||
|
explicit SigNetParams(const ArgsManager& args) {
|
||||||
|
std::vector<uint8_t> bin;
|
||||||
|
vSeeds.clear();
|
||||||
|
|
||||||
|
if (!args.IsArgSet("-signetchallenge")) {
|
||||||
|
LogPrintf("Using default signet network\n");
|
||||||
|
bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
|
||||||
|
vSeeds.emplace_back("178.128.221.177");
|
||||||
|
vSeeds.emplace_back("2a01:7c8:d005:390::5");
|
||||||
|
vSeeds.emplace_back("ntv3mtqw5wt63red.onion:38333");
|
||||||
|
} else {
|
||||||
|
const auto signet_challenge = args.GetArgs("-signetchallenge");
|
||||||
|
if (signet_challenge.size() != 1) {
|
||||||
|
throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
|
||||||
|
}
|
||||||
|
bin = ParseHex(signet_challenge[0]);
|
||||||
|
|
||||||
|
LogPrintf("Signet with challenge %s\n", signet_challenge[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.IsArgSet("-signetseednode")) {
|
||||||
|
vSeeds = args.GetArgs("-signetseednode");
|
||||||
|
}
|
||||||
|
|
||||||
|
strNetworkID = CBaseChainParams::SIGNET;
|
||||||
|
consensus.signet_blocks = true;
|
||||||
|
consensus.signet_challenge.assign(bin.begin(), bin.end());
|
||||||
|
consensus.nSubsidyHalvingInterval = 210000;
|
||||||
|
consensus.BIP34Height = 1;
|
||||||
|
consensus.BIP65Height = 1;
|
||||||
|
consensus.BIP66Height = 1;
|
||||||
|
consensus.CSVHeight = 1;
|
||||||
|
consensus.SegwitHeight = 1;
|
||||||
|
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
|
||||||
|
consensus.nPowTargetSpacing = 10 * 60;
|
||||||
|
consensus.fPowAllowMinDifficultyBlocks = false;
|
||||||
|
consensus.fPowNoRetargeting = false;
|
||||||
|
consensus.nRuleChangeActivationThreshold = 1916;
|
||||||
|
consensus.nMinerConfirmationWindow = 2016;
|
||||||
|
consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
|
||||||
|
|
||||||
|
// message start is defined as the first 4 bytes of the sha256d of the block script
|
||||||
|
CHashWriter h(SER_DISK, 0);
|
||||||
|
h << consensus.signet_challenge;
|
||||||
|
uint256 hash = h.GetHash();
|
||||||
|
memcpy(pchMessageStart, hash.begin(), 4);
|
||||||
|
LogPrintf("Signet derived magic (message start): %s\n", HexStr({pchMessageStart, pchMessageStart + 4}));
|
||||||
|
|
||||||
|
nDefaultPort = 38333;
|
||||||
|
nPruneAfterHeight = 1000;
|
||||||
|
m_assumed_blockchain_size = 0;
|
||||||
|
m_assumed_chain_state_size = 0;
|
||||||
|
|
||||||
|
genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN);
|
||||||
|
consensus.hashGenesisBlock = genesis.GetHash();
|
||||||
|
assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"));
|
||||||
|
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
|
||||||
|
|
||||||
|
vFixedSeeds.clear();
|
||||||
|
|
||||||
|
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
|
||||||
|
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
|
||||||
|
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
|
||||||
|
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
|
||||||
|
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
|
||||||
|
|
||||||
|
bech32_hrp = "tb";
|
||||||
|
|
||||||
|
fDefaultConsistencyChecks = false;
|
||||||
|
fRequireStandard = true;
|
||||||
|
m_is_test_chain = true;
|
||||||
|
m_is_mockable_chain = false;
|
||||||
|
|
||||||
|
chainTxData = ChainTxData{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regression test
|
* Regression test
|
||||||
*/
|
*/
|
||||||
@@ -257,6 +351,8 @@ class CRegTestParams : public CChainParams {
|
|||||||
public:
|
public:
|
||||||
explicit CRegTestParams(const ArgsManager& args) {
|
explicit CRegTestParams(const ArgsManager& args) {
|
||||||
strNetworkID = CBaseChainParams::REGTEST;
|
strNetworkID = CBaseChainParams::REGTEST;
|
||||||
|
consensus.signet_blocks = false;
|
||||||
|
consensus.signet_challenge.clear();
|
||||||
consensus.nSubsidyHalvingInterval = 150;
|
consensus.nSubsidyHalvingInterval = 150;
|
||||||
consensus.BIP16Exception = uint256();
|
consensus.BIP16Exception = uint256();
|
||||||
consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
|
consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
|
||||||
@@ -391,12 +487,15 @@ const CChainParams &Params() {
|
|||||||
|
|
||||||
std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain)
|
std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain)
|
||||||
{
|
{
|
||||||
if (chain == CBaseChainParams::MAIN)
|
if (chain == CBaseChainParams::MAIN) {
|
||||||
return std::unique_ptr<CChainParams>(new CMainParams());
|
return std::unique_ptr<CChainParams>(new CMainParams());
|
||||||
else if (chain == CBaseChainParams::TESTNET)
|
} else if (chain == CBaseChainParams::TESTNET) {
|
||||||
return std::unique_ptr<CChainParams>(new CTestNetParams());
|
return std::unique_ptr<CChainParams>(new CTestNetParams());
|
||||||
else if (chain == CBaseChainParams::REGTEST)
|
} else if (chain == CBaseChainParams::SIGNET) {
|
||||||
|
return std::unique_ptr<CChainParams>(new SigNetParams(gArgs));
|
||||||
|
} else if (chain == CBaseChainParams::REGTEST) {
|
||||||
return std::unique_ptr<CChainParams>(new CRegTestParams(gArgs));
|
return std::unique_ptr<CChainParams>(new CRegTestParams(gArgs));
|
||||||
|
}
|
||||||
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
const std::string CBaseChainParams::MAIN = "main";
|
const std::string CBaseChainParams::MAIN = "main";
|
||||||
const std::string CBaseChainParams::TESTNET = "test";
|
const std::string CBaseChainParams::TESTNET = "test";
|
||||||
|
const std::string CBaseChainParams::SIGNET = "signet";
|
||||||
const std::string CBaseChainParams::REGTEST = "regtest";
|
const std::string CBaseChainParams::REGTEST = "regtest";
|
||||||
|
|
||||||
void SetupChainParamsBaseOptions(ArgsManager& argsman)
|
void SetupChainParamsBaseOptions(ArgsManager& argsman)
|
||||||
@@ -23,6 +24,9 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
|
|||||||
argsman.AddArg("-segwitheight=<n>", "Set the activation height of segwit. -1 to disable. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-segwitheight=<n>", "Set the activation height of segwit. -1 to disable. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
||||||
|
argsman.AddArg("-signet", "Use the signet chain. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||||
|
argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS);
|
||||||
|
argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
|
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
|
||||||
@@ -35,14 +39,16 @@ const CBaseChainParams& BaseParams()
|
|||||||
|
|
||||||
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
|
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
|
||||||
{
|
{
|
||||||
if (chain == CBaseChainParams::MAIN)
|
if (chain == CBaseChainParams::MAIN) {
|
||||||
return MakeUnique<CBaseChainParams>("", 8332);
|
return MakeUnique<CBaseChainParams>("", 8332);
|
||||||
else if (chain == CBaseChainParams::TESTNET)
|
} else if (chain == CBaseChainParams::TESTNET) {
|
||||||
return MakeUnique<CBaseChainParams>("testnet3", 18332);
|
return MakeUnique<CBaseChainParams>("testnet3", 18332);
|
||||||
else if (chain == CBaseChainParams::REGTEST)
|
} else if (chain == CBaseChainParams::SIGNET) {
|
||||||
|
return MakeUnique<CBaseChainParams>("signet", 38332);
|
||||||
|
} else if (chain == CBaseChainParams::REGTEST) {
|
||||||
return MakeUnique<CBaseChainParams>("regtest", 18443);
|
return MakeUnique<CBaseChainParams>("regtest", 18443);
|
||||||
else
|
}
|
||||||
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectBaseParams(const std::string& chain)
|
void SelectBaseParams(const std::string& chain)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public:
|
|||||||
/** Chain name strings */
|
/** Chain name strings */
|
||||||
static const std::string MAIN;
|
static const std::string MAIN;
|
||||||
static const std::string TESTNET;
|
static const std::string TESTNET;
|
||||||
|
static const std::string SIGNET;
|
||||||
static const std::string REGTEST;
|
static const std::string REGTEST;
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,13 @@ struct Params {
|
|||||||
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
|
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
|
||||||
uint256 nMinimumChainWork;
|
uint256 nMinimumChainWork;
|
||||||
uint256 defaultAssumeValid;
|
uint256 defaultAssumeValid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, witness commitments contain a payload equal to a Bitcoin Script solution
|
||||||
|
* to the signet challenge. See BIP325.
|
||||||
|
*/
|
||||||
|
bool signet_blocks{false};
|
||||||
|
std::vector<uint8_t> signet_challenge;
|
||||||
};
|
};
|
||||||
} // namespace Consensus
|
} // namespace Consensus
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
|
|
||||||
|
/** Index marker for when no witness commitment is present in a coinbase transaction. */
|
||||||
|
static constexpr int NO_WITNESS_COMMITMENT{-1};
|
||||||
|
|
||||||
|
/** Minimum size of a witness commitment structure. Defined in BIP 141. **/
|
||||||
|
static constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};
|
||||||
|
|
||||||
/** A "reason" why a transaction was invalid, suitable for determining whether the
|
/** A "reason" why a transaction was invalid, suitable for determining whether the
|
||||||
* provider of the transaction should be banned/ignored/disconnected/etc.
|
* provider of the transaction should be banned/ignored/disconnected/etc.
|
||||||
*/
|
*/
|
||||||
@@ -151,4 +157,25 @@ static inline int64_t GetTransactionInputWeight(const CTxIn& txin)
|
|||||||
return ::GetSerializeSize(txin, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, PROTOCOL_VERSION);
|
return ::GetSerializeSize(txin, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, PROTOCOL_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compute at which vout of the block's coinbase transaction the witness commitment occurs, or -1 if not found */
|
||||||
|
inline int GetWitnessCommitmentIndex(const CBlock& block)
|
||||||
|
{
|
||||||
|
int commitpos = NO_WITNESS_COMMITMENT;
|
||||||
|
if (!block.vtx.empty()) {
|
||||||
|
for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
|
||||||
|
const CTxOut& vout = block.vtx[0]->vout[o];
|
||||||
|
if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&
|
||||||
|
vout.scriptPubKey[0] == OP_RETURN &&
|
||||||
|
vout.scriptPubKey[1] == 0x24 &&
|
||||||
|
vout.scriptPubKey[2] == 0xaa &&
|
||||||
|
vout.scriptPubKey[3] == 0x21 &&
|
||||||
|
vout.scriptPubKey[4] == 0xa9 &&
|
||||||
|
vout.scriptPubKey[5] == 0xed) {
|
||||||
|
commitpos = o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commitpos;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // BITCOIN_CONSENSUS_VALIDATION_H
|
#endif // BITCOIN_CONSENSUS_VALIDATION_H
|
||||||
@@ -46,6 +46,7 @@ static const int TOOLTIP_WRAP_THRESHOLD = 80;
|
|||||||
#define QAPP_ORG_DOMAIN "bitcoin.org"
|
#define QAPP_ORG_DOMAIN "bitcoin.org"
|
||||||
#define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt"
|
#define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt"
|
||||||
#define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet"
|
#define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet"
|
||||||
|
#define QAPP_APP_NAME_SIGNET "Bitcoin-Qt-signet"
|
||||||
#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest"
|
#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest"
|
||||||
|
|
||||||
/* One gigabyte (GB) in bytes */
|
/* One gigabyte (GB) in bytes */
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ static const struct {
|
|||||||
} network_styles[] = {
|
} network_styles[] = {
|
||||||
{"main", QAPP_APP_NAME_DEFAULT, 0, 0},
|
{"main", QAPP_APP_NAME_DEFAULT, 0, 0},
|
||||||
{"test", QAPP_APP_NAME_TESTNET, 70, 30},
|
{"test", QAPP_APP_NAME_TESTNET, 70, 30},
|
||||||
{"regtest", QAPP_APP_NAME_REGTEST, 160, 30}
|
{"signet", QAPP_APP_NAME_SIGNET, 35, 15},
|
||||||
|
{"regtest", QAPP_APP_NAME_REGTEST, 160, 30},
|
||||||
};
|
};
|
||||||
static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
|
static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
|
||||||
|
|
||||||
|
|||||||
+149
@@ -0,0 +1,149 @@
|
|||||||
|
// Copyright (c) 2019-2020 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <signet.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <consensus/merkle.h>
|
||||||
|
#include <consensus/params.h>
|
||||||
|
#include <consensus/validation.h>
|
||||||
|
#include <core_io.h>
|
||||||
|
#include <hash.h>
|
||||||
|
#include <primitives/block.h>
|
||||||
|
#include <primitives/transaction.h>
|
||||||
|
#include <span.h>
|
||||||
|
#include <script/interpreter.h>
|
||||||
|
#include <script/standard.h>
|
||||||
|
#include <streams.h>
|
||||||
|
#include <util/strencodings.h>
|
||||||
|
#include <util/system.h>
|
||||||
|
#include <uint256.h>
|
||||||
|
|
||||||
|
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
|
||||||
|
|
||||||
|
static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
|
||||||
|
|
||||||
|
static bool FetchAndClearCommitmentSection(const Span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
|
||||||
|
{
|
||||||
|
CScript replacement;
|
||||||
|
bool found_header = false;
|
||||||
|
result.clear();
|
||||||
|
|
||||||
|
opcodetype opcode;
|
||||||
|
CScript::const_iterator pc = witness_commitment.begin();
|
||||||
|
std::vector<uint8_t> pushdata;
|
||||||
|
while (witness_commitment.GetOp(pc, opcode, pushdata)) {
|
||||||
|
if (pushdata.size() > 0) {
|
||||||
|
if (!found_header && pushdata.size() > (size_t) header.size() && Span<const uint8_t>(pushdata.data(), header.size()) == header) {
|
||||||
|
// pushdata only counts if it has the header _and_ some data
|
||||||
|
result.insert(result.end(), pushdata.begin() + header.size(), pushdata.end());
|
||||||
|
pushdata.erase(pushdata.begin() + header.size(), pushdata.end());
|
||||||
|
found_header = true;
|
||||||
|
}
|
||||||
|
replacement << pushdata;
|
||||||
|
} else {
|
||||||
|
replacement << opcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_header) witness_commitment = replacement;
|
||||||
|
return found_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CBlock& block)
|
||||||
|
{
|
||||||
|
std::vector<uint256> leaves;
|
||||||
|
leaves.resize(block.vtx.size());
|
||||||
|
leaves[0] = cb.GetHash();
|
||||||
|
for (size_t s = 1; s < block.vtx.size(); ++s) {
|
||||||
|
leaves[s] = block.vtx[s]->GetHash();
|
||||||
|
}
|
||||||
|
return ComputeMerkleRoot(std::move(leaves));
|
||||||
|
}
|
||||||
|
|
||||||
|
SignetTxs SignetTxs::Create(const CBlock& block, const CScript& challenge)
|
||||||
|
{
|
||||||
|
CMutableTransaction tx_to_spend;
|
||||||
|
tx_to_spend.nVersion = 0;
|
||||||
|
tx_to_spend.nLockTime = 0;
|
||||||
|
tx_to_spend.vin.emplace_back(COutPoint(), CScript(OP_0), 0);
|
||||||
|
tx_to_spend.vout.emplace_back(0, challenge);
|
||||||
|
|
||||||
|
CMutableTransaction tx_spending;
|
||||||
|
tx_spending.nVersion = 0;
|
||||||
|
tx_spending.nLockTime = 0;
|
||||||
|
tx_spending.vin.emplace_back(COutPoint(), CScript(), 0);
|
||||||
|
tx_spending.vout.emplace_back(0, CScript(OP_RETURN));
|
||||||
|
|
||||||
|
// can't fill any other fields before extracting signet
|
||||||
|
// responses from block coinbase tx
|
||||||
|
|
||||||
|
// find and delete signet signature
|
||||||
|
if (block.vtx.empty()) return invalid(); // no coinbase tx in block; invalid
|
||||||
|
CMutableTransaction modified_cb(*block.vtx.at(0));
|
||||||
|
|
||||||
|
const int cidx = GetWitnessCommitmentIndex(block);
|
||||||
|
if (cidx == NO_WITNESS_COMMITMENT) {
|
||||||
|
return invalid(); // require a witness commitment
|
||||||
|
}
|
||||||
|
|
||||||
|
CScript& witness_commitment = modified_cb.vout.at(cidx).scriptPubKey;
|
||||||
|
|
||||||
|
std::vector<uint8_t> signet_solution;
|
||||||
|
if (!FetchAndClearCommitmentSection(SIGNET_HEADER, witness_commitment, signet_solution)) {
|
||||||
|
// no signet solution -- allow this to support OP_TRUE as trivial block challenge
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0);
|
||||||
|
v >> tx_spending.vin[0].scriptSig;
|
||||||
|
v >> tx_spending.vin[0].scriptWitness.stack;
|
||||||
|
if (!v.empty()) return invalid(); // extraneous data encountered
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
return invalid(); // parsing error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint256 signet_merkle = ComputeModifiedMerkleRoot(modified_cb, block);
|
||||||
|
|
||||||
|
std::vector<uint8_t> block_data;
|
||||||
|
CVectorWriter writer(SER_NETWORK, INIT_PROTO_VERSION, block_data, 0);
|
||||||
|
writer << block.nVersion;
|
||||||
|
writer << block.hashPrevBlock;
|
||||||
|
writer << signet_merkle;
|
||||||
|
writer << block.nTime;
|
||||||
|
tx_to_spend.vin[0].scriptSig << block_data;
|
||||||
|
tx_spending.vin[0].prevout = COutPoint(tx_to_spend.GetHash(), 0);
|
||||||
|
|
||||||
|
return {tx_to_spend, tx_spending};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signet block solution checker
|
||||||
|
bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& consensusParams)
|
||||||
|
{
|
||||||
|
if (block.GetHash() == consensusParams.hashGenesisBlock) {
|
||||||
|
// genesis block solution is always valid
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CScript challenge(consensusParams.signet_challenge.begin(), consensusParams.signet_challenge.end());
|
||||||
|
const SignetTxs signet_txs(block, challenge);
|
||||||
|
|
||||||
|
if (!signet_txs.m_valid) {
|
||||||
|
LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution parse failure)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CScript& scriptSig = signet_txs.m_to_sign.vin[0].scriptSig;
|
||||||
|
const CScriptWitness& witness = signet_txs.m_to_sign.vin[0].scriptWitness;
|
||||||
|
|
||||||
|
TransactionSignatureChecker sigcheck(&signet_txs.m_to_sign, /*nIn=*/ 0, /*amount=*/ signet_txs.m_to_spend.vout[0].nValue);
|
||||||
|
|
||||||
|
if (!VerifyScript(scriptSig, signet_txs.m_to_spend.vout[0].scriptPubKey, &witness, BLOCK_SCRIPT_VERIFY_FLAGS, sigcheck)) {
|
||||||
|
LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution invalid)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) 2019-2020 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_SIGNET_H
|
||||||
|
#define BITCOIN_SIGNET_H
|
||||||
|
|
||||||
|
#include <consensus/params.h>
|
||||||
|
#include <primitives/block.h>
|
||||||
|
#include <primitives/transaction.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract signature and check whether a block has a valid solution
|
||||||
|
*/
|
||||||
|
bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the signet tx corresponding to the given block
|
||||||
|
*
|
||||||
|
* The signet tx commits to everything in the block except:
|
||||||
|
* 1. It hashes a modified merkle root with the signet signature removed.
|
||||||
|
* 2. It skips the nonce.
|
||||||
|
*/
|
||||||
|
class SignetTxs {
|
||||||
|
private:
|
||||||
|
struct invalid {};
|
||||||
|
SignetTxs(invalid i) : m_to_spend(), m_to_sign(), m_valid(false) { }
|
||||||
|
|
||||||
|
template<class T1, class T2>
|
||||||
|
SignetTxs(const T1& to_spend, const T2& to_sign) : m_to_spend{to_spend}, m_to_sign{to_sign}, m_valid(true) { }
|
||||||
|
|
||||||
|
static SignetTxs Create(const CBlock& block, const CScript& challenge);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SignetTxs(const CBlock& block, const CScript& challenge) : SignetTxs(Create(block, challenge)) { }
|
||||||
|
|
||||||
|
const CTransaction m_to_spend;
|
||||||
|
const CTransaction m_to_sign;
|
||||||
|
const bool m_valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BITCOIN_SIGNET_H
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2020 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <chainparams.h>
|
||||||
|
#include <consensus/validation.h>
|
||||||
|
#include <primitives/block.h>
|
||||||
|
#include <signet.h>
|
||||||
|
#include <streams.h>
|
||||||
|
#include <test/fuzz/fuzz.h>
|
||||||
|
#include <test/fuzz/FuzzedDataProvider.h>
|
||||||
|
#include <test/fuzz/util.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
void initialize()
|
||||||
|
{
|
||||||
|
InitializeFuzzingContext(CBaseChainParams::SIGNET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_one_input(const std::vector<uint8_t>& buffer)
|
||||||
|
{
|
||||||
|
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||||
|
const std::optional<CBlock> block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
|
||||||
|
if (!block) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(void)CheckSignetBlockSolution(*block, Params().GetConsensus());
|
||||||
|
if (GetWitnessCommitmentIndex(*block) != NO_WITNESS_COMMITMENT) {
|
||||||
|
(void)SignetTxs(*block, ConsumeScript(fuzzed_data_provider));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(key_io_invalid)
|
|||||||
std::string exp_base58string = test[0].get_str();
|
std::string exp_base58string = test[0].get_str();
|
||||||
|
|
||||||
// must be invalid as public and as private key
|
// must be invalid as public and as private key
|
||||||
for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST }) {
|
for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST }) {
|
||||||
SelectParams(chain);
|
SelectParams(chain);
|
||||||
destination = DecodeDestination(exp_base58string);
|
destination = DecodeDestination(exp_base58string);
|
||||||
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
|
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
|
||||||
|
|||||||
@@ -135,4 +135,51 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sanity_check_chainparams(std::string chainName)
|
||||||
|
{
|
||||||
|
const auto chainParams = CreateChainParams(chainName);
|
||||||
|
const auto consensus = chainParams->GetConsensus();
|
||||||
|
|
||||||
|
// hash genesis is correct
|
||||||
|
BOOST_CHECK_EQUAL(consensus.hashGenesisBlock, chainParams->GenesisBlock().GetHash());
|
||||||
|
|
||||||
|
// target timespan is an even multiple of spacing
|
||||||
|
BOOST_CHECK_EQUAL(consensus.nPowTargetTimespan % consensus.nPowTargetSpacing, 0);
|
||||||
|
|
||||||
|
// genesis nBits is positive, doesn't overflow and is lower than powLimit
|
||||||
|
arith_uint256 pow_compact;
|
||||||
|
bool neg, over;
|
||||||
|
pow_compact.SetCompact(chainParams->GenesisBlock().nBits, &neg, &over);
|
||||||
|
BOOST_CHECK(!neg && pow_compact != 0);
|
||||||
|
BOOST_CHECK(!over);
|
||||||
|
BOOST_CHECK(UintToArith256(consensus.powLimit) >= pow_compact);
|
||||||
|
|
||||||
|
// check max target * 4*nPowTargetTimespan doesn't overflow -- see pow.cpp:CalculateNextWorkRequired()
|
||||||
|
if (!consensus.fPowNoRetargeting) {
|
||||||
|
arith_uint256 targ_max("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
|
||||||
|
targ_max /= consensus.nPowTargetTimespan*4;
|
||||||
|
BOOST_CHECK(UintToArith256(consensus.powLimit) < targ_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(ChainParams_MAIN_sanity)
|
||||||
|
{
|
||||||
|
sanity_check_chainparams(CBaseChainParams::MAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(ChainParams_REGTEST_sanity)
|
||||||
|
{
|
||||||
|
sanity_check_chainparams(CBaseChainParams::REGTEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(ChainParams_TESTNET_sanity)
|
||||||
|
{
|
||||||
|
sanity_check_chainparams(CBaseChainParams::TESTNET);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity)
|
||||||
|
{
|
||||||
|
sanity_check_chainparams(CBaseChainParams::SIGNET);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
@@ -848,8 +848,8 @@ struct ArgsMergeTestingSetup : public BasicTestingSetup {
|
|||||||
ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
|
ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
|
||||||
for (bool soft_set : {false, true}) {
|
for (bool soft_set : {false, true}) {
|
||||||
for (bool force_set : {false, true}) {
|
for (bool force_set : {false, true}) {
|
||||||
for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
|
for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
|
||||||
for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
|
for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
|
||||||
for (bool net_specific : {false, true}) {
|
for (bool net_specific : {false, true}) {
|
||||||
fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
|
fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
|
||||||
}
|
}
|
||||||
@@ -1003,7 +1003,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
|
|||||||
// Results file is formatted like:
|
// Results file is formatted like:
|
||||||
//
|
//
|
||||||
// <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
|
// <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
|
||||||
BOOST_CHECK_EQUAL(out_sha_hex, "8fd4877bb8bf337badca950ede6c917441901962f160e52514e06a60dea46cde");
|
BOOST_CHECK_EQUAL(out_sha_hex, "d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar test as above, but for ArgsManager::GetChainName function.
|
// Similar test as above, but for ArgsManager::GetChainName function.
|
||||||
@@ -1106,7 +1106,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
|
|||||||
// Results file is formatted like:
|
// Results file is formatted like:
|
||||||
//
|
//
|
||||||
// <input> || <output>
|
// <input> || <output>
|
||||||
BOOST_CHECK_EQUAL(out_sha_hex, "f0b3a3c29869edc765d579c928f7f1690a71fbb673b49ccf39cbc4de18156a0d");
|
BOOST_CHECK_EQUAL(out_sha_hex, "f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
|
BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
|
||||||
|
|||||||
+8
-2
@@ -263,6 +263,7 @@ const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
|
|||||||
// Section names to be recognized in the config file.
|
// Section names to be recognized in the config file.
|
||||||
static const std::set<std::string> available_sections{
|
static const std::set<std::string> available_sections{
|
||||||
CBaseChainParams::REGTEST,
|
CBaseChainParams::REGTEST,
|
||||||
|
CBaseChainParams::SIGNET,
|
||||||
CBaseChainParams::TESTNET,
|
CBaseChainParams::TESTNET,
|
||||||
CBaseChainParams::MAIN
|
CBaseChainParams::MAIN
|
||||||
};
|
};
|
||||||
@@ -916,16 +917,21 @@ std::string ArgsManager::GetChainName() const
|
|||||||
};
|
};
|
||||||
|
|
||||||
const bool fRegTest = get_net("-regtest");
|
const bool fRegTest = get_net("-regtest");
|
||||||
|
const bool fSigNet = get_net("-signet");
|
||||||
const bool fTestNet = get_net("-testnet");
|
const bool fTestNet = get_net("-testnet");
|
||||||
const bool is_chain_arg_set = IsArgSet("-chain");
|
const bool is_chain_arg_set = IsArgSet("-chain");
|
||||||
|
|
||||||
if ((int)is_chain_arg_set + (int)fRegTest + (int)fTestNet > 1) {
|
if ((int)is_chain_arg_set + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
|
||||||
throw std::runtime_error("Invalid combination of -regtest, -testnet and -chain. Can use at most one.");
|
throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one.");
|
||||||
}
|
}
|
||||||
if (fRegTest)
|
if (fRegTest)
|
||||||
return CBaseChainParams::REGTEST;
|
return CBaseChainParams::REGTEST;
|
||||||
|
if (fSigNet) {
|
||||||
|
return CBaseChainParams::SIGNET;
|
||||||
|
}
|
||||||
if (fTestNet)
|
if (fTestNet)
|
||||||
return CBaseChainParams::TESTNET;
|
return CBaseChainParams::TESTNET;
|
||||||
|
|
||||||
return GetArg("-chain", CBaseChainParams::MAIN);
|
return GetArg("-chain", CBaseChainParams::MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-23
@@ -33,6 +33,7 @@
|
|||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
#include <shutdown.h>
|
#include <shutdown.h>
|
||||||
|
#include <signet.h>
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <txdb.h>
|
#include <txdb.h>
|
||||||
@@ -1169,6 +1170,11 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
|
|||||||
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
|
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
|
||||||
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
|
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
|
||||||
|
|
||||||
|
// Signet only: check block solution
|
||||||
|
if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) {
|
||||||
|
return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3346,6 +3352,11 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
|
|||||||
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
|
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Signet only: check block solution
|
||||||
|
if (consensusParams.signet_blocks && fCheckPOW && !CheckSignetBlockSolution(block, consensusParams)) {
|
||||||
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-signet-blksig", "signet block signature validation failure");
|
||||||
|
}
|
||||||
|
|
||||||
// Check the merkle root.
|
// Check the merkle root.
|
||||||
if (fCheckMerkleRoot) {
|
if (fCheckMerkleRoot) {
|
||||||
bool mutated;
|
bool mutated;
|
||||||
@@ -3409,31 +3420,11 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
|
|||||||
return (height >= params.SegwitHeight);
|
return (height >= params.SegwitHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetWitnessCommitmentIndex(const CBlock& block)
|
|
||||||
{
|
|
||||||
int commitpos = -1;
|
|
||||||
if (!block.vtx.empty()) {
|
|
||||||
for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
|
|
||||||
const CTxOut& vout = block.vtx[0]->vout[o];
|
|
||||||
if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&
|
|
||||||
vout.scriptPubKey[0] == OP_RETURN &&
|
|
||||||
vout.scriptPubKey[1] == 0x24 &&
|
|
||||||
vout.scriptPubKey[2] == 0xaa &&
|
|
||||||
vout.scriptPubKey[3] == 0x21 &&
|
|
||||||
vout.scriptPubKey[4] == 0xa9 &&
|
|
||||||
vout.scriptPubKey[5] == 0xed) {
|
|
||||||
commitpos = o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commitpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
|
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
|
||||||
{
|
{
|
||||||
int commitpos = GetWitnessCommitmentIndex(block);
|
int commitpos = GetWitnessCommitmentIndex(block);
|
||||||
static const std::vector<unsigned char> nonce(32, 0x00);
|
static const std::vector<unsigned char> nonce(32, 0x00);
|
||||||
if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
|
if (commitpos != NO_WITNESS_COMMITMENT && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
|
||||||
CMutableTransaction tx(*block.vtx[0]);
|
CMutableTransaction tx(*block.vtx[0]);
|
||||||
tx.vin[0].scriptWitness.stack.resize(1);
|
tx.vin[0].scriptWitness.stack.resize(1);
|
||||||
tx.vin[0].scriptWitness.stack[0] = nonce;
|
tx.vin[0].scriptWitness.stack[0] = nonce;
|
||||||
@@ -3447,7 +3438,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
|
|||||||
int commitpos = GetWitnessCommitmentIndex(block);
|
int commitpos = GetWitnessCommitmentIndex(block);
|
||||||
std::vector<unsigned char> ret(32, 0x00);
|
std::vector<unsigned char> ret(32, 0x00);
|
||||||
if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
|
if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
|
||||||
if (commitpos == -1) {
|
if (commitpos == NO_WITNESS_COMMITMENT) {
|
||||||
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
|
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
|
||||||
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
|
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
|
||||||
CTxOut out;
|
CTxOut out;
|
||||||
@@ -3585,7 +3576,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
|
|||||||
bool fHaveWitness = false;
|
bool fHaveWitness = false;
|
||||||
if (nHeight >= consensusParams.SegwitHeight) {
|
if (nHeight >= consensusParams.SegwitHeight) {
|
||||||
int commitpos = GetWitnessCommitmentIndex(block);
|
int commitpos = GetWitnessCommitmentIndex(block);
|
||||||
if (commitpos != -1) {
|
if (commitpos != NO_WITNESS_COMMITMENT) {
|
||||||
bool malleated = false;
|
bool malleated = false;
|
||||||
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
|
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
|
||||||
// The malleation check is ignored; as the transaction tree itself
|
// The malleation check is ignored; as the transaction tree itself
|
||||||
|
|||||||
@@ -93,8 +93,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
|
|||||||
// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB
|
// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB
|
||||||
// Setting the target to >= 550 MiB will make it likely we can respect the target.
|
// Setting the target to >= 550 MiB will make it likely we can respect the target.
|
||||||
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
|
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
|
||||||
/** Minimum size of a witness commitment structure. Defined in BIP 141. **/
|
|
||||||
static constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};
|
|
||||||
|
|
||||||
struct BlockHasher
|
struct BlockHasher
|
||||||
{
|
{
|
||||||
@@ -306,9 +304,6 @@ bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainpar
|
|||||||
* Note that transaction witness validation rules are always enforced when P2SH is enforced. */
|
* Note that transaction witness validation rules are always enforced when P2SH is enforced. */
|
||||||
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
|
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
|
||||||
|
|
||||||
/** Compute at which vout of the block's coinbase transaction the witness commitment occurs, or -1 if not found */
|
|
||||||
int GetWitnessCommitmentIndex(const CBlock& block);
|
|
||||||
|
|
||||||
/** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */
|
/** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */
|
||||||
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
|
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
|
|||||||
Executable
+71
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2019-2020 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
"""Test basic signet functionality"""
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import assert_equal
|
||||||
|
|
||||||
|
signet_blocks = [
|
||||||
|
'00000020f61eee3b63a380a477a063af32b2bbc97c9ff9f01f2c4225e973988108000000f575c83235984e7dc4afc1f30944c170462e84437ab6f2d52e16878a79e4678bd1914d5fae77031eccf4070001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025151feffffff0200f2052a010000001600149243f727dd5343293eb83174324019ec16c2630f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205e423a8754336ca99dbe16509b877ef1bf98d008836c725005b3c787c41ebe46022047246e4467ad7cc7f1ad98662afcaf14c115e0095a227c7b05c5182591c23e7e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'00000020533b53ded9bff4adc94101d32400a144c54edc5ed492a3b26c63b2d686000000b38fef50592017cfafbcab88eb3d9cf50b2c801711cad8299495d26df5e54812e7914d5fae77031ecfdd0b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025251feffffff0200f2052a01000000160014fd09839740f0e0b4fc6d5e2527e4022aa9b89dfa0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022031d64a1692cdad1fc0ced69838169fe19ae01be524d831b95fcf5ea4e6541c3c02204f9dea0801df8b4d0cd0857c62ab35c6c25cc47c930630dc7fe723531daa3e9b01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'000000202960f3752f0bfa8858a3e333294aedc7808025e868c9dc03e71d88bb320000007765fcd3d5b4966beb338bba2675dc2cf2ad28d4ad1d83bdb6f286e7e27ac1f807924d5fae77031e81d60b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025351feffffff0200f2052a010000001600141e5fb426042692ae0e87c070e78c39307a5661c20000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205de93694763a42954865bcf1540cb82958bc62d0ec4eee02070fb7937cd037f4022067f333753bce47b10bc25eb6e1f311482e994c862a7e0b2d41ab1c8679fd1b1101000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'00000020b06443a13ae1d3d50faef5ecad38c6818194dc46abca3e972e2aacdae800000069a5829097e80fee00ac49a56ea9f82d741a6af84d32b3bc455cf31871e2a8ac27924d5fae77031e9c91050001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025451feffffff0200f2052a0100000016001430db2f8225dcf7751361ab38735de08190318cb70000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402200936f5f9872f6df5dd242026ad52241a68423f7f682e79169a8d85a374eab9b802202cd2979c48b321b3453e65e8f92460db3fca93cbea8539b450c959f4fbe630c601000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'000000207ed403758a4f228a1939418a155e2ebd4ae6b26e5ffd0ae433123f7694010000542e80b609c5bc58af5bdf492e26d4f60cd43a3966c2e063c50444c29b3757a636924d5fae77031ee8601d0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025551feffffff0200f2052a01000000160014edc207e014df34fa3885dff97d1129d356e1186a0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022021a3656609f85a66a2c5672ed9322c2158d57251040d2716ed202a1fe14f0c12022057d68bc6611f7a9424a7e00bbf3e27e6ae6b096f60bac624a094bc97a59aa1ff01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'000000205bea0a88d1422c3df08d766ad72df95084d0700e6f873b75dd4e986c7703000002b57516d33ed60c2bdd9f93d6d5614083324c837e68e5ba6e04287a7285633585924d5fae77031ed171960001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025651feffffff0200f2052a010000001600143ae612599cf96f2442ce572633e0251116eaa52f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022059a7c54de76bfdbb1dd44c78ea2dbd2bb4e97f4abad38965f41e76433e56423c022054bf17f04fe17415c0141f60eebd2b839200f574d8ad8d55a0917b92b0eb913401000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'00000020daf3b60d374b19476461f97540498dcfa2eb7016238ec6b1d022f82fb60100007a7ae65b53cb988c2ec92d2384996713821d5645ffe61c9acea60da75cd5edfa1a944d5fae77031e9dbb050001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025751feffffff0200f2052a01000000160014ef2dceae02e35f8137de76768ae3345d99ca68860000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402202b3f946d6447f9bf17d00f3696cede7ee70b785495e5498274ee682a493befd5022045fc0bcf9332243168b5d35507175f9f374a8eba2336873885d12aada67ea5f601000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'00000020457cc5f3c2e1a5655bc20e20e48d33e1b7ea68786c614032b5c518f0b6000000541f36942d82c6e7248275ff15c8933487fbe1819c67a9ecc0f4b70bb7e6cf672a944d5fae77031e8f39860001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025851feffffff0200f2052a0100000016001472a27906947c06d034b38ba2fa13c6391a4832790000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402202d62805ce60cbd60591f97f949b5ea5bd7e2307bcde343e6ea8394da92758e72022053a25370b0aa20da100189b7899a8f8675a0fdc60e38ece6b8a4f98edd94569e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'00000020a2eb61eb4f3831baa3a3363e1b42db4462663f756f07423e81ed30322102000077224de7dea0f8d0ec22b1d2e2e255f0a987b96fe7200e1a2e6373f48a2f5b7894954d5fae77031e36867e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025951feffffff0200f2052a01000000160014aa0ad9f26801258382e0734dceec03a4a75f60240000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402206fa0d59990eed369bd7375767c9a6c9369fae209152b8674e520da270605528c0220749eed3b12dbe3f583f505d21803e4aef59c8e24c5831951eafa4f15a8f92c4e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'00000020a868e8514be5e46dabd6a122132f423f36a43b716a40c394e2a8d063e1010000f4c6c717e99d800c699c25a2006a75a0c5c09f432a936f385e6fce139cdbd1a5e9964d5fae77031e7d026e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025a51feffffff0200f2052a01000000160014aaa671c82b138e3b8f510cd801e5f2bd0aa305940000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022042309f4c3c7a1a2ac8c24f890f962df1c0086cec10be0868087cfc427520cb2702201dafee8911c269b7e786e242045bb57cef3f5b0f177010c6159abae42f646cc501000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
]
|
||||||
|
|
||||||
|
class SignetBasicTest(BitcoinTestFramework):
|
||||||
|
def set_test_params(self):
|
||||||
|
self.chain = "signet"
|
||||||
|
self.num_nodes = 6
|
||||||
|
self.setup_clean_chain = True
|
||||||
|
shared_args1 = ["-signetchallenge=51"] # OP_TRUE
|
||||||
|
shared_args2 = [] # default challenge
|
||||||
|
# we use the exact same challenge except we do it as a 2-of-2, which means it should fail
|
||||||
|
shared_args3 = ["-signetchallenge=522103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae"]
|
||||||
|
|
||||||
|
self.extra_args = [
|
||||||
|
shared_args1, shared_args1,
|
||||||
|
shared_args2, shared_args2,
|
||||||
|
shared_args3, shared_args3,
|
||||||
|
]
|
||||||
|
|
||||||
|
def skip_test_if_missing_module(self):
|
||||||
|
self.skip_if_no_wallet()
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
self.log.info("basic tests using OP_TRUE challenge")
|
||||||
|
|
||||||
|
self.log.info('getmininginfo')
|
||||||
|
mining_info = self.nodes[0].getmininginfo()
|
||||||
|
assert_equal(mining_info['blocks'], 0)
|
||||||
|
assert_equal(mining_info['chain'], 'signet')
|
||||||
|
assert 'currentblocktx' not in mining_info
|
||||||
|
assert 'currentblockweight' not in mining_info
|
||||||
|
assert_equal(mining_info['networkhashps'], Decimal('0'))
|
||||||
|
assert_equal(mining_info['pooledtx'], 0)
|
||||||
|
|
||||||
|
self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
|
||||||
|
|
||||||
|
self.log.info("pregenerated signet blocks check")
|
||||||
|
|
||||||
|
height = 0
|
||||||
|
for block in signet_blocks:
|
||||||
|
assert_equal(self.nodes[2].submitblock(block), None)
|
||||||
|
height = height + 1
|
||||||
|
assert_equal(self.nodes[2].getblockcount(), height)
|
||||||
|
|
||||||
|
self.log.info("pregenerated signet blocks check (incompatible solution)")
|
||||||
|
|
||||||
|
assert_equal(self.nodes[4].submitblock(signet_blocks[0]), 'bad-signet-blksig')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
SignetBasicTest().main()
|
||||||
@@ -109,6 +109,7 @@ MAGIC_BYTES = {
|
|||||||
"mainnet": b"\xf9\xbe\xb4\xd9", # mainnet
|
"mainnet": b"\xf9\xbe\xb4\xd9", # mainnet
|
||||||
"testnet3": b"\x0b\x11\x09\x07", # testnet3
|
"testnet3": b"\x0b\x11\x09\x07", # testnet3
|
||||||
"regtest": b"\xfa\xbf\xb5\xda", # regtest
|
"regtest": b"\xfa\xbf\xb5\xda", # regtest
|
||||||
|
"signet": b"\x0a\x03\xcf\x40", # signet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ BASE_SCRIPTS = [
|
|||||||
'rpc_bind.py --ipv6',
|
'rpc_bind.py --ipv6',
|
||||||
'rpc_bind.py --nonloopback',
|
'rpc_bind.py --nonloopback',
|
||||||
'mining_basic.py',
|
'mining_basic.py',
|
||||||
|
'feature_signet.py',
|
||||||
'wallet_bumpfee.py',
|
'wallet_bumpfee.py',
|
||||||
'wallet_implicitsegwit.py',
|
'wallet_implicitsegwit.py',
|
||||||
'rpc_named_arguments.py',
|
'rpc_named_arguments.py',
|
||||||
|
|||||||
Reference in new issue
Block a user