Skip to content

Commit fc14609

Browse files
committed
RPC: augment getblockchaininfo bip9_softforks data
1 parent d736a6e commit fc14609

File tree

7 files changed

+121
-44
lines changed

7 files changed

+121
-44
lines changed

qa/rpc-tests/bip9-softforks.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ def get_bip9_status(self, key):
8181
return info['bip9_softforks'][key]
8282

8383
def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature, bitno):
84+
assert_equal(self.get_bip9_status(bipName)['status'], 'defined')
85+
assert_equal(self.get_bip9_status(bipName)['since'], 0)
86+
8487
# generate some coins for later
8588
self.coinbase_blocks = self.nodes[0].generate(2)
8689
self.height = 3 # height of the next block to build
@@ -89,6 +92,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu
8992
self.last_block_time = int(time.time())
9093

9194
assert_equal(self.get_bip9_status(bipName)['status'], 'defined')
95+
assert_equal(self.get_bip9_status(bipName)['since'], 0)
9296
tmpl = self.nodes[0].getblocktemplate({})
9397
assert(bipName not in tmpl['rules'])
9498
assert(bipName not in tmpl['vbavailable'])
@@ -101,6 +105,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu
101105
yield TestInstance(test_blocks, sync_every_block=False)
102106

103107
assert_equal(self.get_bip9_status(bipName)['status'], 'started')
108+
assert_equal(self.get_bip9_status(bipName)['since'], 144)
104109
tmpl = self.nodes[0].getblocktemplate({})
105110
assert(bipName not in tmpl['rules'])
106111
assert_equal(tmpl['vbavailable'][bipName], bitno)
@@ -117,6 +122,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu
117122
yield TestInstance(test_blocks, sync_every_block=False)
118123

119124
assert_equal(self.get_bip9_status(bipName)['status'], 'started')
125+
assert_equal(self.get_bip9_status(bipName)['since'], 144)
120126
tmpl = self.nodes[0].getblocktemplate({})
121127
assert(bipName not in tmpl['rules'])
122128
assert_equal(tmpl['vbavailable'][bipName], bitno)
@@ -133,6 +139,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu
133139
yield TestInstance(test_blocks, sync_every_block=False)
134140

135141
assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in')
142+
assert_equal(self.get_bip9_status(bipName)['since'], 432)
136143
tmpl = self.nodes[0].getblocktemplate({})
137144
assert(bipName not in tmpl['rules'])
138145

@@ -142,6 +149,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu
142149
yield TestInstance(test_blocks, sync_every_block=False)
143150

144151
assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in')
152+
assert_equal(self.get_bip9_status(bipName)['since'], 432)
145153
tmpl = self.nodes[0].getblocktemplate({})
146154
assert(bipName not in tmpl['rules'])
147155

@@ -167,6 +175,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu
167175
yield TestInstance([[block, True]])
168176

169177
assert_equal(self.get_bip9_status(bipName)['status'], 'active')
178+
assert_equal(self.get_bip9_status(bipName)['since'], 576)
170179
tmpl = self.nodes[0].getblocktemplate({})
171180
assert(bipName in tmpl['rules'])
172181
assert(bipName not in tmpl['vbavailable'])

src/main.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6918,6 +6918,12 @@ ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::D
69186918
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
69196919
}
69206920

6921+
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)
6922+
{
6923+
LOCK(cs_main);
6924+
return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);
6925+
}
6926+
69216927
class CMainCleanup
69226928
{
69236929
public:

src/main.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ std::string FormatStateMessage(const CValidationState &state);
297297
/** Get the BIP9 state for a given deployment at the current tip. */
298298
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
299299

300-
300+
/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */
301+
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);
301302

302303
/**
303304
* Count ECDSA signature operations the old-fashioned (pre-0.6) way

src/rpc/blockchain.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,7 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
10091009
}
10101010
rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime));
10111011
rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout));
1012+
rv.push_back(Pair("since", VersionBitsTipStateSinceHeight(consensusParams, id)));
10121013
return rv;
10131014
}
10141015

@@ -1053,7 +1054,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
10531054
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
10541055
" \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
10551056
" \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
1056-
" \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
1057+
" \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
1058+
" \"since\": xx (numeric) height of the first block to which the status applies\n"
10571059
" }\n"
10581060
" }\n"
10591061
"}\n"

src/test/versionbits_tests.cpp

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2014-2015 The Bitcoin Core developers
1+
// Copyright (c) 2014-2016 The Bitcoin Core developers
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

@@ -30,6 +30,7 @@ class TestConditionChecker : public AbstractThresholdConditionChecker
3030
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); }
3131

3232
ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); }
33+
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }
3334
};
3435

3536
#define CHECKERS 6
@@ -78,6 +79,16 @@ class VersionBitsTester
7879
return *this;
7980
}
8081

82+
VersionBitsTester& TestStateSinceHeight(int height) {
83+
for (int i = 0; i < CHECKERS; i++) {
84+
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
85+
BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? NULL : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
86+
}
87+
}
88+
num++;
89+
return *this;
90+
}
91+
8192
VersionBitsTester& TestDefined() {
8293
for (int i = 0; i < CHECKERS; i++) {
8394
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
@@ -137,53 +148,64 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
137148
{
138149
for (int i = 0; i < 64; i++) {
139150
// DEFINED -> FAILED
140-
VersionBitsTester().TestDefined()
141-
.Mine(1, TestTime(1), 0x100).TestDefined()
142-
.Mine(11, TestTime(11), 0x100).TestDefined()
143-
.Mine(989, TestTime(989), 0x100).TestDefined()
144-
.Mine(999, TestTime(20000), 0x100).TestDefined()
145-
.Mine(1000, TestTime(20000), 0x100).TestFailed()
146-
.Mine(1999, TestTime(30001), 0x100).TestFailed()
147-
.Mine(2000, TestTime(30002), 0x100).TestFailed()
148-
.Mine(2001, TestTime(30003), 0x100).TestFailed()
149-
.Mine(2999, TestTime(30004), 0x100).TestFailed()
150-
.Mine(3000, TestTime(30005), 0x100).TestFailed()
151+
VersionBitsTester().TestDefined().TestStateSinceHeight(0)
152+
.Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)
153+
.Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)
154+
.Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0)
155+
.Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0)
156+
.Mine(1000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(1000)
157+
.Mine(1999, TestTime(30001), 0x100).TestFailed().TestStateSinceHeight(1000)
158+
.Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(1000)
159+
.Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(1000)
160+
.Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(1000)
161+
.Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(1000)
151162

152163
// DEFINED -> STARTED -> FAILED
153-
.Reset().TestDefined()
154-
.Mine(1, TestTime(1), 0).TestDefined()
155-
.Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined
156-
.Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period
157-
.Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks
158-
.Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks
159-
.Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000)
160-
.Mine(4000, TestTime(20010), 0x100).TestFailed()
164+
.Reset().TestDefined().TestStateSinceHeight(0)
165+
.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
166+
.Mine(1000, TestTime(10000) - 1, 0x100).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
167+
.Mine(2000, TestTime(10000), 0x100).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
168+
.Mine(2051, TestTime(10010), 0).TestStarted().TestStateSinceHeight(2000) // 51 old blocks
169+
.Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 899 new blocks
170+
.Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000)
171+
.Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000)
161172

162173
// DEFINED -> STARTED -> FAILED while threshold reached
163-
.Reset().TestDefined()
164-
.Mine(1, TestTime(1), 0).TestDefined()
165-
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
166-
.Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
167-
.Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks
168-
.Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new)
169-
.Mine(3999, TestTime(30001), 0).TestFailed()
170-
.Mine(4000, TestTime(30002), 0).TestFailed()
171-
.Mine(14333, TestTime(30003), 0).TestFailed()
172-
.Mine(24000, TestTime(40000), 0).TestFailed()
174+
.Reset().TestDefined().TestStateSinceHeight(0)
175+
.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
176+
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
177+
.Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
178+
.Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks
179+
.Mine(3000, TestTime(30000), 0x100).TestFailed().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)
180+
.Mine(3999, TestTime(30001), 0).TestFailed().TestStateSinceHeight(3000)
181+
.Mine(4000, TestTime(30002), 0).TestFailed().TestStateSinceHeight(3000)
182+
.Mine(14333, TestTime(30003), 0).TestFailed().TestStateSinceHeight(3000)
183+
.Mine(24000, TestTime(40000), 0).TestFailed().TestStateSinceHeight(3000)
173184

174185
// DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE
175186
.Reset().TestDefined()
176-
.Mine(1, TestTime(1), 0).TestDefined()
177-
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
178-
.Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
179-
.Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks
180-
.Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks
181-
.Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks
182-
.Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000)
183-
.Mine(3999, TestTime(30001), 0).TestLockedIn()
184-
.Mine(4000, TestTime(30002), 0).TestActive()
185-
.Mine(14333, TestTime(30003), 0).TestActive()
186-
.Mine(24000, TestTime(40000), 0).TestActive();
187+
.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
188+
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
189+
.Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
190+
.Mine(2050, TestTime(10010), 0x200).TestStarted().TestStateSinceHeight(2000) // 50 old blocks
191+
.Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 900 new blocks
192+
.Mine(2999, TestTime(19999), 0x200).TestStarted().TestStateSinceHeight(2000) // 49 old blocks
193+
.Mine(3000, TestTime(29999), 0x200).TestLockedIn().TestStateSinceHeight(3000) // 1 old block (so 900 out of the past 1000)
194+
.Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)
195+
.Mine(4000, TestTime(30002), 0).TestActive().TestStateSinceHeight(4000)
196+
.Mine(14333, TestTime(30003), 0).TestActive().TestStateSinceHeight(4000)
197+
.Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000)
198+
199+
// DEFINED multiple periods -> STARTED multiple periods -> FAILED
200+
.Reset().TestDefined().TestStateSinceHeight(0)
201+
.Mine(999, TestTime(999), 0).TestDefined().TestStateSinceHeight(0)
202+
.Mine(1000, TestTime(1000), 0).TestDefined().TestStateSinceHeight(0)
203+
.Mine(2000, TestTime(2000), 0).TestDefined().TestStateSinceHeight(0)
204+
.Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
205+
.Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
206+
.Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
207+
.Mine(6000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(6000)
208+
.Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000);
187209
}
188210

189211
// Sanity checks of version bit deployments

src/versionbits.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,36 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
105105
return state;
106106
}
107107

108+
int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
109+
{
110+
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
111+
112+
// BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
113+
if (initialState == THRESHOLD_DEFINED) {
114+
return 0;
115+
}
116+
117+
const int nPeriod = Period(params);
118+
119+
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
120+
// To ease understanding of the following height calculation, it helps to remember that
121+
// right now pindexPrev points to the block prior to the block that we are computing for, thus:
122+
// if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
123+
// if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
124+
// The parent of the genesis block is represented by NULL.
125+
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
126+
127+
const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
128+
129+
while (previousPeriodParent != NULL && GetStateFor(previousPeriodParent, params, cache) == initialState) {
130+
pindexPrev = previousPeriodParent;
131+
previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
132+
}
133+
134+
// Adjust the result because right now we point to the parent block.
135+
return pindexPrev->nHeight + 1;
136+
}
137+
108138
namespace
109139
{
110140
/**
@@ -137,6 +167,11 @@ ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::
137167
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
138168
}
139169

170+
int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
171+
{
172+
return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, cache.caches[pos]);
173+
}
174+
140175
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos)
141176
{
142177
return VersionBitsConditionChecker(pos).Mask(params);

src/versionbits.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ class AbstractThresholdConditionChecker {
5151
virtual int Threshold(const Consensus::Params& params) const =0;
5252

5353
public:
54-
// Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent.
54+
// Note that the functions below take a pindexPrev as input: they compute information for block B based on its parent.
5555
ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
56+
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
5657
};
5758

5859
struct VersionBitsCache
@@ -63,6 +64,7 @@ struct VersionBitsCache
6364
};
6465

6566
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
67+
int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
6668
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
6769

6870
#endif

0 commit comments

Comments
 (0)