diff --git a/src/script/sighashtype.h b/src/script/sighashtype.h index 8d34a51be..477741899 100644 --- a/src/script/sighashtype.h +++ b/src/script/sighashtype.h @@ -1,83 +1,89 @@ // Copyright (c) 2017 Bitcoin ABC developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_HASH_TYPE_H #define BITCOIN_SCRIPT_HASH_TYPE_H #include "serialize.h" #include #include /** Signature hash types/flags */ enum { SIGHASH_ALL = 1, SIGHASH_NONE = 2, SIGHASH_SINGLE = 3, SIGHASH_FORKID = 0x40, SIGHASH_ANYONECANPAY = 0x80, }; /** * Base signature hash types * Base sig hash types not defined in this enum may be used, but they will be * represented as UNSUPPORTED. See transaction * c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73 for an * example where an unsupported base sig hash of 0 was used. */ enum class BaseSigHashType : uint32_t { UNSUPPORTED = 0, ALL = SIGHASH_ALL, NONE = SIGHASH_NONE, SINGLE = SIGHASH_SINGLE }; /** Signature hash type wrapper class */ class SigHashType { private: uint32_t sigHash; public: explicit SigHashType() : sigHash(SIGHASH_ALL) {} explicit SigHashType(uint32_t sigHashIn) : sigHash(sigHashIn) {} SigHashType withBaseType(BaseSigHashType baseSigHashType) const { return SigHashType((sigHash & ~0x1f) | uint32_t(baseSigHashType)); } + SigHashType withForkValue(uint32_t forkId) const { + return SigHashType((forkId << 8) | (sigHash & 0xff)); + } + SigHashType withForkId(bool forkId = true) const { return SigHashType((sigHash & ~SIGHASH_FORKID) | (forkId ? SIGHASH_FORKID : 0)); } SigHashType withAnyoneCanPay(bool anyoneCanPay = true) const { return SigHashType((sigHash & ~SIGHASH_ANYONECANPAY) | (anyoneCanPay ? SIGHASH_ANYONECANPAY : 0)); } BaseSigHashType getBaseType() const { return BaseSigHashType(sigHash & 0x1f); } + uint32_t getForkValue() const { return sigHash >> 8; } + bool hasSupportedBaseType() const { BaseSigHashType baseType = getBaseType(); return baseType >= BaseSigHashType::ALL && baseType <= BaseSigHashType::SINGLE; } bool hasForkId() const { return (sigHash & SIGHASH_FORKID) != 0; } bool hasAnyoneCanPay() const { return (sigHash & SIGHASH_ANYONECANPAY) != 0; } uint32_t getRawSigHashType() const { return sigHash; } template void Serialize(Stream &s) const { ::Serialize(s, getRawSigHashType()); } }; #endif // BITCOIN_SCRIPT_HASH_TYPE_H diff --git a/src/test/script_sighashtype_tests.cpp b/src/test/script_sighashtype_tests.cpp index 1cf4538ee..df0fcadb5 100644 --- a/src/test/script_sighashtype_tests.cpp +++ b/src/test/script_sighashtype_tests.cpp @@ -1,117 +1,137 @@ // Copyright (c) 2016 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 "script/sighashtype.h" #include "test/test_bitcoin.h" #include #include BOOST_FIXTURE_TEST_SUITE(script_sighashtype_tests, BasicTestingSetup) static void CheckSigHashType(SigHashType t, BaseSigHashType baseType, - bool hasSupportedBaseType, bool hasForkId, - bool hasAnyoneCanPay) { + bool hasSupportedBaseType, uint32_t forkValue, + bool hasForkId, bool hasAnyoneCanPay) { BOOST_CHECK(t.getBaseType() == baseType); BOOST_CHECK_EQUAL(t.hasSupportedBaseType(), hasSupportedBaseType); + BOOST_CHECK_EQUAL(t.getForkValue(), forkValue); BOOST_CHECK_EQUAL(t.hasForkId(), hasForkId); BOOST_CHECK_EQUAL(t.hasAnyoneCanPay(), hasAnyoneCanPay); } BOOST_AUTO_TEST_CASE(sighash_construction_test) { // Check default values. - CheckSigHashType(SigHashType(), BaseSigHashType::ALL, true, false, false); + CheckSigHashType(SigHashType(), BaseSigHashType::ALL, true, 0, false, + false); // Check all possible permutations. std::set baseTypes{ BaseSigHashType::UNSUPPORTED, BaseSigHashType::ALL, BaseSigHashType::NONE, BaseSigHashType::SINGLE}; + std::set forkValues{0, 1, 0x123456, 0xfedcba, 0xffffff}; std::set forkIdFlagValues{false, true}; std::set anyoneCanPayFlagValues{false, true}; for (BaseSigHashType baseType : baseTypes) { - for (bool hasForkId : forkIdFlagValues) { - for (bool hasAnyoneCanPay : anyoneCanPayFlagValues) { - SigHashType t = SigHashType() - .withBaseType(baseType) - .withForkId(hasForkId) - .withAnyoneCanPay(hasAnyoneCanPay); - - bool hasSupportedBaseType = - baseType != BaseSigHashType::UNSUPPORTED; - CheckSigHashType(t, baseType, hasSupportedBaseType, hasForkId, - hasAnyoneCanPay); - - // Also check all possible alterations. - CheckSigHashType(t.withForkId(hasForkId), baseType, - hasSupportedBaseType, hasForkId, - hasAnyoneCanPay); - CheckSigHashType(t.withForkId(!hasForkId), baseType, - hasSupportedBaseType, !hasForkId, - hasAnyoneCanPay); - CheckSigHashType(t.withAnyoneCanPay(hasAnyoneCanPay), baseType, - hasSupportedBaseType, hasForkId, - hasAnyoneCanPay); - CheckSigHashType(t.withAnyoneCanPay(!hasAnyoneCanPay), baseType, - hasSupportedBaseType, hasForkId, - !hasAnyoneCanPay); - - for (BaseSigHashType newBaseType : baseTypes) { - bool hasSupportedNewBaseType = - newBaseType != BaseSigHashType::UNSUPPORTED; - CheckSigHashType(t.withBaseType(newBaseType), newBaseType, - hasSupportedNewBaseType, hasForkId, + for (uint32_t forkValue : forkValues) { + for (bool hasForkId : forkIdFlagValues) { + for (bool hasAnyoneCanPay : anyoneCanPayFlagValues) { + SigHashType t = SigHashType() + .withBaseType(baseType) + .withForkValue(forkValue) + .withForkId(hasForkId) + .withAnyoneCanPay(hasAnyoneCanPay); + + bool hasSupportedBaseType = + baseType != BaseSigHashType::UNSUPPORTED; + CheckSigHashType(t, baseType, hasSupportedBaseType, + forkValue, hasForkId, hasAnyoneCanPay); + + // Also check all possible alterations. + CheckSigHashType(t.withForkId(hasForkId), baseType, + hasSupportedBaseType, forkValue, hasForkId, hasAnyoneCanPay); + CheckSigHashType(t.withForkId(!hasForkId), baseType, + hasSupportedBaseType, forkValue, + !hasForkId, hasAnyoneCanPay); + CheckSigHashType(t.withAnyoneCanPay(hasAnyoneCanPay), + baseType, hasSupportedBaseType, forkValue, + hasForkId, hasAnyoneCanPay); + CheckSigHashType(t.withAnyoneCanPay(!hasAnyoneCanPay), + baseType, hasSupportedBaseType, forkValue, + hasForkId, !hasAnyoneCanPay); + + for (BaseSigHashType newBaseType : baseTypes) { + bool hasSupportedNewBaseType = + newBaseType != BaseSigHashType::UNSUPPORTED; + CheckSigHashType(t.withBaseType(newBaseType), + newBaseType, hasSupportedNewBaseType, + forkValue, hasForkId, hasAnyoneCanPay); + } + + for (uint32_t newForkValue : forkValues) { + CheckSigHashType(t.withForkValue(newForkValue), + baseType, hasSupportedBaseType, + newForkValue, hasForkId, + hasAnyoneCanPay); + } } } } } } BOOST_AUTO_TEST_CASE(sighash_serialization_test) { - // Test all possible base sig hash values + std::set forkValues{0, 1, 0xab1fe9, 0xc81eea, 0xffffff}; + + // Test all possible base sig hash values. for (uint32_t baseType = 0; baseType <= 0x1f; baseType++) { - bool hasSupportedBaseType = - (baseType != 0) && (baseType <= SIGHASH_SINGLE); - - SigHashType tbase(baseType); - SigHashType tforkid(baseType | SIGHASH_FORKID); - SigHashType tanyonecanspend(baseType | SIGHASH_ANYONECANPAY); - SigHashType tboth(baseType | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); - - // Check deserialization. - CheckSigHashType(tbase, BaseSigHashType(baseType), hasSupportedBaseType, - false, false); - CheckSigHashType(tforkid, BaseSigHashType(baseType), - hasSupportedBaseType, true, false); - CheckSigHashType(tanyonecanspend, BaseSigHashType(baseType), - hasSupportedBaseType, false, true); - CheckSigHashType(tboth, BaseSigHashType(baseType), hasSupportedBaseType, - true, true); - - // Check raw value. - BOOST_CHECK_EQUAL(tbase.getRawSigHashType(), baseType); - BOOST_CHECK_EQUAL(tforkid.getRawSigHashType(), - baseType | SIGHASH_FORKID); - BOOST_CHECK_EQUAL(tanyonecanspend.getRawSigHashType(), - baseType | SIGHASH_ANYONECANPAY); - BOOST_CHECK_EQUAL(tboth.getRawSigHashType(), - baseType | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); - - // Check serialization/deserialization. - uint32_t unserializedOutput; - (CDataStream(SER_DISK, 0) << tbase) >> unserializedOutput; - BOOST_CHECK_EQUAL(unserializedOutput, baseType); - (CDataStream(SER_DISK, 0) << tforkid) >> unserializedOutput; - BOOST_CHECK_EQUAL(unserializedOutput, baseType | SIGHASH_FORKID); - (CDataStream(SER_DISK, 0) << tanyonecanspend) >> unserializedOutput; - BOOST_CHECK_EQUAL(unserializedOutput, baseType | SIGHASH_ANYONECANPAY); - (CDataStream(SER_DISK, 0) << tboth) >> unserializedOutput; - BOOST_CHECK_EQUAL(unserializedOutput, - baseType | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); + for (uint32_t forkValue : forkValues) { + bool hasSupportedBaseType = + (baseType != 0) && (baseType <= SIGHASH_SINGLE); + + uint32_t rawType = baseType | (forkValue << 8); + + SigHashType tbase(rawType); + SigHashType tforkid(rawType | SIGHASH_FORKID); + SigHashType tanyonecanspend(rawType | SIGHASH_ANYONECANPAY); + SigHashType tboth(rawType | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); + + // Check deserialization. + CheckSigHashType(tbase, BaseSigHashType(baseType), + hasSupportedBaseType, forkValue, false, false); + CheckSigHashType(tforkid, BaseSigHashType(baseType), + hasSupportedBaseType, forkValue, true, false); + CheckSigHashType(tanyonecanspend, BaseSigHashType(baseType), + hasSupportedBaseType, forkValue, false, true); + CheckSigHashType(tboth, BaseSigHashType(baseType), + hasSupportedBaseType, forkValue, true, true); + + // Check raw value. + BOOST_CHECK_EQUAL(tbase.getRawSigHashType(), rawType); + BOOST_CHECK_EQUAL(tforkid.getRawSigHashType(), + rawType | SIGHASH_FORKID); + BOOST_CHECK_EQUAL(tanyonecanspend.getRawSigHashType(), + rawType | SIGHASH_ANYONECANPAY); + BOOST_CHECK_EQUAL(tboth.getRawSigHashType(), + rawType | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); + + // Check serialization/deserialization. + uint32_t unserializedOutput; + (CDataStream(SER_DISK, 0) << tbase) >> unserializedOutput; + BOOST_CHECK_EQUAL(unserializedOutput, rawType); + (CDataStream(SER_DISK, 0) << tforkid) >> unserializedOutput; + BOOST_CHECK_EQUAL(unserializedOutput, rawType | SIGHASH_FORKID); + (CDataStream(SER_DISK, 0) << tanyonecanspend) >> unserializedOutput; + BOOST_CHECK_EQUAL(unserializedOutput, + rawType | SIGHASH_ANYONECANPAY); + (CDataStream(SER_DISK, 0) << tboth) >> unserializedOutput; + BOOST_CHECK_EQUAL(unserializedOutput, + rawType | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); + } } } BOOST_AUTO_TEST_SUITE_END()