Align with btc 0.12 (#1409)

* Implement BIP 9 GBT changes

- BIP9DeploymentInfo struct for static deployment info
- VersionBitsDeploymentInfo: Avoid C++11ism by commenting parameter names
- getblocktemplate: Make sure to set deployments in the version if it is LOCKED_IN
- In this commit, all rules are considered required for clients to support

* qa/rpc-tests: bip9-softforks: Add tests for getblocktemplate versionbits updates

* getblocktemplate: Explicitly handle the distinction between GBT-affecting softforks vs not

* getblocktemplate: Use version/force mutation to support pre-BIP9 clients

* Don't use floating point

Github-Pull: #8317
Rebased-From: 477777f250

* Send tip change notification from invalidateblock

This change is needed to prevent sync_blocks timeouts in the mempool_reorg
test after the sync_blocks update in the upcoming commit
"[qa] Change sync_blocks to pick smarter maxheight".

This change was initially suggested by Suhas Daftuar <sdaftuar@chaincode.com>
in https://github.com/bitcoin/bitcoin/pull/8680#r78209060

Github-Pull: #9196
Rebased-From: 67c6326abd

* torcontrol: Explicitly request RSA1024 private key

When generating a new service key, explicitly request a RSA1024 one.

The bitcoin P2P protocol has no support for the longer hidden service names
that will come with ed25519 keys, until it does, we depend on the old
hidden service type so make this explicit.

See #9214.

Github-Pull: #9234
Rebased-From: 7d3b627395

* Bugfix: FRT: don't terminate when keypool is empty

Github-Pull: #9295
Rebased-From: c24a4f5981

* add fundrawtransaction test on a locked wallet with empty keypool

Github-Pull: #9295
Rebased-From: 1a6eacbf3b
This commit is contained in:
UdjinM6 2017-04-11 13:53:54 +03:00 committed by GitHub
parent 4595db0ce3
commit ff30aed68f
11 changed files with 177 additions and 22 deletions

View File

@ -83,7 +83,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
raise IndexError ('key:"%s" not found' % key) raise IndexError ('key:"%s" not found' % key)
def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature): def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature, bitno):
# generate some coins for later # generate some coins for later
self.coinbase_blocks = self.nodes[0].generate(2) self.coinbase_blocks = self.nodes[0].generate(2)
self.height = 3 # height of the next block to build self.height = 3 # height of the next block to build
@ -92,6 +92,11 @@ class BIP9SoftForksTest(ComparisonTestFramework):
self.last_block_time = int(time.time()) self.last_block_time = int(time.time())
assert_equal(self.get_bip9_status(bipName)['status'], 'defined') assert_equal(self.get_bip9_status(bipName)['status'], 'defined')
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
assert(bipName not in tmpl['vbavailable'])
assert_equal(tmpl['vbrequired'], 0)
assert_equal(tmpl['version'], 0x20000000)
# Test 1 # Test 1
# Advance from DEFINED to STARTED # Advance from DEFINED to STARTED
@ -99,6 +104,11 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False) yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'started') assert_equal(self.get_bip9_status(bipName)['status'], 'started')
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
assert_equal(tmpl['vbavailable'][bipName], bitno)
assert_equal(tmpl['vbrequired'], 0)
assert(tmpl['version'] & activated_version)
# Test 2 # Test 2
# Fail to achieve LOCKED_IN 100 out of 144 signal bit 1 # Fail to achieve LOCKED_IN 100 out of 144 signal bit 1
@ -110,6 +120,11 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False) yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'started') assert_equal(self.get_bip9_status(bipName)['status'], 'started')
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
assert_equal(tmpl['vbavailable'][bipName], bitno)
assert_equal(tmpl['vbrequired'], 0)
assert(tmpl['version'] & activated_version)
# Test 3 # Test 3
# 108 out of 144 signal bit 1 to achieve LOCKED_IN # 108 out of 144 signal bit 1 to achieve LOCKED_IN
@ -121,6 +136,8 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False) yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in')
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
# Test 4 # Test 4
# 143 more version 536870913 blocks (waiting period-1) # 143 more version 536870913 blocks (waiting period-1)
@ -128,6 +145,8 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False) yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in')
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
# Test 5 # Test 5
# Check that the new rule is enforced # Check that the new rule is enforced
@ -151,6 +170,11 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance([[block, True]]) yield TestInstance([[block, True]])
assert_equal(self.get_bip9_status(bipName)['status'], 'active') assert_equal(self.get_bip9_status(bipName)['status'], 'active')
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName in tmpl['rules'])
assert(bipName not in tmpl['vbavailable'])
assert_equal(tmpl['vbrequired'], 0)
assert(not (tmpl['version'] & (1 << bitno)))
# Test 6 # Test 6
# Check that the new sequence lock rules are enforced # Check that the new sequence lock rules are enforced
@ -184,9 +208,9 @@ class BIP9SoftForksTest(ComparisonTestFramework):
def get_tests(self): def get_tests(self):
for test in itertools.chain( for test in itertools.chain(
self.test_BIP('csv', 536870913, self.sequence_lock_invalidate, self.donothing), self.test_BIP('csv', 0x20000001, self.sequence_lock_invalidate, self.donothing, 0),
self.test_BIP('csv', 536870913, self.mtp_invalidate, self.donothing), self.test_BIP('csv', 0x20000001, self.mtp_invalidate, self.donothing, 0),
self.test_BIP('csv', 536870913, self.donothing, self.csv_invalidate) self.test_BIP('csv', 0x20000001, self.donothing, self.csv_invalidate, 0)
): ):
yield test yield test

View File

@ -457,6 +457,23 @@ class RawTransactionsTest(BitcoinTestFramework):
self.is_network_split=False self.is_network_split=False
self.sync_all() self.sync_all()
# drain the keypool
self.nodes[1].getnewaddress()
inputs = []
outputs = {self.nodes[0].getnewaddress():1.1}
rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
try:
fundedTx = self.nodes[1].fundrawtransaction(rawTx)
raise AssertionError("Wallet unlocked without passphrase")
except JSONRPCException as e:
assert('Keypool ran out' in e.error['message'])
#refill the keypool
self.nodes[1].walletpassphrase("test", 100)
self.nodes[1].walletlock()
try: try:
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 12) self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 12)
raise AssertionError("Wallet unlocked without passphrase") raise AssertionError("Wallet unlocked without passphrase")

View File

@ -16,6 +16,7 @@ enum DeploymentPos
{ {
DEPLOYMENT_TESTDUMMY, DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113. DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS MAX_VERSION_BITS_DEPLOYMENTS
}; };

View File

@ -2474,7 +2474,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
} }
// Protected by cs_main // Protected by cs_main
static VersionBitsCache versionbitscache; VersionBitsCache versionbitscache;
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{ {
@ -3470,6 +3470,7 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus
InvalidChainFound(pindex); InvalidChainFound(pindex);
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true; return true;
} }

View File

@ -839,6 +839,8 @@ extern CBlockTreeDB *pblocktree;
*/ */
int GetSpendHeight(const CCoinsViewCache& inputs); int GetSpendHeight(const CCoinsViewCache& inputs);
extern VersionBitsCache versionbitscache;
/** /**
* Determine what nVersion a new block should use. * Determine what nVersion a new block should use.
*/ */

View File

@ -10,6 +10,7 @@
#include "chain.h" #include "chain.h"
#include "chainparams.h" #include "chainparams.h"
#include "consensus/consensus.h" #include "consensus/consensus.h"
#include "consensus/params.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#include "core_io.h" #include "core_io.h"
#include "init.h" #include "init.h"
@ -326,6 +327,15 @@ static UniValue BIP22ValidationResult(const CValidationState& state)
return "valid?"; return "valid?";
} }
std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
std::string s = vbinfo.name;
if (!vbinfo.gbt_force) {
s.insert(s.begin(), '!');
}
return s;
}
UniValue getblocktemplate(const UniValue& params, bool fHelp) UniValue getblocktemplate(const UniValue& params, bool fHelp)
{ {
if (fHelp || params.size() > 1) if (fHelp || params.size() > 1)
@ -333,7 +343,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
"getblocktemplate ( \"jsonrequestobject\" )\n" "getblocktemplate ( \"jsonrequestobject\" )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n" "It returns data needed to construct a block to work on.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" "For full specification, see BIPs 22 and 9:\n"
" https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
@ -349,6 +361,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
"\nResult:\n" "\nResult:\n"
"{\n" "{\n"
" \"version\" : n, (numeric) The block version\n" " \"version\" : n, (numeric) The block version\n"
" \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n"
" \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n"
" \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
" ,...\n"
" },\n"
" \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n"
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n" " {\n"
@ -409,6 +427,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
std::string strMode = "template"; std::string strMode = "template";
UniValue lpval = NullUniValue; UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
if (params.size() > 0) if (params.size() > 0)
{ {
const UniValue& oparam = params[0].get_obj(); const UniValue& oparam = params[0].get_obj();
@ -452,6 +472,20 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
TestBlockValidity(state, Params(), block, pindexPrev, false, true); TestBlockValidity(state, Params(), block, pindexPrev, false, true);
return BIP22ValidationResult(state); return BIP22ValidationResult(state);
} }
const UniValue& aClientRules = find_value(oparam, "rules");
if (aClientRules.isArray()) {
for (unsigned int i = 0; i < aClientRules.size(); ++i) {
const UniValue& v = aClientRules[i];
setClientRules.insert(v.get_str());
}
} else {
// NOTE: It is important that this NOT be read if versionbits is supported
const UniValue& uvMaxVersion = find_value(oparam, "maxversion");
if (uvMaxVersion.isNum()) {
nMaxVersionPreVB = uvMaxVersion.get_int64();
}
}
} }
if (strMode != "template") if (strMode != "template")
@ -544,9 +578,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
pindexPrev = pindexPrevNew; pindexPrev = pindexPrevNew;
} }
CBlock* pblock = &pblocktemplate->block; // pointer for convenience CBlock* pblock = &pblocktemplate->block; // pointer for convenience
const Consensus::Params& consensusParams = Params().GetConsensus();
// Update nTime // Update nTime
UpdateTime(pblock, Params().GetConsensus(), pindexPrev); UpdateTime(pblock, consensusParams, pindexPrev);
pblock->nNonce = 0; pblock->nNonce = 0;
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
@ -587,17 +622,69 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
static UniValue aMutable(UniValue::VARR); UniValue aMutable(UniValue::VARR);
if (aMutable.empty())
{
aMutable.push_back("time"); aMutable.push_back("time");
aMutable.push_back("transactions"); aMutable.push_back("transactions");
aMutable.push_back("prevblock"); aMutable.push_back("prevblock");
}
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("capabilities", aCaps));
UniValue aRules(UniValue::VARR);
UniValue vbavailable(UniValue::VOBJ);
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
Consensus::DeploymentPos pos = Consensus::DeploymentPos(i);
ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache);
switch (state) {
case THRESHOLD_DEFINED:
case THRESHOLD_FAILED:
// Not exposed to GBT at all
break;
case THRESHOLD_LOCKED_IN:
// Ensure bit is set in block version
pblock->nVersion |= VersionBitsMask(consensusParams, pos);
// FALL THROUGH to get vbavailable set...
case THRESHOLD_STARTED:
{
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
vbavailable.push_back(Pair(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit));
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
if (!vbinfo.gbt_force) {
// If the client doesn't support this, don't indicate it in the [default] version
pblock->nVersion &= ~VersionBitsMask(consensusParams, pos);
}
}
break;
}
case THRESHOLD_ACTIVE:
{
// Add to rules only
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
aRules.push_back(gbt_vb_name(pos));
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
// Not supported by the client; make sure it's safe to proceed
if (!vbinfo.gbt_force) {
// If we do anything other than throw an exception here, be sure version/force isn't sent to old clients
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name));
}
}
break;
}
}
}
result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("version", pblock->nVersion));
result.push_back(Pair("rules", aRules));
result.push_back(Pair("vbavailable", vbavailable));
result.push_back(Pair("vbrequired", int(0)));
if (nMaxVersionPreVB >= 2) {
// If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here
// Because BIP 34 changed how the generation transaction is serialised, we can only use version/force back to v2 blocks
// This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated
// Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated
aMutable.push_back("version/force");
}
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("transactions", transactions)); result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbaseaux", aux));

View File

@ -465,7 +465,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r
// Finally - now create the service // Finally - now create the service
if (private_key.empty()) // No private key, generate one if (private_key.empty()) // No private key, generate one
private_key = "NEW:BEST"; private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214
// Request hidden service, redirect port. // Request hidden service, redirect port.
// Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient
// choice. TODO; refactor the shutdown sequence some day. // choice. TODO; refactor the shutdown sequence some day.

View File

@ -4,6 +4,19 @@
#include "versionbits.h" #include "versionbits.h"
#include "consensus/params.h"
const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
/*.name =*/ "testdummy",
/*.gbt_force =*/ true,
},
{
/*.name =*/ "csv",
/*.gbt_force =*/ true,
}
};
ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
{ {
int nPeriod = Period(params); int nPeriod = Period(params);

View File

@ -30,6 +30,15 @@ enum ThresholdState {
// will either be NULL or a block with (height + 1) % Period() == 0. // will either be NULL or a block with (height + 1) % Period() == 0.
typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache; typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
struct BIP9DeploymentInfo {
/** Deployment name */
const char *name;
/** Whether GBT clients can safely ignore this rule in simplified usage */
bool gbt_force;
};
extern const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[];
/** /**
* Abstract class that implements BIP9-style threshold logic, and caches results. * Abstract class that implements BIP9-style threshold logic, and caches results.
*/ */

View File

@ -668,7 +668,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
CScript scriptPubKey = GetScriptForDestination(address.Get()); CScript scriptPubKey = GetScriptForDestination(address.Get());
if (!IsMine(*pwalletMain, scriptPubKey)) if (!IsMine(*pwalletMain, scriptPubKey))
return (double)0.0; return ValueFromAmount(0);
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
@ -746,7 +746,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
} }
} }
return (double)nAmount / (double)COIN; return ValueFromAmount(nAmount);
} }

View File

@ -3070,10 +3070,11 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Reserve a new key pair from key pool // Reserve a new key pair from key pool
CPubKey vchPubKey; CPubKey vchPubKey;
bool ret; if (!reservekey.GetReservedKey(vchPubKey))
ret = reservekey.GetReservedKey(vchPubKey); {
assert(ret); // should never fail, as we just unlocked strFailReason = _("Keypool ran out, please call keypoolrefill first");
return false;
}
scriptChange = GetScriptForDestination(vchPubKey.GetID()); scriptChange = GetScriptForDestination(vchPubKey.GetID());
} }