mirror of https://github.com/bitcoin/bitcoin.git
Merge bitcoin/bitcoin#33446: rpc: fix getblock(header) returns target for tip
bf7996cbc3
rpc: fix getblock(header) returns target for tip (Sjors Provoost)4c3c1f42cf
test: add block 2016 to mock mainnet (Sjors Provoost) Pull request description: A `target` field was added to the `getblock` and `getblockheader` RPC calls in #31583, but it mistakingly always used the tip value. This PR fixes it to return the target for the given block. Because regtest does not have difficulty adjustment, the mainnet test is expanded to cover the fix. A preliminary commit deals with mining block 2016 that's needed for the test. It also: - renames the `create_coinbase` `retarget_period` argument to `halving_period`. Before #31583 this was hardcoded for regtest where these values are the same. - drops unused `fees` argument from `mine` helper - expands the CPU miner instructions for generating the alternative mainnet chain Fixes #33440 ACKs for top commit: sipa: utACKbf7996cbc3
luke-jr: crACKbf7996cbc3
TheCharlatan: ACKbf7996cbc3
ismaelsadeeq: Code review ACKbf7996cbc3
Tree-SHA512: 2a2e11efd91f4aaccf9d2ec4dff9fd82c366b8a7e797ce5981dca2e6f08028f69154f4e6a27aef20d78b0e6c3304416789267c2fad42d7aa5072f8537d0c8b0d
This commit is contained in:
commit
d41b503ae1
|
@ -166,7 +166,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex
|
||||||
result.pushKV("mediantime", blockindex.GetMedianTimePast());
|
result.pushKV("mediantime", blockindex.GetMedianTimePast());
|
||||||
result.pushKV("nonce", blockindex.nNonce);
|
result.pushKV("nonce", blockindex.nNonce);
|
||||||
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
|
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
|
||||||
result.pushKV("target", GetTarget(tip, pow_limit).GetHex());
|
result.pushKV("target", GetTarget(blockindex, pow_limit).GetHex());
|
||||||
result.pushKV("difficulty", GetDifficulty(blockindex));
|
result.pushKV("difficulty", GetDifficulty(blockindex));
|
||||||
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
|
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
|
||||||
result.pushKV("nTx", blockindex.nTx);
|
result.pushKV("nTx", blockindex.nTx);
|
||||||
|
|
|
@ -11,9 +11,10 @@ The alternate mainnet chain was generated as follows:
|
||||||
- restart node with a faketime 2 minutes later
|
- restart node with a faketime 2 minutes later
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
for i in {1..2015}
|
for i in {1..2016}
|
||||||
do
|
do
|
||||||
faketime "`date -d @"$(( 1231006505 + $i * 120 ))" +'%Y-%m-%d %H:%M:%S'`" \
|
t=$(( 1231006505 + $i * 120 ))
|
||||||
|
faketime "`date -d @$t +'%Y-%m-%d %H:%M:%S'`" \
|
||||||
bitcoind -connect=0 -nocheckpoints -stopatheight=$i
|
bitcoind -connect=0 -nocheckpoints -stopatheight=$i
|
||||||
done
|
done
|
||||||
```
|
```
|
||||||
|
@ -21,7 +22,9 @@ done
|
||||||
The CPU miner is kept running as follows:
|
The CPU miner is kept running as follows:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./minerd --coinbase-addr 1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r --no-stratum --algo sha256d --no-longpoll --scantime 3 --retry-pause 1
|
./minerd -u ... -p ... -o http://127.0.0.1:8332 --no-stratum \
|
||||||
|
--coinbase-addr 1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r \
|
||||||
|
--algo sha256d --no-longpoll --scantime 3 --retry-pause 1
|
||||||
```
|
```
|
||||||
|
|
||||||
The payout address is derived from first BIP32 test vector master key:
|
The payout address is derived from first BIP32 test vector master key:
|
||||||
|
@ -40,3 +43,8 @@ The timestamp was not kept constant because at difficulty 1 it's not sufficient
|
||||||
to only grind the nonce. Grinding the extra_nonce or version field instead
|
to only grind the nonce. Grinding the extra_nonce or version field instead
|
||||||
would have required additional (stratum) software. It would also make it more
|
would have required additional (stratum) software. It would also make it more
|
||||||
complicated to reconstruct the blocks in this test.
|
complicated to reconstruct the blocks in this test.
|
||||||
|
|
||||||
|
The `getblocktemplate` RPC code needs to be patched to ignore not being connected
|
||||||
|
to any peers, and to ignore the IBD status check.
|
||||||
|
|
||||||
|
On macOS use `faketime "@$t"` instead.
|
||||||
|
|
|
@ -2014,7 +2014,8 @@
|
||||||
1231247971,
|
1231247971,
|
||||||
1231248071,
|
1231248071,
|
||||||
1231248198,
|
1231248198,
|
||||||
1231248322
|
1231248322,
|
||||||
|
1231248621
|
||||||
],
|
],
|
||||||
"nonces": [
|
"nonces": [
|
||||||
2345621585,
|
2345621585,
|
||||||
|
@ -4031,6 +4032,7 @@
|
||||||
3658502865,
|
3658502865,
|
||||||
2519048297,
|
2519048297,
|
||||||
1915965760,
|
1915965760,
|
||||||
1183846025
|
1183846025,
|
||||||
|
2713372123
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,15 +53,15 @@ class MiningMainnetTest(BitcoinTestFramework):
|
||||||
help='Block data file (default: %(default)s)',
|
help='Block data file (default: %(default)s)',
|
||||||
)
|
)
|
||||||
|
|
||||||
def mine(self, height, prev_hash, blocks, node, fees=0):
|
def mine(self, height, prev_hash, blocks, node):
|
||||||
self.log.debug(f"height={height}")
|
self.log.debug(f"height={height}")
|
||||||
block = CBlock()
|
block = CBlock()
|
||||||
block.nVersion = 0x20000000
|
block.nVersion = 0x20000000
|
||||||
block.hashPrevBlock = int(prev_hash, 16)
|
block.hashPrevBlock = int(prev_hash, 16)
|
||||||
block.nTime = blocks['timestamps'][height - 1]
|
block.nTime = blocks['timestamps'][height - 1]
|
||||||
block.nBits = DIFF_1_N_BITS
|
block.nBits = DIFF_1_N_BITS if height < 2016 else DIFF_4_N_BITS
|
||||||
block.nNonce = blocks['nonces'][height - 1]
|
block.nNonce = blocks['nonces'][height - 1]
|
||||||
block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), retarget_period=2016)]
|
block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), halving_period=210000)]
|
||||||
# The alternate mainnet chain was mined with non-timelocked coinbase txs.
|
# The alternate mainnet chain was mined with non-timelocked coinbase txs.
|
||||||
block.vtx[0].nLockTime = 0
|
block.vtx[0].nLockTime = 0
|
||||||
block.vtx[0].vin[0].nSequence = SEQUENCE_FINAL
|
block.vtx[0].vin[0].nSequence = SEQUENCE_FINAL
|
||||||
|
@ -82,12 +82,15 @@ class MiningMainnetTest(BitcoinTestFramework):
|
||||||
self.log.info("Load alternative mainnet blocks")
|
self.log.info("Load alternative mainnet blocks")
|
||||||
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile)
|
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile)
|
||||||
prev_hash = node.getbestblockhash()
|
prev_hash = node.getbestblockhash()
|
||||||
|
blocks = None
|
||||||
with open(path, encoding='utf-8') as f:
|
with open(path, encoding='utf-8') as f:
|
||||||
blocks = json.load(f)
|
blocks = json.load(f)
|
||||||
n_blocks = len(blocks['timestamps'])
|
n_blocks = len(blocks['timestamps'])
|
||||||
assert_equal(n_blocks, 2015)
|
assert_equal(n_blocks, 2016)
|
||||||
for i in range(2015):
|
|
||||||
prev_hash = self.mine(i + 1, prev_hash, blocks, node)
|
# Mine up to the last block of the first retarget period
|
||||||
|
for i in range(2015):
|
||||||
|
prev_hash = self.mine(i + 1, prev_hash, blocks, node)
|
||||||
|
|
||||||
assert_equal(node.getblockcount(), 2015)
|
assert_equal(node.getblockcount(), 2015)
|
||||||
|
|
||||||
|
@ -102,5 +105,21 @@ class MiningMainnetTest(BitcoinTestFramework):
|
||||||
assert_equal(mining_info['next']['bits'], nbits_str(DIFF_4_N_BITS))
|
assert_equal(mining_info['next']['bits'], nbits_str(DIFF_4_N_BITS))
|
||||||
assert_equal(mining_info['next']['target'], target_str(DIFF_4_TARGET))
|
assert_equal(mining_info['next']['target'], target_str(DIFF_4_TARGET))
|
||||||
|
|
||||||
|
# Mine first block of the second retarget period
|
||||||
|
height = 2016
|
||||||
|
prev_hash = self.mine(height, prev_hash, blocks, node)
|
||||||
|
assert_equal(node.getblockcount(), height)
|
||||||
|
|
||||||
|
mining_info = node.getmininginfo()
|
||||||
|
assert_equal(mining_info['difficulty'], 4)
|
||||||
|
|
||||||
|
self.log.info("getblock RPC should show historical target")
|
||||||
|
block_info = node.getblock(node.getblockhash(1))
|
||||||
|
|
||||||
|
assert_equal(block_info['difficulty'], 1)
|
||||||
|
assert_equal(block_info['bits'], nbits_str(DIFF_1_N_BITS))
|
||||||
|
assert_equal(block_info['target'], target_str(DIFF_1_TARGET))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
MiningMainnetTest(__file__).main()
|
MiningMainnetTest(__file__).main()
|
||||||
|
|
|
@ -144,7 +144,7 @@ def script_BIP34_coinbase_height(height):
|
||||||
return CScript([CScriptNum(height)])
|
return CScript([CScriptNum(height)])
|
||||||
|
|
||||||
|
|
||||||
def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50, retarget_period=REGTEST_RETARGET_PERIOD):
|
def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50, halving_period=REGTEST_RETARGET_PERIOD):
|
||||||
"""Create a coinbase transaction.
|
"""Create a coinbase transaction.
|
||||||
|
|
||||||
If pubkey is passed in, the coinbase output will be a P2PK output;
|
If pubkey is passed in, the coinbase output will be a P2PK output;
|
||||||
|
@ -158,7 +158,7 @@ def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_scr
|
||||||
coinbaseoutput = CTxOut()
|
coinbaseoutput = CTxOut()
|
||||||
coinbaseoutput.nValue = nValue * COIN
|
coinbaseoutput.nValue = nValue * COIN
|
||||||
if nValue == 50:
|
if nValue == 50:
|
||||||
halvings = int(height / retarget_period)
|
halvings = int(height / halving_period)
|
||||||
coinbaseoutput.nValue >>= halvings
|
coinbaseoutput.nValue >>= halvings
|
||||||
coinbaseoutput.nValue += fees
|
coinbaseoutput.nValue += fees
|
||||||
if pubkey is not None:
|
if pubkey is not None:
|
||||||
|
|
Loading…
Reference in New Issue