Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move vote class code to a separate file #4338

Merged
merged 2 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nano/secure/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ add_library(
network_filter.cpp
utility.hpp
utility.cpp
vote.hpp
vote.cpp
working.hpp)

target_link_libraries(secure nano_lib ed25519 crypto_lib Boost::system)
Expand Down
185 changes: 0 additions & 185 deletions nano/secure/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,191 +430,6 @@ nano::block_info::block_info (nano::account const & account_a, nano::amount cons
{
}

bool nano::vote::operator== (nano::vote const & other_a) const
{
return timestamp_m == other_a.timestamp_m && hashes == other_a.hashes && account == other_a.account && signature == other_a.signature;
}

bool nano::vote::operator!= (nano::vote const & other_a) const
{
return !(*this == other_a);
}

void nano::vote::serialize_json (boost::property_tree::ptree & tree) const
{
tree.put ("account", account.to_account ());
tree.put ("signature", signature.number ());
tree.put ("sequence", std::to_string (timestamp ()));
tree.put ("timestamp", std::to_string (timestamp ()));
tree.put ("duration", std::to_string (duration_bits ()));
boost::property_tree::ptree blocks_tree;
for (auto const & hash : hashes)
{
boost::property_tree::ptree entry;
entry.put ("", hash.to_string ());
blocks_tree.push_back (std::make_pair ("", entry));
}
tree.add_child ("blocks", blocks_tree);
}

std::string nano::vote::to_json () const
{
std::stringstream stream;
boost::property_tree::ptree tree;
serialize_json (tree);
boost::property_tree::write_json (stream, tree);
return stream.str ();
}

/**
* Returns the timestamp of the vote (with the duration bits masked, set to zero)
* If it is a final vote, all the bits including duration bits are returned as they are, all FF
*/
uint64_t nano::vote::timestamp () const
{
return (timestamp_m == std::numeric_limits<uint64_t>::max ())
? timestamp_m // final vote
: (timestamp_m & timestamp_mask);
}

uint8_t nano::vote::duration_bits () const
{
// Duration field is specified in the 4 low-order bits of the timestamp.
// This makes the timestamp have a minimum granularity of 16ms
// The duration is specified as 2^(duration + 4) giving it a range of 16-524,288ms in power of two increments
auto result = timestamp_m & ~timestamp_mask;
debug_assert (result < 16);
return static_cast<uint8_t> (result);
}

std::chrono::milliseconds nano::vote::duration () const
{
return std::chrono::milliseconds{ 1u << (duration_bits () + 4) };
}

nano::vote::vote (nano::vote const & other_a) :
timestamp_m{ other_a.timestamp_m },
hashes{ other_a.hashes },
account (other_a.account),
signature (other_a.signature)
{
}

nano::vote::vote (bool & error_a, nano::stream & stream_a)
{
error_a = deserialize (stream_a);
}

nano::vote::vote (nano::account const & account_a, nano::raw_key const & prv_a, uint64_t timestamp_a, uint8_t duration, std::vector<nano::block_hash> const & hashes) :
hashes{ hashes },
timestamp_m{ packed_timestamp (timestamp_a, duration) },
account (account_a)
{
signature = nano::sign_message (prv_a, account_a, hash ());
}

std::string nano::vote::hashes_string () const
{
std::string result;
for (auto const & hash : hashes)
{
result += hash.to_string ();
result += ", ";
}
return result;
}

std::string const nano::vote::hash_prefix = "vote ";

nano::block_hash nano::vote::hash () const
{
nano::block_hash result;
blake2b_state hash;
blake2b_init (&hash, sizeof (result.bytes));
blake2b_update (&hash, hash_prefix.data (), hash_prefix.size ());
for (auto const & block_hash : hashes)
{
blake2b_update (&hash, block_hash.bytes.data (), sizeof (block_hash.bytes));
}
union
{
uint64_t qword;
std::array<uint8_t, 8> bytes;
};
qword = timestamp_m;
blake2b_update (&hash, bytes.data (), sizeof (bytes));
blake2b_final (&hash, result.bytes.data (), sizeof (result.bytes));
return result;
}

nano::block_hash nano::vote::full_hash () const
{
nano::block_hash result;
blake2b_state state;
blake2b_init (&state, sizeof (result.bytes));
blake2b_update (&state, hash ().bytes.data (), sizeof (hash ().bytes));
blake2b_update (&state, account.bytes.data (), sizeof (account.bytes.data ()));
blake2b_update (&state, signature.bytes.data (), sizeof (signature.bytes.data ()));
blake2b_final (&state, result.bytes.data (), sizeof (result.bytes));
return result;
}

void nano::vote::serialize (nano::stream & stream_a) const
{
write (stream_a, account);
write (stream_a, signature);
write (stream_a, boost::endian::native_to_little (timestamp_m));
for (auto const & hash : hashes)
{
write (stream_a, hash);
}
}

bool nano::vote::deserialize (nano::stream & stream_a)
{
auto error = false;
try
{
nano::read (stream_a, account.bytes);
nano::read (stream_a, signature.bytes);
nano::read (stream_a, timestamp_m);

while (stream_a.in_avail () > 0)
{
nano::block_hash block_hash;
nano::read (stream_a, block_hash);
hashes.push_back (block_hash);
}
}
catch (std::runtime_error const &)
{
error = true;
}
return error;
}

bool nano::vote::validate () const
{
return nano::validate_message (account, hash (), signature);
}

uint64_t nano::vote::packed_timestamp (uint64_t timestamp, uint8_t duration) const
{
debug_assert (duration <= duration_max && "Invalid duration");
debug_assert ((!(timestamp == timestamp_max) || (duration == duration_max)) && "Invalid final vote");
return (timestamp & timestamp_mask) | duration;
}

bool nano::vote::is_final_timestamp (uint64_t timestamp)
{
return timestamp == std::numeric_limits<uint64_t>::max ();
}

nano::block_hash nano::iterate_vote_blocks_as_hash::operator() (nano::block_hash const & item) const
{
return item;
}

nano::vote_uniquer::vote_uniquer (nano::block_uniquer & uniquer_a) :
uniquer (uniquer_a)
{
Expand Down
59 changes: 1 addition & 58 deletions nano/secure/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <nano/lib/stats.hpp>
#include <nano/lib/timer.hpp>
#include <nano/lib/utility.hpp>
#include <nano/secure/vote.hpp>

#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional/optional.hpp>
Expand Down Expand Up @@ -243,64 +244,6 @@ namespace confirmation_height
uint64_t const unbounded_cutoff{ 16384 };
}

using vote_blocks_vec_iter = std::vector<nano::block_hash>::const_iterator;
class iterate_vote_blocks_as_hash final
{
public:
iterate_vote_blocks_as_hash () = default;
nano::block_hash operator() (nano::block_hash const & item) const;
};
class vote final
{
public:
vote () = default;
vote (nano::vote const &);
vote (bool &, nano::stream &);
vote (nano::account const &, nano::raw_key const &, nano::millis_t timestamp, uint8_t duration, std::vector<nano::block_hash> const &);
std::string hashes_string () const;
nano::block_hash hash () const;
nano::block_hash full_hash () const;
bool operator== (nano::vote const &) const;
bool operator!= (nano::vote const &) const;
void serialize (nano::stream &) const;
void serialize_json (boost::property_tree::ptree & tree) const;
/**
* Deserializes a vote from the bytes in `stream'
* Returns true if there was an error
*/
bool deserialize (nano::stream &);
bool validate () const;
boost::transform_iterator<nano::iterate_vote_blocks_as_hash, nano::vote_blocks_vec_iter> begin () const;
boost::transform_iterator<nano::iterate_vote_blocks_as_hash, nano::vote_blocks_vec_iter> end () const;
std::string to_json () const;
uint64_t timestamp () const;
uint8_t duration_bits () const;
std::chrono::milliseconds duration () const;

static uint64_t constexpr timestamp_mask = { 0xffff'ffff'ffff'fff0ULL };
static nano::seconds_t constexpr timestamp_max = { 0xffff'ffff'ffff'fff0ULL };
static uint64_t constexpr timestamp_min = { 0x0000'0000'0000'0010ULL };
static uint8_t constexpr duration_max = { 0x0fu };

/* Check if timestamp represents a final vote */
static bool is_final_timestamp (uint64_t timestamp);

private:
// Vote timestamp
uint64_t timestamp_m;

public:
// The hashes for which this vote directly covers
std::vector<nano::block_hash> hashes;
// Account that's voting
nano::account account;
// Signature of timestamp + block hashes
nano::signature signature;
static std::string const hash_prefix;

private:
uint64_t packed_timestamp (uint64_t timestamp, uint8_t duration) const;
};
/**
* This class serves to find and return unique variants of a vote in order to minimize memory usage
*/
Expand Down
Loading
Loading