2020-09-22 15:06:12 +08:00
|
|
|
#include"Bitcoin/Tx.hpp"
|
|
|
|
|
#include"Bitcoin/TxId.hpp"
|
|
|
|
|
#include"Bitcoin/le.hpp"
|
|
|
|
|
#include"Bitcoin/varint.hpp"
|
|
|
|
|
#include"Sha256/HasherStream.hpp"
|
|
|
|
|
#include"Sha256/fun.hpp"
|
2020-09-22 16:29:01 +08:00
|
|
|
#include"Util/Str.hpp"
|
2020-09-22 15:06:12 +08:00
|
|
|
#include<algorithm>
|
2020-09-22 16:29:01 +08:00
|
|
|
#include<sstream>
|
2020-09-22 17:42:33 +08:00
|
|
|
#include<stdexcept>
|
2020-09-22 15:06:12 +08:00
|
|
|
|
|
|
|
|
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) {
|
2020-11-17 17:19:08 +08:00
|
|
|
auto len = std::uint64_t();
|
2020-09-22 15:06:12 +08:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2020-11-17 17:19:08 +08:00
|
|
|
v.inputs.resize(std::size_t(len));
|
2020-09-22 15:06:12 +08:00
|
|
|
for (auto& i : v.inputs)
|
|
|
|
|
is >> i;
|
|
|
|
|
|
|
|
|
|
is >> Bitcoin::varint(len);
|
2020-11-17 17:19:08 +08:00
|
|
|
v.outputs.resize(std::size_t(len));
|
2020-09-22 15:06:12 +08:00
|
|
|
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 {
|
|
|
|
|
|
2020-09-22 16:29:01 +08:00
|
|
|
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;
|
2020-09-22 17:42:33 +08:00
|
|
|
if (!is.good())
|
2024-07-25 17:00:18 -07:00
|
|
|
throw Util::BacktraceException<std::invalid_argument>("Bitcoin::Tx: invalid hex string input.");
|
2020-09-22 17:50:58 +08:00
|
|
|
if (is.get() != std::char_traits<char>::eof())
|
2024-07-25 17:00:18 -07:00
|
|
|
throw Util::BacktraceException<std::invalid_argument>("Bitcoin::Tx: input string too long.");
|
2020-09-22 16:29:01 +08:00
|
|
|
}
|
|
|
|
|
|
2020-09-22 15:06:12 +08:00
|
|
|
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())
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-22 17:54:31 +08:00
|
|
|
Tx::operator std::string() const {
|
|
|
|
|
auto os = std::ostringstream();
|
|
|
|
|
os << *this;
|
|
|
|
|
auto str = os.str();
|
|
|
|
|
return Util::Str::hexdump(&str[0], str.size());
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-22 15:06:12 +08:00
|
|
|
}
|