Skip to content

Commit

Permalink
Witness.
Browse files Browse the repository at this point in the history
  • Loading branch information
evoskuil committed Jul 15, 2024
1 parent c0422d9 commit 971d5d2
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 22 deletions.
4 changes: 3 additions & 1 deletion include/bitcoin/system/chain/witness.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,11 @@ class BC_API witness
witness(const chunk_cptrs& stack, bool valid, size_t size) NOEXCEPT;

private:
void assign_data(reader& source, bool prefix) NOEXCEPT;
////static witness from_data(reader& source, bool prefix) NOEXCEPT;

// TODO: move to config serialization wrapper.
static witness from_string(const std::string& mnemonic) NOEXCEPT;
static witness from_data(reader& source, bool prefix) NOEXCEPT;

BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
Expand Down
45 changes: 26 additions & 19 deletions src/chain/witness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,15 @@ witness::witness(std::istream& stream, bool prefix) NOEXCEPT
}

witness::witness(reader&& source, bool prefix) NOEXCEPT
: witness(from_data(source, prefix))
: witness(source, prefix/*from_data(source, prefix)*/)
{
}

witness::witness(reader& source, bool prefix) NOEXCEPT
: witness(from_data(source, prefix))
////: witness(from_data(source, prefix))
: stack_(source.arena())
{
assign_data(source, prefix);
}

witness::witness(const std::string& mnemonic) NOEXCEPT
Expand Down Expand Up @@ -162,36 +164,41 @@ void witness::skip(reader& source, bool prefix) NOEXCEPT
}
}

static data_chunk read_element(reader& source) NOEXCEPT
// private
void witness::assign_data(reader& source, bool prefix) NOEXCEPT
{
// Each witness encoded as variable integer prefixed byte array (bip144).
return source.read_bytes(source.read_size(max_block_weight));
}

// static/private
witness witness::from_data(reader& source, bool prefix) NOEXCEPT
{
size_t size{};
chunk_cptrs stack{};
size_ = zero;
const auto& allocator = source.allocator();
////allocator.destroy<chunk_cptrs>(&stack_);
////allocator.construct<chunk_cptrs>(&stack_);

if (prefix)
{
const auto capacity = source.read_size(max_block_weight);
stack.reserve(capacity);
const auto count = source.read_size(max_block_weight);
stack_.reserve(count);

for (size_t element = 0; element < capacity; ++element)
for (size_t element = 0; element < count; ++element)
{
stack.push_back(to_shared<data_chunk>(read_element(source)));
size = element_size(size, stack.back());
const auto size = source.read_size(max_block_weight);
stack_.emplace_back(
source.read_bytes_raw(size),
allocator.deleter<data_chunk>(source.arena()));
size_ = element_size(size_, stack_.back());
}
}
else
{
while (!source.is_exhausted())
stack.push_back(to_shared<data_chunk>(read_element(source)));
{
const auto size = source.read_size(max_block_weight);
stack_.emplace_back(
source.read_bytes_raw(size),
allocator.deleter<data_chunk>(source.arena()));
size_ = element_size(size_, stack_.back());
}
}

return { stack, source, size };
valid_ = source;
}

inline bool is_push_token(const std::string& token) NOEXCEPT
Expand Down
181 changes: 179 additions & 2 deletions test/chain/witness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,187 @@
BOOST_AUTO_TEST_SUITE(witness_tests)

namespace json = boost::json;
using namespace system::chain;

BOOST_AUTO_TEST_CASE(witness_test)
const block& get_block() NOEXCEPT
{
BOOST_REQUIRE(true);
constexpr auto root = base16_hash("1bf6a4281aca254af9dafb696dc1b9ce47d9f0785ebd4622fa0e28104fe3df44");
constexpr uint32_t block_version{ 0 };
constexpr hash_digest previous_block_hash{ 1 };
constexpr hash_digest merkle_root{ root };
constexpr uint32_t timestamp{ 3 };
constexpr uint32_t bits{ 4 };
constexpr uint32_t nonce{ 5 };
constexpr uint32_t tx_version{ 6 };
constexpr uint32_t locktime{ 7 };
constexpr uint32_t sequence{ 8 };
constexpr uint64_t value{ 9 };
constexpr hash_digest point_hash{ 9 };
constexpr uint32_t point_index{ 9 };
constexpr bool minimal{ true };

static const block instance
{
header // ptr<header>
{
block_version,
previous_block_hash,
merkle_root,
timestamp,
bits,
nonce
},
transactions // ptr<vector<tx>>
{
// coinbase
transaction // first tx
{
tx_version,
inputs
{
input // exactly one input
{
point // null point
{
null_hash,
point::null_index
},
script{ operations{ operation{ opcode::nop1 }, operation{ opcode::nop2 } } }, // minumum 2 bytes
sequence
}
},
outputs
{
output // at least one output
{
value, // no more than reward
script{}
}
},
locktime
},
transaction // ptr<tx>
{
tx_version,
inputs // ptr<vector<ptr<input>>>
{
input // ptr<input>
{
point // ptr<point>
{
point_hash,
point_index
},
script // ptr<script>
{
operations // vector<operation>
{
operation
{
opcode::nop3 // ptr<nullptr>
},
operation
{
data_chunk{}, // ptr<data_chunk>
minimal
}
}
},
witness // ptr<witness>
{
data_stack // vector<ptr<data_chunk>>
{
data_chunk{}, // ptr<data_chunk>
data_chunk{} // ptr<data_chunk>
}
},
sequence
}
},
outputs // vector<ptr<output>>
{
output // ptr<output>
{
value,
script // ptr<script>
{
operations // vector<operation>
{
operation
{
opcode::nop4 // ptr<nullptr>
},
operation
{
data_chunk{}, // ptr<data_chunk>
minimal
}
}
}
}
},
locktime
}
}
};

return instance;
}

const data_chunk& get_data(bool witness) NOEXCEPT
{
static const auto data = get_block().to_data(witness);
return data;
}

BOOST_AUTO_TEST_CASE(witness__block__with_witness__parse_round_trips)
{
constexpr auto witness = true;
const auto& instance1 = get_block();
const auto& data = get_data(witness);

const block instance2(data, witness);
BOOST_REQUIRE(instance1.is_valid());
BOOST_REQUIRE(instance2.is_valid());
BOOST_REQUIRE(instance1.hash() == instance2.hash());
BOOST_REQUIRE(instance1 == instance2);
BOOST_REQUIRE(instance1.is_segregated());
BOOST_REQUIRE(instance2.is_segregated());
}

BOOST_AUTO_TEST_CASE(witness__block__genesis_block__arena_parse_round_trips)
{
constexpr auto witness = true;
const auto genesis = settings(selection::mainnet).genesis_block;
const auto data = genesis.to_data(true);

test::reporting_arena<false> arena{};
stream::in::fast stream(data);
read::bytes::fast source(stream, &arena);
const block instance(source, witness);
BOOST_REQUIRE(!instance.check());
}

BOOST_AUTO_TEST_CASE(witness__block__with_witness__checks)
{
constexpr auto witness = true;
test::reporting_arena<false> arena{};
const auto& data = get_data(witness);
stream::in::fast stream(data);
read::bytes::fast source(stream, &arena);
const block instance(source, witness);
BOOST_REQUIRE(!instance.check());
}

BOOST_AUTO_TEST_CASE(witness__block__without_witness__checks)
{
constexpr auto witness = false;
test::reporting_arena<false> arena{};
const auto& data = get_data(witness);
stream::in::fast stream(data);
read::bytes::fast source(stream, &arena);
const block instance(source, witness);
BOOST_REQUIRE(!instance.check());
}

// json
Expand Down

0 comments on commit 971d5d2

Please sign in to comment.