Skip to content

Commit 4cfe6c3

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#18847: compressor: use a prevector in CompressScript serialization [ZAP1]
83a425d compressor: use a prevector in compressed script serialization (William Casarin) Pull request description: This function was doing millions of unnecessary heap allocations during IBD. I'm start to catalog unnecessary heap allocations as a pet project of mine: as-zero-as-possible-alloc IBD. This is one small step. before: ![May01-174536](https://user-images.githubusercontent.com/45598/80850964-9a38de80-8bd3-11ea-8eec-08cd38ee1fa1.png) after: ![May01-174610](https://user-images.githubusercontent.com/45598/80850974-a91f9100-8bd3-11ea-94a1-e2077391f6f4.png) ~should I type alias this?~ *I type aliased it* This is a part of the Zero Allocations Project #18849 (ZAP1). This code came up as a place where many allocations occur. ACKs for top commit: Empact: ACK bitcoin/bitcoin@83a425d elichai: tACK 83a425d sipa: utACK 83a425d Tree-SHA512: f0ffa6ab0ea1632715b0b76362753f9f6935f05cdcc80d85566774401155a3c57ad45a687942a1806d3503858f0bb698da9243746c8e2edb8fdf13611235b0e0
2 parents 328da33 + 83a425d commit 4cfe6c3

File tree

4 files changed

+27
-13
lines changed

4 files changed

+27
-13
lines changed

src/compressor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static bool IsToPubKey(const CScript& script, CPubKey &pubkey)
5252
return false;
5353
}
5454

55-
bool CompressScript(const CScript& script, std::vector<unsigned char> &out)
55+
bool CompressScript(const CScript& script, CompressedScript& out)
5656
{
5757
CKeyID keyID;
5858
if (IsToKeyID(script, keyID)) {
@@ -92,7 +92,7 @@ unsigned int GetSpecialScriptSize(unsigned int nSize)
9292
return 0;
9393
}
9494

95-
bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &in)
95+
bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in)
9696
{
9797
switch(nSize) {
9898
case 0x00:

src/compressor.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,26 @@
66
#ifndef BITCOIN_COMPRESSOR_H
77
#define BITCOIN_COMPRESSOR_H
88

9+
#include <prevector.h>
910
#include <primitives/transaction.h>
1011
#include <script/script.h>
1112
#include <serialize.h>
1213
#include <span.h>
1314

14-
bool CompressScript(const CScript& script, std::vector<unsigned char> &out);
15+
/**
16+
* This saves us from making many heap allocations when serializing
17+
* and deserializing compressed scripts.
18+
*
19+
* This prevector size is determined by the largest .resize() in the
20+
* CompressScript function. The largest compressed script format is a
21+
* compressed public key, which is 33 bytes.
22+
*/
23+
using CompressedScript = prevector<33, unsigned char>;
24+
25+
26+
bool CompressScript(const CScript& script, CompressedScript& out);
1527
unsigned int GetSpecialScriptSize(unsigned int nSize);
16-
bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &out);
28+
bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in);
1729

1830
/**
1931
* Compress amount.
@@ -51,7 +63,7 @@ struct ScriptCompression
5163

5264
template<typename Stream>
5365
void Ser(Stream &s, const CScript& script) {
54-
std::vector<unsigned char> compr;
66+
CompressedScript compr;
5567
if (CompressScript(script, compr)) {
5668
s << MakeSpan(compr);
5769
return;
@@ -66,7 +78,7 @@ struct ScriptCompression
6678
unsigned int nSize = 0;
6779
s >> VARINT(nSize);
6880
if (nSize < nSpecialScripts) {
69-
std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00);
81+
CompressedScript vch(GetSpecialScriptSize(nSize), 0x00);
7082
s >> MakeSpan(vch);
7183
DecompressScript(script, nSize, vch);
7284
return;

src/test/compress_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_ckey_id)
7272
CScript script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
7373
BOOST_CHECK_EQUAL(script.size(), 25U);
7474

75-
std::vector<unsigned char> out;
75+
CompressedScript out;
7676
bool done = CompressScript(script, out);
7777
BOOST_CHECK_EQUAL(done, true);
7878

@@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_cscript_id)
8989
script << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
9090
BOOST_CHECK_EQUAL(script.size(), 23U);
9191

92-
std::vector<unsigned char> out;
92+
CompressedScript out;
9393
bool done = CompressScript(script, out);
9494
BOOST_CHECK_EQUAL(done, true);
9595

@@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_compressed_pubkey_id)
107107
CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // COMPRESSED_PUBLIC_KEY_SIZE (33)
108108
BOOST_CHECK_EQUAL(script.size(), 35U);
109109

110-
std::vector<unsigned char> out;
110+
CompressedScript out;
111111
bool done = CompressScript(script, out);
112112
BOOST_CHECK_EQUAL(done, true);
113113

@@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_uncompressed_pubkey_id)
124124
CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // PUBLIC_KEY_SIZE (65)
125125
BOOST_CHECK_EQUAL(script.size(), 67U); // 1 char code + 65 char pubkey + OP_CHECKSIG
126126

127-
std::vector<unsigned char> out;
127+
CompressedScript out;
128128
bool done = CompressScript(script, out);
129129
BOOST_CHECK_EQUAL(done, true);
130130

src/test/fuzz/script.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ FUZZ_TARGET_INIT(script, initialize_script)
4343
if (!script_opt) return;
4444
const CScript script{*script_opt};
4545

46-
std::vector<unsigned char> compressed;
46+
CompressedScript compressed;
4747
if (CompressScript(script, compressed)) {
4848
const unsigned int size = compressed[0];
4949
compressed.erase(compressed.begin());
@@ -143,10 +143,12 @@ FUZZ_TARGET_INIT(script, initialize_script)
143143

144144
{
145145
const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
146+
CompressedScript compressed_script;
147+
compressed_script.assign(bytes.begin(), bytes.end());
146148
// DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
147-
if (bytes.size() >= 32) {
149+
if (compressed_script.size() >= 32) {
148150
CScript decompressed_script;
149-
DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes);
151+
DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script);
150152
}
151153
}
152154

0 commit comments

Comments
 (0)