Skip to content

Commit

Permalink
fix: 0-initialize pubkey arrays to avoid non-deterministic data for c…
Browse files Browse the repository at this point in the history
…ompressed pubkeys

BREAKING CHANGE: Reparsing the blockchain is strongly recommended.

In v0.6 the format of raw pubkeys was changed from a dedicated class (CPubKey) to an array (std::array<unsigned char, 65>). The dedicated class handled compressed pubkeys with 33 bytes correctly, while the new array left the remaining bytes uninitialized. This caused non-deterministic parser outputs and incorrect handling of multisig addresses.

Closes #367
  • Loading branch information
mplattner authored and maltemoeser committed Jan 31, 2020
1 parent bccf558 commit fc34ac3
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 5 deletions.
18 changes: 15 additions & 3 deletions include/blocksci/core/script_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <blocksci/blocksci_export.h>
#include <blocksci/core/bitcoin_uint256.hpp>
#include <blocksci/core/raw_address.hpp>
#include <blocksci/scripts/bitcoin_pubkey.hpp>

#include <array>
#include <limits>
Expand Down Expand Up @@ -107,8 +108,16 @@ namespace blocksci {
};
bool hasPubkey;

PubkeyData(uint32_t txNum, const RawPubkey &pubkey_) : ScriptDataBase(txNum), pubkey(pubkey_), hasPubkey(true) {}
PubkeyData(uint32_t txNum, const uint160 &address_) : ScriptDataBase(txNum), address(address_), hasPubkey(false) {}
PubkeyData(uint32_t txNum, const RawPubkey &pubkey_) : ScriptDataBase(txNum), hasPubkey(true) {
pubkey.fill(0);
auto itBegin = pubkey_.begin();
auto itEnd = itBegin + blocksci::CPubKey::GetLen(pubkey_[0]);
std::copy(itBegin, itEnd, pubkey.begin());
}
PubkeyData(uint32_t txNum, const uint160 &address_) : ScriptDataBase(txNum), hasPubkey(false) {
pubkey.fill(0);
address = address_;
}

size_t size() {
return sizeof(PubkeyData);
Expand All @@ -123,7 +132,10 @@ namespace blocksci {
RawAddress wrappedAddress;
bool isSegwit;

ScriptHashData(uint32_t txNum, uint160 hash160_, const RawAddress &wrappedAddress_) : ScriptDataBase(txNum), hash160(hash160_), wrappedAddress(wrappedAddress_), isSegwit(false) {}
ScriptHashData(uint32_t txNum, uint160 hash160_, const RawAddress &wrappedAddress_) : ScriptDataBase(txNum), wrappedAddress(wrappedAddress_), isSegwit(false) {
hash256.SetNull();
hash160 = hash160_;
}

ScriptHashData(uint32_t txNum, uint256 hash256_, const RawAddress &wrappedAddress_) : ScriptDataBase(txNum), hash256(hash256_), wrappedAddress(wrappedAddress_), isSegwit(true) {}

Expand Down
2 changes: 2 additions & 0 deletions tools/parser/script_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void ScriptInputData<blocksci::AddressType::Enum::SCRIPTHASH>::check(AddressStat
}

ScriptInputData<blocksci::AddressType::Enum::PUBKEYHASH>::ScriptInputData(const InputView &inputView, const blocksci::CScriptView &scriptView, const RawTransaction &, const SpendData<blocksci::AddressType::Enum::PUBKEYHASH> &) {
pubkey.fill(0);
if (scriptView.size() > 0) {
auto pc = scriptView.begin();
blocksci::opcodetype opcode = blocksci::OP_0;
Expand Down Expand Up @@ -173,6 +174,7 @@ ScriptInputData<blocksci::AddressType::Enum::NULL_DATA>::ScriptInputData(const I
}

ScriptInputData<blocksci::AddressType::Enum::WITNESS_PUBKEYHASH>::ScriptInputData(const InputView &inputView, const blocksci::CScriptView &, const RawTransaction &, const SpendData<blocksci::AddressType::Enum::WITNESS_PUBKEYHASH> &) {
pubkey.fill(0);
auto &pubkeyWitness = inputView.witnessStack[1];
std::copy(reinterpret_cast<const unsigned char *>(pubkeyWitness.itemBegin), reinterpret_cast<const unsigned char *>(pubkeyWitness.itemBegin) + pubkeyWitness.length, pubkey.begin());
}
Expand Down
2 changes: 2 additions & 0 deletions tools/parser/script_output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ uint32_t AnyScriptOutput::resolve(AddressState &state) {
// MARK: TX_PUBKEY

ScriptOutputData<blocksci::AddressType::Enum::PUBKEY>::ScriptOutputData(const ranges::iterator_range<const unsigned char *> &vch1) {
pubkey.fill(0);
std::copy(vch1.begin(), vch1.end(), pubkey.begin());
}

Expand Down Expand Up @@ -284,6 +285,7 @@ blocksci::uint160 ScriptOutputData<blocksci::AddressType::Enum::MULTISIG>::getHa

void ScriptOutputData<blocksci::AddressType::Enum::MULTISIG>::addAddress(const ranges::iterator_range<const unsigned char *> &vch1) {
blocksci::RawPubkey pubkey;
pubkey.fill(0);
std::copy(vch1.begin(), vch1.end(), pubkey.begin());
addresses.emplace_back(pubkey);
addressCount++;
Expand Down
10 changes: 8 additions & 2 deletions tools/parser/script_output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ struct ScriptOutputData<blocksci::AddressType::Enum::PUBKEY> : public ScriptOutp
blocksci::RawPubkey pubkey;

ScriptOutputData(const ranges::iterator_range<const unsigned char *> &vch1);
ScriptOutputData(const blocksci::RawPubkey &pub) : pubkey(pub) {}
ScriptOutputData(const blocksci::RawPubkey &pub) {
pubkey.fill(0);
pubkey = pub;
}
ScriptOutputData() = default;

blocksci::uint160 getHash() const;
Expand All @@ -91,7 +94,10 @@ struct ScriptOutputData<blocksci::AddressType::Enum::MULTISIG_PUBKEY> : public S
blocksci::RawPubkey pubkey;

ScriptOutputData(const ranges::iterator_range<const unsigned char *> &vch1);
ScriptOutputData(const blocksci::RawPubkey &pub) : pubkey(pub) {}
ScriptOutputData(const blocksci::RawPubkey &pub) {
pubkey.fill(0);
pubkey = pub;
}
ScriptOutputData() = default;

blocksci::uint160 getHash() const;
Expand Down

0 comments on commit fc34ac3

Please sign in to comment.