Skip to content

Commit

Permalink
Move compressor utility functions out of class
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa authored and furszy committed Jul 3, 2021
1 parent 7376a95 commit 3e38199
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 40 deletions.
30 changes: 19 additions & 11 deletions src/compressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
#include "pubkey.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 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
memcpy(&hash, &script[3], 20);
Expand All @@ -19,7 +27,7 @@ bool CScriptCompressor::IsToKeyID(CKeyID& hash) const
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 && script[22] == OP_EQUAL) {
memcpy(&hash, &script[2], 20);
Expand All @@ -28,7 +36,7 @@ bool CScriptCompressor::IsToScriptID(CScriptID& hash) const
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 && (script[1] == 0x02 || script[1] == 0x03)) {
pubkey.Set(&script[1], &script[34]);
Expand All @@ -41,24 +49,24 @@ bool CScriptCompressor::IsToPubKey(CPubKey& pubkey) const
return false;
}

bool CScriptCompressor::Compress(std::vector<unsigned char>& out) const
bool CompressScript(const CScript& script, std::vector<unsigned char> &out)
{
CKeyID keyID;
if (IsToKeyID(keyID)) {
if (IsToKeyID(script, keyID)) {
out.resize(21);
out[0] = 0x00;
memcpy(&out[1], &keyID, 20);
return true;
}
CScriptID scriptID;
if (IsToScriptID(scriptID)) {
if (IsToScriptID(script, scriptID)) {
out.resize(21);
out[0] = 0x01;
memcpy(&out[1], &scriptID, 20);
return true;
}
CPubKey pubkey;
if (IsToPubKey(pubkey)) {
if (IsToPubKey(script, pubkey)) {
out.resize(33);
memcpy(&out[1], &pubkey[1], 32);
if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
Expand All @@ -72,7 +80,7 @@ bool CScriptCompressor::Compress(std::vector<unsigned char>& out) const
return false;
}

unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
unsigned int GetSpecialScriptSize(unsigned int nSize)
{
if (nSize == 0 || nSize == 1)
return 20;
Expand All @@ -81,7 +89,7 @@ unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
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) {
case 0x00:
Expand Down Expand Up @@ -135,7 +143,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
// (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)
return 0;
Expand All @@ -154,7 +162,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
if (x == 0)
Expand Down
37 changes: 12 additions & 25 deletions src/compressor.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ class CKeyID;
class CPubKey;
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.
*
* It detects common cases and encodes them much more efficiently.
Expand All @@ -38,32 +45,15 @@ class CScriptCompressor
*/
static const unsigned int nSpecialScripts = 6;

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);

CScript &script;
public:
CScriptCompressor(CScript& scriptIn) : script(scriptIn) {}

template <typename Stream>
void Serialize(Stream& s) const
{
std::vector<unsigned char> compr;
if (Compress(compr)) {
if (CompressScript(script, compr)) {
s << MakeSpan(compr);
return;
}
Expand All @@ -78,9 +68,9 @@ class CScriptCompressor
unsigned int nSize = 0;
s >> VARINT(nSize);
if (nSize < nSpecialScripts) {
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00);
s >> MakeSpan(vch);
Decompress(nSize, vch);
DecompressScript(script, nSize, vch);
return;
}
nSize -= nSpecialScripts;
Expand All @@ -102,10 +92,7 @@ class CTxOutCompressor
CTxOut& txout;

public:
static uint64_t CompressAmount(uint64_t nAmount);
static uint64_t DecompressAmount(uint64_t nAmount);

CTxOutCompressor(CTxOut& txoutIn) : txout(txoutIn) {}
explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }

ADD_SERIALIZE_METHODS;

Expand Down
8 changes: 4 additions & 4 deletions src/test/compress_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@
BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup)

bool static TestEncode(uint64_t in) {
return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in));
return in == DecompressAmount(CompressAmount(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) {
return CTxOutCompressor::CompressAmount(dec) == enc &&
CTxOutCompressor::DecompressAmount(enc) == dec;
return CompressAmount(dec) == enc &&
DecompressAmount(enc) == dec;
}

BOOST_AUTO_TEST_CASE(compress_amounts)
Expand Down

0 comments on commit 3e38199

Please sign in to comment.