mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-05 13:17:49 +02:00
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:
@@ -202,6 +202,7 @@ BITCOIN_CORE_H = \
|
||||
script/signingprovider.h \
|
||||
script/standard.h \
|
||||
shutdown.h \
|
||||
signet.h \
|
||||
streams.h \
|
||||
support/allocators/secure.h \
|
||||
support/allocators/zeroafterfree.h \
|
||||
@@ -322,6 +323,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
rpc/server.cpp \
|
||||
script/sigcache.cpp \
|
||||
shutdown.cpp \
|
||||
signet.cpp \
|
||||
timedata.cpp \
|
||||
torcontrol.cpp \
|
||||
txdb.cpp \
|
||||
|
||||
@@ -137,6 +137,7 @@ FUZZ_TARGETS = \
|
||||
test/fuzz/secp256k1_ecdsa_signature_parse_der_lax \
|
||||
test/fuzz/service_deserialize \
|
||||
test/fuzz/signature_checker \
|
||||
test/fuzz/signet \
|
||||
test/fuzz/snapshotmetadata_deserialize \
|
||||
test/fuzz/span \
|
||||
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_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_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
test_fuzz_snapshotmetadata_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <chainparamsseeds.h>
|
||||
#include <consensus/merkle.h>
|
||||
#include <hash.h> // for signet block challenge hash
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
#include <util/strencodings.h>
|
||||
@@ -63,6 +64,8 @@ class CMainParams : public CChainParams {
|
||||
public:
|
||||
CMainParams() {
|
||||
strNetworkID = CBaseChainParams::MAIN;
|
||||
consensus.signet_blocks = false;
|
||||
consensus.signet_challenge.clear();
|
||||
consensus.nSubsidyHalvingInterval = 210000;
|
||||
consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
|
||||
consensus.BIP34Height = 227931;
|
||||
@@ -172,6 +175,8 @@ class CTestNetParams : public CChainParams {
|
||||
public:
|
||||
CTestNetParams() {
|
||||
strNetworkID = CBaseChainParams::TESTNET;
|
||||
consensus.signet_blocks = false;
|
||||
consensus.signet_challenge.clear();
|
||||
consensus.nSubsidyHalvingInterval = 210000;
|
||||
consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
|
||||
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
|
||||
*/
|
||||
@@ -257,6 +351,8 @@ class CRegTestParams : public CChainParams {
|
||||
public:
|
||||
explicit CRegTestParams(const ArgsManager& args) {
|
||||
strNetworkID = CBaseChainParams::REGTEST;
|
||||
consensus.signet_blocks = false;
|
||||
consensus.signet_challenge.clear();
|
||||
consensus.nSubsidyHalvingInterval = 150;
|
||||
consensus.BIP16Exception = uint256();
|
||||
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)
|
||||
{
|
||||
if (chain == CBaseChainParams::MAIN)
|
||||
if (chain == CBaseChainParams::MAIN) {
|
||||
return std::unique_ptr<CChainParams>(new CMainParams());
|
||||
else if (chain == CBaseChainParams::TESTNET)
|
||||
} else if (chain == CBaseChainParams::TESTNET) {
|
||||
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));
|
||||
}
|
||||
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
const std::string CBaseChainParams::MAIN = "main";
|
||||
const std::string CBaseChainParams::TESTNET = "test";
|
||||
const std::string CBaseChainParams::SIGNET = "signet";
|
||||
const std::string CBaseChainParams::REGTEST = "regtest";
|
||||
|
||||
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("-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("-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;
|
||||
@@ -35,14 +39,16 @@ const CBaseChainParams& BaseParams()
|
||||
|
||||
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
|
||||
{
|
||||
if (chain == CBaseChainParams::MAIN)
|
||||
if (chain == CBaseChainParams::MAIN) {
|
||||
return MakeUnique<CBaseChainParams>("", 8332);
|
||||
else if (chain == CBaseChainParams::TESTNET)
|
||||
} else if (chain == CBaseChainParams::TESTNET) {
|
||||
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);
|
||||
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)
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
/** Chain name strings */
|
||||
static const std::string MAIN;
|
||||
static const std::string TESTNET;
|
||||
static const std::string SIGNET;
|
||||
static const std::string REGTEST;
|
||||
///@}
|
||||
|
||||
|
||||
@@ -80,6 +80,13 @@ struct Params {
|
||||
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
|
||||
uint256 nMinimumChainWork;
|
||||
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
|
||||
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
#include <primitives/transaction.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
|
||||
* 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);
|
||||
}
|
||||
|
||||
/** 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
|
||||
|
||||
@@ -46,6 +46,7 @@ static const int TOOLTIP_WRAP_THRESHOLD = 80;
|
||||
#define QAPP_ORG_DOMAIN "bitcoin.org"
|
||||
#define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt"
|
||||
#define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet"
|
||||
#define QAPP_APP_NAME_SIGNET "Bitcoin-Qt-signet"
|
||||
#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest"
|
||||
|
||||
/* One gigabyte (GB) in bytes */
|
||||
|
||||
@@ -19,7 +19,8 @@ static const struct {
|
||||
} network_styles[] = {
|
||||
{"main", QAPP_APP_NAME_DEFAULT, 0, 0},
|
||||
{"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);
|
||||
|
||||
|
||||
149
src/signet.cpp
Normal file
149
src/signet.cpp
Normal file
@@ -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;
|
||||
}
|
||||
42
src/signet.h
Normal file
42
src/signet.h
Normal file
@@ -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
|
||||
34
src/test/fuzz/signet.cpp
Normal file
34
src/test/fuzz/signet.cpp
Normal file
@@ -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();
|
||||
|
||||
// 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);
|
||||
destination = DecodeDestination(exp_base58string);
|
||||
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()
|
||||
|
||||
@@ -848,8 +848,8 @@ struct ArgsMergeTestingSetup : public BasicTestingSetup {
|
||||
ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
|
||||
for (bool soft_set : {false, true}) {
|
||||
for (bool force_set : {false, true}) {
|
||||
for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
|
||||
for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
|
||||
for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
|
||||
for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
|
||||
for (bool net_specific : {false, true}) {
|
||||
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:
|
||||
//
|
||||
// <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.
|
||||
@@ -1106,7 +1106,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
|
||||
// Results file is formatted like:
|
||||
//
|
||||
// <input> || <output>
|
||||
BOOST_CHECK_EQUAL(out_sha_hex, "f0b3a3c29869edc765d579c928f7f1690a71fbb673b49ccf39cbc4de18156a0d");
|
||||
BOOST_CHECK_EQUAL(out_sha_hex, "f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
|
||||
|
||||
@@ -263,6 +263,7 @@ const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
|
||||
// Section names to be recognized in the config file.
|
||||
static const std::set<std::string> available_sections{
|
||||
CBaseChainParams::REGTEST,
|
||||
CBaseChainParams::SIGNET,
|
||||
CBaseChainParams::TESTNET,
|
||||
CBaseChainParams::MAIN
|
||||
};
|
||||
@@ -916,16 +917,21 @@ std::string ArgsManager::GetChainName() const
|
||||
};
|
||||
|
||||
const bool fRegTest = get_net("-regtest");
|
||||
const bool fSigNet = get_net("-signet");
|
||||
const bool fTestNet = get_net("-testnet");
|
||||
const bool is_chain_arg_set = IsArgSet("-chain");
|
||||
|
||||
if ((int)is_chain_arg_set + (int)fRegTest + (int)fTestNet > 1) {
|
||||
throw std::runtime_error("Invalid combination of -regtest, -testnet and -chain. Can use at most one.");
|
||||
if ((int)is_chain_arg_set + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
|
||||
throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one.");
|
||||
}
|
||||
if (fRegTest)
|
||||
return CBaseChainParams::REGTEST;
|
||||
if (fSigNet) {
|
||||
return CBaseChainParams::SIGNET;
|
||||
}
|
||||
if (fTestNet)
|
||||
return CBaseChainParams::TESTNET;
|
||||
|
||||
return GetArg("-chain", CBaseChainParams::MAIN);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <script/script.h>
|
||||
#include <script/sigcache.h>
|
||||
#include <shutdown.h>
|
||||
#include <signet.h>
|
||||
#include <timedata.h>
|
||||
#include <tinyformat.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))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -3346,6 +3352,11 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
|
||||
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
|
||||
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.
|
||||
if (fCheckMerkleRoot) {
|
||||
bool mutated;
|
||||
@@ -3409,31 +3420,11 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
|
||||
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)
|
||||
{
|
||||
int commitpos = GetWitnessCommitmentIndex(block);
|
||||
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]);
|
||||
tx.vin[0].scriptWitness.stack.resize(1);
|
||||
tx.vin[0].scriptWitness.stack[0] = nonce;
|
||||
@@ -3447,7 +3438,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
|
||||
int commitpos = GetWitnessCommitmentIndex(block);
|
||||
std::vector<unsigned char> ret(32, 0x00);
|
||||
if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
|
||||
if (commitpos == -1) {
|
||||
if (commitpos == NO_WITNESS_COMMITMENT) {
|
||||
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
|
||||
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
|
||||
CTxOut out;
|
||||
@@ -3585,7 +3576,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
|
||||
bool fHaveWitness = false;
|
||||
if (nHeight >= consensusParams.SegwitHeight) {
|
||||
int commitpos = GetWitnessCommitmentIndex(block);
|
||||
if (commitpos != -1) {
|
||||
if (commitpos != NO_WITNESS_COMMITMENT) {
|
||||
bool malleated = false;
|
||||
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
|
||||
// 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
|
||||
// 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;
|
||||
/** Minimum size of a witness commitment structure. Defined in BIP 141. **/
|
||||
static constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};
|
||||
|
||||
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. */
|
||||
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. */
|
||||
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
|
||||
|
||||
|
||||
71
test/functional/feature_signet.py
Executable file
71
test/functional/feature_signet.py
Executable file
@@ -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
|
||||
"testnet3": b"\x0b\x11\x09\x07", # testnet3
|
||||
"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 --nonloopback',
|
||||
'mining_basic.py',
|
||||
'feature_signet.py',
|
||||
'wallet_bumpfee.py',
|
||||
'wallet_implicitsegwit.py',
|
||||
'rpc_named_arguments.py',
|
||||
|
||||
Reference in New Issue
Block a user