mirror of
https://github.com/ZmnSCPxj/clboss.git
synced 2026-08-13 12:33:20 +02:00
121 lines
2.5 KiB
C++
121 lines
2.5 KiB
C++
#include"Bitcoin/Tx.hpp"
|
|
#include"Bitcoin/TxId.hpp"
|
|
#include"Bitcoin/le.hpp"
|
|
#include"Bitcoin/varint.hpp"
|
|
#include"Sha256/HasherStream.hpp"
|
|
#include"Sha256/fun.hpp"
|
|
#include"Util/Str.hpp"
|
|
#include<algorithm>
|
|
#include<sstream>
|
|
#include<stdexcept>
|
|
|
|
std::ostream& operator<<(std::ostream& os, Bitcoin::Tx const& v) {
|
|
os << Bitcoin::le(v.nVersion);
|
|
|
|
/* Should we serialize as segwit? */
|
|
auto segwit = std::any_of
|
|
( v.inputs.begin(), v.inputs.end()
|
|
, [](Bitcoin::TxIn const& i) { return !i.witness.empty(); }
|
|
);
|
|
|
|
if (segwit) {
|
|
/* Flag and marker. */
|
|
os.put(0x00);
|
|
os.put(0x01);
|
|
}
|
|
|
|
os << Bitcoin::varint(v.inputs.size());
|
|
for (auto const& i : v.inputs)
|
|
os << i;
|
|
|
|
os << Bitcoin::varint(v.outputs.size());
|
|
for (auto const& o : v.outputs)
|
|
os << o;
|
|
|
|
if (segwit) {
|
|
for (auto const& i : v.inputs)
|
|
os << i.witness;
|
|
}
|
|
|
|
os << Bitcoin::le(v.nLockTime);
|
|
|
|
return os;
|
|
}
|
|
|
|
std::istream& operator>>(std::istream& is, Bitcoin::Tx& v) {
|
|
auto len = std::uint64_t();
|
|
|
|
is >> Bitcoin::le(v.nVersion)
|
|
>> Bitcoin::varint(len)
|
|
;
|
|
auto segwit = (len == 0);
|
|
|
|
if (segwit) {
|
|
/* Marker and *actual* length. */
|
|
if (is.get() != 0x01) {
|
|
is.setstate(std::ios_base::failbit);
|
|
return is;
|
|
}
|
|
is >> Bitcoin::varint(len);
|
|
}
|
|
v.inputs.resize(std::size_t(len));
|
|
for (auto& i : v.inputs)
|
|
is >> i;
|
|
|
|
is >> Bitcoin::varint(len);
|
|
v.outputs.resize(std::size_t(len));
|
|
for (auto& o : v.outputs)
|
|
is >> o;
|
|
|
|
if (segwit) {
|
|
for (auto& i : v.inputs)
|
|
is >> i.witness;
|
|
} else {
|
|
for (auto& i : v.inputs)
|
|
i.witness.witnesses.clear();
|
|
}
|
|
|
|
is >> Bitcoin::le(v.nLockTime);
|
|
|
|
return is;
|
|
}
|
|
|
|
namespace Bitcoin {
|
|
|
|
Tx::Tx(std::string const& s) {
|
|
auto buf = Util::Str::hexread(s);
|
|
auto str = std::string(buf.begin(), buf.end());
|
|
auto is = std::istringstream(std::move(str));
|
|
is >> *this;
|
|
if (!is.good())
|
|
throw Util::BacktraceException<std::invalid_argument>("Bitcoin::Tx: invalid hex string input.");
|
|
if (is.get() != std::char_traits<char>::eof())
|
|
throw Util::BacktraceException<std::invalid_argument>("Bitcoin::Tx: input string too long.");
|
|
}
|
|
|
|
Bitcoin::TxId Tx::get_txid() const {
|
|
/* Copy this, then strip witnesses.
|
|
* Inefficient, but easy.
|
|
*/
|
|
auto tmp = *this;
|
|
for (auto& i : tmp.inputs)
|
|
i.witness.witnesses.clear();
|
|
|
|
/* Create a sha256 hasher stream. */
|
|
Sha256::HasherStream hasher;
|
|
hasher << tmp;
|
|
|
|
/* Double-hash. */
|
|
return Bitcoin::TxId(
|
|
Sha256::fun(std::move(hasher).finalize())
|
|
);
|
|
}
|
|
|
|
Tx::operator std::string() const {
|
|
auto os = std::ostringstream();
|
|
os << *this;
|
|
auto str = os.str();
|
|
return Util::Str::hexdump(&str[0], str.size());
|
|
}
|
|
|
|
}
|