diff options
author | MarcoFalke <falke.marco@gmail.com> | 2021-04-28 21:13:36 +0200 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2021-04-28 21:13:44 +0200 |
commit | 4cfe6c37d956be58e6228f50833d25b84aafe55a (patch) | |
tree | e9328b9c4f10c2aec180a6442169f37c7a14c3ad /src | |
parent | 328da3355787e76184d6bb16e6cf04eca760cbc6 (diff) | |
parent | 83a425d25af033086744c1c8c892015014ed46bd (diff) | |
download | bitcoin-4cfe6c37d956be58e6228f50833d25b84aafe55a.tar.xz |
Merge bitcoin/bitcoin#18847: compressor: use a prevector in CompressScript serialization [ZAP1]
83a425d25af033086744c1c8c892015014ed46bd 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 https://github.com/bitcoin/bitcoin/pull/18847/commits/83a425d25af033086744c1c8c892015014ed46bd
elichai:
tACK 83a425d25af033086744c1c8c892015014ed46bd
sipa:
utACK 83a425d25af033086744c1c8c892015014ed46bd
Tree-SHA512: f0ffa6ab0ea1632715b0b76362753f9f6935f05cdcc80d85566774401155a3c57ad45a687942a1806d3503858f0bb698da9243746c8e2edb8fdf13611235b0e0
Diffstat (limited to 'src')
-rw-r--r-- | src/compressor.cpp | 4 | ||||
-rw-r--r-- | src/compressor.h | 20 | ||||
-rw-r--r-- | src/test/compress_tests.cpp | 8 | ||||
-rw-r--r-- | src/test/fuzz/script.cpp | 8 |
4 files changed, 27 insertions, 13 deletions
diff --git a/src/compressor.cpp b/src/compressor.cpp index a70306d320..ef3135e7a5 100644 --- a/src/compressor.cpp +++ b/src/compressor.cpp @@ -52,7 +52,7 @@ static bool IsToPubKey(const CScript& script, CPubKey &pubkey) return false; } -bool CompressScript(const CScript& script, std::vector<unsigned char> &out) +bool CompressScript(const CScript& script, CompressedScript& out) { CKeyID keyID; if (IsToKeyID(script, keyID)) { @@ -92,7 +92,7 @@ unsigned int GetSpecialScriptSize(unsigned int nSize) return 0; } -bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &in) +bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in) { switch(nSize) { case 0x00: diff --git a/src/compressor.h b/src/compressor.h index 478bfff0b6..40b2496f06 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -6,14 +6,26 @@ #ifndef BITCOIN_COMPRESSOR_H #define BITCOIN_COMPRESSOR_H +#include <prevector.h> #include <primitives/transaction.h> #include <script/script.h> #include <serialize.h> #include <span.h> -bool CompressScript(const CScript& script, std::vector<unsigned char> &out); +/** + * This saves us from making many heap allocations when serializing + * and deserializing compressed scripts. + * + * This prevector size is determined by the largest .resize() in the + * CompressScript function. The largest compressed script format is a + * compressed public key, which is 33 bytes. + */ +using CompressedScript = prevector<33, unsigned char>; + + +bool CompressScript(const CScript& script, CompressedScript& out); unsigned int GetSpecialScriptSize(unsigned int nSize); -bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &out); +bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in); /** * Compress amount. @@ -51,7 +63,7 @@ struct ScriptCompression template<typename Stream> void Ser(Stream &s, const CScript& script) { - std::vector<unsigned char> compr; + CompressedScript compr; if (CompressScript(script, compr)) { s << MakeSpan(compr); return; @@ -66,7 +78,7 @@ struct ScriptCompression unsigned int nSize = 0; s >> VARINT(nSize); if (nSize < nSpecialScripts) { - std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00); + CompressedScript vch(GetSpecialScriptSize(nSize), 0x00); s >> MakeSpan(vch); DecompressScript(script, nSize, vch); return; diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index 4ddbc8338e..7b661a0d1d 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_ckey_id) CScript script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK_EQUAL(script.size(), 25U); - std::vector<unsigned char> out; + CompressedScript out; bool done = CompressScript(script, out); BOOST_CHECK_EQUAL(done, true); @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_cscript_id) script << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; BOOST_CHECK_EQUAL(script.size(), 23U); - std::vector<unsigned char> out; + CompressedScript out; bool done = CompressScript(script, out); BOOST_CHECK_EQUAL(done, true); @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_compressed_pubkey_id) CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // COMPRESSED_PUBLIC_KEY_SIZE (33) BOOST_CHECK_EQUAL(script.size(), 35U); - std::vector<unsigned char> out; + CompressedScript out; bool done = CompressScript(script, out); BOOST_CHECK_EQUAL(done, true); @@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_uncompressed_pubkey_id) CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // PUBLIC_KEY_SIZE (65) BOOST_CHECK_EQUAL(script.size(), 67U); // 1 char code + 65 char pubkey + OP_CHECKSIG - std::vector<unsigned char> out; + CompressedScript out; bool done = CompressScript(script, out); BOOST_CHECK_EQUAL(done, true); diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index c8f95c2980..b87bcf2ef5 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -43,7 +43,7 @@ FUZZ_TARGET_INIT(script, initialize_script) if (!script_opt) return; const CScript script{*script_opt}; - std::vector<unsigned char> compressed; + CompressedScript compressed; if (CompressScript(script, compressed)) { const unsigned int size = compressed[0]; compressed.erase(compressed.begin()); @@ -143,10 +143,12 @@ FUZZ_TARGET_INIT(script, initialize_script) { const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); + CompressedScript compressed_script; + compressed_script.assign(bytes.begin(), bytes.end()); // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short - if (bytes.size() >= 32) { + if (compressed_script.size() >= 32) { CScript decompressed_script; - DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes); + DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script); } } |