Merge #12752: [MOVEONLY] Move compressor utility functions out of class

76a9aac Move compressor utility functions out of class (Pieter Wuille)

Pull request description:

  This is a refactor from #10785 with no functionality change.

  Move the compresion utility functions out of CScriptCompressor, as a preparation for making the class templated. I'm submitting it as a separate PR as I think it's a general improvement to code readability, and to reduce the diff further on.

Tree-SHA512: 3b3d17c2b96e43f752f512dd573296a6bb15cae165fbe3c79212a0970f5196a62a59a821d5100f29638af1e7461c9171f3dccb8112f005ee08da0ec7fe0073fd
pull/12744/merge
Wladimir J. van der Laan 7 years ago
commit d2d7267e23
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D

@ -9,7 +9,15 @@
#include <pubkey.h> #include <pubkey.h>
#include <script/standard.h> #include <script/standard.h>
bool CScriptCompressor::IsToKeyID(CKeyID &hash) const /*
* These check for scripts for which a special case with a shorter encoding is defined.
* They are implemented separately from the CScript test, as these test for exact byte
* sequence correspondences, and are more strict. For example, IsToPubKey also verifies
* whether the public key is valid (as invalid ones cannot be represented in compressed
* form).
*/
static bool IsToKeyID(const CScript& script, CKeyID &hash)
{ {
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
&& script[2] == 20 && script[23] == OP_EQUALVERIFY && script[2] == 20 && script[23] == OP_EQUALVERIFY
@ -20,7 +28,7 @@ bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
return false; return false;
} }
bool CScriptCompressor::IsToScriptID(CScriptID &hash) const static bool IsToScriptID(const CScript& script, CScriptID &hash)
{ {
if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
&& script[22] == OP_EQUAL) { && script[22] == OP_EQUAL) {
@ -30,7 +38,7 @@ bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
return false; return false;
} }
bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const static bool IsToPubKey(const CScript& script, CPubKey &pubkey)
{ {
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
&& (script[1] == 0x02 || script[1] == 0x03)) { && (script[1] == 0x02 || script[1] == 0x03)) {
@ -45,24 +53,24 @@ bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
return false; return false;
} }
bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const bool CompressScript(const CScript& script, std::vector<unsigned char> &out)
{ {
CKeyID keyID; CKeyID keyID;
if (IsToKeyID(keyID)) { if (IsToKeyID(script, keyID)) {
out.resize(21); out.resize(21);
out[0] = 0x00; out[0] = 0x00;
memcpy(&out[1], &keyID, 20); memcpy(&out[1], &keyID, 20);
return true; return true;
} }
CScriptID scriptID; CScriptID scriptID;
if (IsToScriptID(scriptID)) { if (IsToScriptID(script, scriptID)) {
out.resize(21); out.resize(21);
out[0] = 0x01; out[0] = 0x01;
memcpy(&out[1], &scriptID, 20); memcpy(&out[1], &scriptID, 20);
return true; return true;
} }
CPubKey pubkey; CPubKey pubkey;
if (IsToPubKey(pubkey)) { if (IsToPubKey(script, pubkey)) {
out.resize(33); out.resize(33);
memcpy(&out[1], &pubkey[1], 32); memcpy(&out[1], &pubkey[1], 32);
if (pubkey[0] == 0x02 || pubkey[0] == 0x03) { if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
@ -76,7 +84,7 @@ bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
return false; return false;
} }
unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const unsigned int GetSpecialScriptSize(unsigned int nSize)
{ {
if (nSize == 0 || nSize == 1) if (nSize == 0 || nSize == 1)
return 20; return 20;
@ -85,7 +93,7 @@ unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
return 0; return 0;
} }
bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in) bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &in)
{ {
switch(nSize) { switch(nSize) {
case 0x00: case 0x00:
@ -139,7 +147,7 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 // * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
// (this is decodable, as d is in [1-9] and e is in [0-9]) // (this is decodable, as d is in [1-9] and e is in [0-9])
uint64_t CTxOutCompressor::CompressAmount(uint64_t n) uint64_t CompressAmount(uint64_t n)
{ {
if (n == 0) if (n == 0)
return 0; return 0;
@ -158,7 +166,7 @@ uint64_t CTxOutCompressor::CompressAmount(uint64_t n)
} }
} }
uint64_t CTxOutCompressor::DecompressAmount(uint64_t x) uint64_t DecompressAmount(uint64_t x)
{ {
// x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
if (x == 0) if (x == 0)

@ -14,6 +14,13 @@ class CKeyID;
class CPubKey; class CPubKey;
class CScriptID; class CScriptID;
bool CompressScript(const CScript& script, std::vector<unsigned char> &out);
unsigned int GetSpecialScriptSize(unsigned int nSize);
bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &out);
uint64_t CompressAmount(uint64_t nAmount);
uint64_t DecompressAmount(uint64_t nAmount);
/** Compact serializer for scripts. /** Compact serializer for scripts.
* *
* It detects common cases and encodes them much more efficiently. * It detects common cases and encodes them much more efficiently.
@ -37,28 +44,13 @@ private:
static const unsigned int nSpecialScripts = 6; static const unsigned int nSpecialScripts = 6;
CScript &script; CScript &script;
protected:
/**
* These check for scripts for which a special case with a shorter encoding is defined.
* They are implemented separately from the CScript test, as these test for exact byte
* sequence correspondences, and are more strict. For example, IsToPubKey also verifies
* whether the public key is valid (as invalid ones cannot be represented in compressed
* form).
*/
bool IsToKeyID(CKeyID &hash) const;
bool IsToScriptID(CScriptID &hash) const;
bool IsToPubKey(CPubKey &pubkey) const;
bool Compress(std::vector<unsigned char> &out) const;
unsigned int GetSpecialSize(unsigned int nSize) const;
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
public: public:
explicit CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } explicit CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
template<typename Stream> template<typename Stream>
void Serialize(Stream &s) const { void Serialize(Stream &s) const {
std::vector<unsigned char> compr; std::vector<unsigned char> compr;
if (Compress(compr)) { if (CompressScript(script, compr)) {
s << CFlatData(compr); s << CFlatData(compr);
return; return;
} }
@ -72,9 +64,9 @@ public:
unsigned int nSize = 0; unsigned int nSize = 0;
s >> VARINT(nSize); s >> VARINT(nSize);
if (nSize < nSpecialScripts) { if (nSize < nSpecialScripts) {
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00); std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00);
s >> CFlatData(vch); s >> CFlatData(vch);
Decompress(nSize, vch); DecompressScript(script, nSize, vch);
return; return;
} }
nSize -= nSpecialScripts; nSize -= nSpecialScripts;
@ -96,9 +88,6 @@ private:
CTxOut &txout; CTxOut &txout;
public: public:
static uint64_t CompressAmount(uint64_t nAmount);
static uint64_t DecompressAmount(uint64_t nAmount);
explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { } explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;

@ -25,16 +25,16 @@
BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup)
bool static TestEncode(uint64_t in) { bool static TestEncode(uint64_t in) {
return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in)); return in == DecompressAmount(CompressAmount(in));
} }
bool static TestDecode(uint64_t in) { bool static TestDecode(uint64_t in) {
return in == CTxOutCompressor::CompressAmount(CTxOutCompressor::DecompressAmount(in)); return in == CompressAmount(DecompressAmount(in));
} }
bool static TestPair(uint64_t dec, uint64_t enc) { bool static TestPair(uint64_t dec, uint64_t enc) {
return CTxOutCompressor::CompressAmount(dec) == enc && return CompressAmount(dec) == enc &&
CTxOutCompressor::DecompressAmount(enc) == dec; DecompressAmount(enc) == dec;
} }
BOOST_AUTO_TEST_CASE(compress_amounts) BOOST_AUTO_TEST_CASE(compress_amounts)

Loading…
Cancel
Save