Set Params::pow_limit to an attainable value not a theoretical one

`cloudhead` on IRC was asking how to properly use
`BlockHeader::validate_pow()` on genesis (or similar) when the
pow_limit field isn't expressible as a compact target (and, thus,
does not actually represent the PoW limit/genesis target). We
swap it for the actual PoW limit by truncating the way a compact
encoding round-trip would.

Note that, in Bitcoin Core, the original value is only ever used
once in its original form:
```
    if (bnNew > bnPowLimit) // Note: bnPowLimit is params.powLimit
        bnNew = bnPowLimit;

    return bnNew.GetCompact();
```
Thus, even if Core adopted our change, as long as there exist no
256-bit integer x which satisfies
`x <= powLimit && x > encoding_roundtrip_truncated(powLimit)` and
`enoding_roundtrip_truncated(x) != powLimit`, the change would have
no impact on consensus.

It is trivial to show that there are no values which are between
the new value
(0x00000000ffff0000000000000000000000000000000000000000000000000000)
and the original value
(0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
which can be encoded in compact form, but it is also critically, no
such values will encode to a compact form of anything different than
the new value as the encoding always truncates the low bits, never
rounding up.
This commit is contained in:
Matt Corallo 2020-08-31 13:58:55 -04:00
parent e8bcde4d38
commit cf45a61070
1 changed files with 22 additions and 15 deletions

View File

@ -20,26 +20,26 @@
use network::constants::Network;
use util::uint::Uint256;
/// Lowest possible difficulty for Mainnet.
/// Lowest possible difficulty for Mainnet. See comment on Params::pow_limit for more info.
const MAX_BITS_BITCOIN: Uint256 = Uint256([
0xffffffffffffffffu64,
0xffffffffffffffffu64,
0xffffffffffffffffu64,
0x00000000ffffffffu64,
0x0000000000000000u64,
0x0000000000000000u64,
0x0000000000000000u64,
0x00000000ffff0000u64,
]);
/// Lowest possible difficulty for Testnet.
/// Lowest possible difficulty for Testnet. See comment on Params::pow_limit for more info.
const MAX_BITS_TESTNET: Uint256 = Uint256([
0xffffffffffffffffu64,
0xffffffffffffffffu64,
0xffffffffffffffffu64,
0x00000000ffffffffu64,
0x0000000000000000u64,
0x0000000000000000u64,
0x0000000000000000u64,
0x00000000ffff0000u64,
]);
/// Lowest possible difficulty for Regtest.
/// Lowest possible difficulty for Regtest. See comment on Params::pow_limit for more info.
const MAX_BITS_REGTEST: Uint256 = Uint256([
0xffffffffffffffffu64,
0xffffffffffffffffu64,
0xffffffffffffffffu64,
0x7fffffffffffffffu64,
0x0000000000000000u64,
0x0000000000000000u64,
0x0000000000000000u64,
0x7fffff0000000000u64,
]);
#[derive(Debug, Clone)]
@ -62,6 +62,13 @@ pub struct Params {
/// Number of blocks with the same set of rules.
pub miner_confirmation_window: u32,
/// Proof of work limit value. It contains the lowest possible difficulty.
///
/// Note that this value differs from Bitcoin Core's powLimit field in that this value is
/// attainable, but Bitcoin Core's is not. Specifically, because targets in Bitcoin are always
/// rounded to the nearest float expressible in "compact form", not all targets are attainable.
/// Still, this should not affect consensus as the only place where the non-compact form of
/// this is used in Bitcoin Core's consensus algorithm is in comparison and there are no
/// compact-expressible values between Bitcoin Core's and the limit expressed here.
pub pow_limit: Uint256,
/// Expected amount of time to mine one block.
pub pow_target_spacing: u64,