Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor
Browse files Browse the repository at this point in the history
Sjors committed Dec 11, 2023
1 parent 2c86343 commit 743f7d3
Showing 4 changed files with 50 additions and 166 deletions.
146 changes: 38 additions & 108 deletions src/node/sv2_template_provider.cpp
Original file line number Diff line number Diff line change
@@ -131,7 +131,11 @@ void Sv2TemplateProvider::ThreadSv2Handler()
WAIT_LOCK(g_best_block_mutex, lock);
auto checktime = std::chrono::steady_clock::now() + std::chrono::milliseconds(50);
g_best_block_cv.wait_until(lock, checktime);
return m_best_prev_hash.m_prev_hash != g_best_block;
if (m_best_prev_hash.m_prev_hash != g_best_block) {
m_best_prev_hash.m_prev_hash = g_best_block;
return true;
}
return false;
}();

// TODO: this is triggered far more often than necessary, and should
@@ -148,31 +152,14 @@ void Sv2TemplateProvider::ThreadSv2Handler()
// Build a new best template, best prev hash and update the block cache.
should_make_template = true;
template_last_update = mempool_last_update;
} else if (timer.trigger() && mempool_last_update > template_last_update && m_sv2_clients.size() > 0) {
} else if (timer.trigger() && mempool_last_update > template_last_update && !m_sv2_clients.empty()) {
should_make_template = true;
// for (const auto& client : m_sv2_clients) {
// ++m_template_id;
// Sv2Client& c = *client.get();
// should_make_template = true;
// auto new_template = BuildNewTemplate(false, c.m_coinbase_tx_outputs_size, m_template_id);
// m_block_cache.insert({m_template_id, std::move(new_template.block_template)});
// if (!SendTemplate(*client.get(), new_template.new_template)) {
// client->m_disconnect_flag = true;
// continue;
// }
// }
}

if (should_make_template) {
++m_template_id;
auto new_work_set = BuildNewWorkSet(m_default_future_templates, m_default_coinbase_tx_additional_output_size, m_template_id);
m_best_new_template = std::move(new_work_set.new_template);
m_best_prev_hash = std::move(new_work_set.prev_hash);
m_block_cache.insert({m_template_id, std::move(new_work_set.block_template)});

// Update all clients with the new template and prev hash.
for (const auto& client : m_sv2_clients) {
if (!SendWork(*client.get(), m_best_new_template, m_best_prev_hash, m_block_cache, m_template_id)) {
if (!SendWork(*client.get(), /*send_new_prevhash=*/best_block_changed)) {
client->m_disconnect_flag = true;
continue;
}
@@ -239,7 +226,7 @@ void Sv2TemplateProvider::ThreadSv2Handler()

for (auto& m : sv2_msgs)
{
ProcessSv2Message(m, *client.get(), m_best_new_template, m_best_prev_hash, m_block_cache, m_template_id);
ProcessSv2Message(m, *client.get());
}
}
} catch (const std::exception& e) {
@@ -295,7 +282,7 @@ void Sv2TemplateProvider::ProcessSv2Noise(Sv2Client& client, Span<std::byte> buf
}
}

Sv2TemplateProvider::NewWorkSet Sv2TemplateProvider::BuildNewWorkSet(bool future_template, unsigned int coinbase_output_max_additional_size, uint64_t template_id)
Sv2TemplateProvider::NewWorkSet Sv2TemplateProvider::BuildNewWorkSet(bool future_template, unsigned int coinbase_output_max_additional_size)
{
node::BlockAssembler::Options options;

@@ -307,115 +294,55 @@ Sv2TemplateProvider::NewWorkSet Sv2TemplateProvider::BuildNewWorkSet(bool future
auto blocktemplate = node::BlockAssembler(m_chainman.ActiveChainstate(), &m_mempool, options).CreateNewBlock(CScript());
LogPrintLevel(BCLog::SV2, BCLog::Level::Trace, "Assemble template: %.2fms\n",
Ticks<MillisecondsDouble>(SteadyClock::now() - time_start));
node::Sv2NewTemplateMsg new_template{blocktemplate->block, template_id, future_template};
node::Sv2SetNewPrevHashMsg set_new_prev_hash{blocktemplate->block, template_id};
node::Sv2NewTemplateMsg new_template{blocktemplate->block, m_template_id, future_template};
node::Sv2SetNewPrevHashMsg set_new_prev_hash{blocktemplate->block, m_template_id};

return NewWorkSet { new_template, std::move(blocktemplate), set_new_prev_hash};
}

// Sv2TemplateProvider::ReducedWorkSet Sv2TemplateProvider::BuildNewTemplate(bool future_template, unsigned int coinbase_output_max_additional_size, uint64_t template_id)
// {
// node::BlockAssembler::Options options;

// // Reducing the size of nBlockMaxWeight by the coinbase output additional size allows the miner extra weighted bytes in their coinbase space.
// options.nBlockMaxWeight = MAX_BLOCK_WEIGHT - coinbase_output_max_additional_size;
// options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);

// const auto time_start{SteadyClock::now()};
// auto blocktemplate = node::BlockAssembler(m_chainman.ActiveChainstate(), &m_mempool, options).CreateNewBlock(CScript());
// LogPrintLevel(BCLog::SV2, BCLog::Level::Trace, "Assemble template: %.2fms\n",
// Ticks<MillisecondsDouble>(SteadyClock::now() - time_start));

// node::Sv2NewTemplateMsg new_template{blocktemplate->block, template_id, future_template};
// return ReducedWorkSet { new_template, std::move(blocktemplate)};
// }

bool Sv2TemplateProvider::SendTemplate(const Sv2Client& client, const node::Sv2NewTemplateMsg& best_template)
bool Sv2TemplateProvider::SendWork(const Sv2Client& client, bool send_new_prevhash)
{
LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Send 0x71 NewTemplate (id=%d)\n", best_template.m_template_id);
// The current implementation doesn't create templates for future empty
// or speculative blocks. Despite that, we first send NewTemplate with
// future_template set to true, followed by SetNewPrevHash. We do this
// both when first connecting and when a new block is found.
//
// When the template is update to take newer mempool transactions into
// account, we set future_template to false and don't send SetNewPrevHash.

// TODO: reuse template_id for clients with the same m_default_coinbase_tx_additional_output_size
++m_template_id;
auto new_work_set = BuildNewWorkSet(/*future_template=*/send_new_prevhash, client.m_coinbase_tx_outputs_size);
m_block_cache.insert({m_template_id, std::move(new_work_set.block_template)});

try {
auto msg = node::Sv2NetMsg{best_template};
auto msg = node::Sv2NetMsg{new_work_set.new_template};
auto msg_buf = BuildEncryptedHeader(msg, *client.m_noise.get());

if (!SendBuf(client, msg_buf)) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending best NewTemplate message\n");
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending NewTemplate message\n");
return false;
}
} catch (const std::exception& e) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Failed to serialize best new template: %s\n", e.what());
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Failed to serialize new template: %s\n", e.what());
return false;
}

return true;
}

bool Sv2TemplateProvider::SendWork(const Sv2Client& client, const node::Sv2NewTemplateMsg& best_template, const node::Sv2SetNewPrevHashMsg& best_prev_hash, BlockCache& block_cache, uint64_t& template_id)
{
if (client.m_coinbase_tx_outputs_size > 0) {
++template_id;
auto new_work_set = BuildNewWorkSet(m_default_future_templates, client.m_coinbase_tx_outputs_size, template_id);
block_cache.insert({template_id, std::move(new_work_set.block_template)});

LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Send 0x71 NewTemplate (id=%d)\n", template_id);

try {
auto msg = node::Sv2NetMsg{new_work_set.new_template};
auto msg_buf = BuildEncryptedHeader(msg, *client.m_noise.get());

if (!SendBuf(client, msg_buf)) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending Sv2NewTemplate message\n");
return false;
}
} catch (const std::exception& e) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Failed to serialize new template: %s\n", e.what());
return false;
}

if (send_new_prevhash) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Send 0x20 SetNewPrevHash\n");

try {
auto msg = node::Sv2NetMsg{new_work_set.prev_hash};
auto msg_buf = BuildEncryptedHeader(msg, *client.m_noise.get());

if (!SendBuf(client, msg_buf)) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending Sv2SetNewPrevHash message\n");
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending SetNewPrevHash message\n");
return false;
}
} catch (const std::exception& e) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Failed to serialize new prev hash: %s\n", e.what());
return false;
}
} else {
LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Send 0x71 NewTemplate (id=%d)\n", template_id);

try {
auto msg = node::Sv2NetMsg{best_template};
auto msg_buf = BuildEncryptedHeader(msg, *client.m_noise.get());

if (!SendBuf(client, msg_buf)) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending best Sv2NewTemplate message\n");
return false;
}
} catch (const std::exception& e) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Failed to serialize best new template: %s\n", e.what());
return false;
}

try {
auto msg = node::Sv2NetMsg{best_prev_hash};
auto msg_buf = BuildEncryptedHeader(msg, *client.m_noise.get());

LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Send 0x20 SetNewPrevHash\n");

if (!SendBuf(client, msg_buf)) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Error sending best Sv2SetNewPrevHash message\n");
return false;
}
} catch (const std::exception& e) {
LogPrintLevel(BCLog::SV2, BCLog::Level::Error, "Failed to serialize best new prev hash: %s\n", e.what());
return false;
}
}

return true;
@@ -435,7 +362,7 @@ Sock::EventsPerSock Sv2TemplateProvider::GenerateWaitSockets(const std::shared_p
return events_per_sock;
}

void Sv2TemplateProvider::ProcessSv2Message(const node::Sv2NetMsg& sv2_net_msg, Sv2Client& client, const node::Sv2NewTemplateMsg& best_new_template, const node::Sv2SetNewPrevHashMsg& best_prev_hash, BlockCache& block_cache, uint64_t& template_id)
void Sv2TemplateProvider::ProcessSv2Message(const node::Sv2NetMsg& sv2_net_msg, Sv2Client& client)
{
DataStream ss (sv2_net_msg.m_msg);

@@ -544,7 +471,8 @@ void Sv2TemplateProvider::ProcessSv2Message(const node::Sv2NetMsg& sv2_net_msg,

client.m_coinbase_tx_outputs_size = coinbase_output_data_size.m_coinbase_output_max_additional_size;

if (!SendWork(client, best_new_template, best_prev_hash, block_cache, template_id)) {
// Send new template and prevout
if (!SendWork(client, /*send_new_prevhash=*/true)) {
return;
}

@@ -566,8 +494,8 @@ void Sv2TemplateProvider::ProcessSv2Message(const node::Sv2NetMsg& sv2_net_msg,
return;
}

auto cached_block = block_cache.find(submit_solution.m_template_id);
if (cached_block != block_cache.end()) {
auto cached_block = m_block_cache.find(submit_solution.m_template_id);
if (cached_block != m_block_cache.end()) {
CBlock& block = (*cached_block->second).block;

auto coinbase_tx = CTransaction(std::move(submit_solution.m_coinbase_tx));
@@ -606,8 +534,8 @@ void Sv2TemplateProvider::ProcessSv2Message(const node::Sv2NetMsg& sv2_net_msg,
return;
}

auto cached_block = block_cache.find(request_tx_data.m_template_id);
if (cached_block != block_cache.end()) {
auto cached_block = m_block_cache.find(request_tx_data.m_template_id);
if (cached_block != m_block_cache.end()) {
CBlock& block = (*cached_block->second).block;

std::vector<uint8_t> witness_reserve_value;
@@ -661,6 +589,8 @@ std::vector<CTransactionRef> txs;

std::vector<std::byte> Sv2TemplateProvider::BuildEncryptedHeader(const node::Sv2NetMsg& net_msg, Sv2NoiseSession& noise)
{
LogPrintLevel(BCLog::SV2, BCLog::Level::Trace, "To encrypt: %s", HexStr(net_msg.m_msg));

DataStream ss_header{};
ss_header << net_msg.m_sv2_header;

17 changes: 5 additions & 12 deletions src/node/sv2_template_provider.h
Original file line number Diff line number Diff line change
@@ -130,15 +130,11 @@ class Sv2TemplateProvider
Clients m_sv2_clients;

/**
* The current best known new template id. This is incremented on creating new template.
* The most recent template id. This is incremented on creating new template,
* which happens for each connected client.
*/
uint64_t m_template_id;

/**
* The best known template to send to all sv2 clients.
*/
node::Sv2NewTemplateMsg m_best_new_template;

/**
* The current best known SetNewPrevHash that references the current best known
* block hash in the network.
@@ -201,7 +197,7 @@ class Sv2TemplateProvider
/**
* Main handler for all received stratum v2 messages.
*/
void ProcessSv2Message(const node::Sv2NetMsg& sv2_header, Sv2Client& client, const node::Sv2NewTemplateMsg& best_new_template, const node::Sv2SetNewPrevHashMsg& best_prev_hash, BlockCache& block_cache, uint64_t& template_id);
void ProcessSv2Message(const node::Sv2NetMsg& sv2_header, Sv2Client& client);

/**
* A helper function to process incoming noise messages to either progress a handshake or encrypt/decrypt in secure communication.
@@ -242,15 +238,12 @@ class Sv2TemplateProvider
/**
* Builds a NewWorkSet that contains the Sv2NewTemplateMsg, a new full block and a Sv2SetNewPrevHashMsg that are all linked to the same work.
*/
[[nodiscard]] NewWorkSet BuildNewWorkSet(bool future_template, unsigned int coinbase_output_max_additional_size, uint64_t template_id);
[[nodiscard]] NewWorkSet BuildNewWorkSet(bool future_template, unsigned int coinbase_output_max_additional_size);

// [[nodiscard]] ReducedWorkSet BuildNewTemplate(bool future_template, unsigned int coinbase_output_max_additional_size, uint64_t template_id);
/**
* Sends the best NewTemplate and SetNewPrevHash to a client.
*/
[[nodiscard]] bool SendWork(const Sv2Client& client, const node::Sv2NewTemplateMsg& new_template, const node::Sv2SetNewPrevHashMsg& prev_hash, BlockCache& block_cache, uint64_t& template_id);

[[nodiscard]] bool SendTemplate(const Sv2Client& client, const node::Sv2NewTemplateMsg& new_template);
[[nodiscard]] bool SendWork(const Sv2Client& client, bool send_new_prevhash);

/**
* Generates the socket events for each Sv2Client socket and the main listening socket.
18 changes: 3 additions & 15 deletions src/test/fuzz/sv2_template_provider.cpp
Original file line number Diff line number Diff line change
@@ -31,29 +31,17 @@ FUZZ_TARGET(sv2_template_provider)
auto setup_conn = node::Sv2NetMsg(std::move(header), std::move(random_bytes));

template_provider.ProcessSv2Message(setup_conn,
client,
best_new_template,
best_prev_hash,
block_cache,
template_id);
client);

client.m_setup_connection_confirmed = true;
header = node::Sv2NetHeader{node::Sv2MsgType::COINBASE_OUTPUT_DATA_SIZE, static_cast<uint32_t>(random_bytes.size())};
auto coinbase_output_size = node::Sv2NetMsg(std::move(header), std::move(random_bytes));
template_provider.ProcessSv2Message(coinbase_output_size,
client,
best_new_template,
best_prev_hash,
block_cache,
template_id);
client);

client.m_coinbase_output_data_size_recv = true;
header = node::Sv2NetHeader{node::Sv2MsgType::SUBMIT_SOLUTION, static_cast<uint32_t>(random_bytes.size())};
auto submit_solution = node::Sv2NetMsg(std::move(header), std::move(random_bytes));
template_provider.ProcessSv2Message(submit_solution,
client,
best_new_template,
best_prev_hash,
block_cache,
template_id);
client);
};
Loading

0 comments on commit 743f7d3

Please sign in to comment.