Skip to content

Commit

Permalink
Incrementally update sv2 block template
Browse files Browse the repository at this point in the history
Co-Authored-By: Fi3
  • Loading branch information
Sjors committed Jan 8, 2024
1 parent 909e08d commit e625634
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,8 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-sv2", "Bitcoind will act as a Stratum v2 Template Provider (default: false)", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-sv2interval", strprintf("Template Provider block template update interval (default: %d seconds)", DEFAULT_SV2_INTERVAL), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-sv2feedelta", strprintf("Minimum fee delta for Template Provider to send update upstream (default: %d sat)", DEFAULT_SV2_INTERVAL), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);

argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid values for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
Expand Down Expand Up @@ -1025,6 +1027,10 @@ bool AppInitParameterInteraction(const ArgsManager& args)

nBytesPerSigOp = args.GetIntArg("-bytespersigop", nBytesPerSigOp);

if (args.GetIntArg("-sv2interval", DEFAULT_SV2_INTERVAL) < 1) {
return InitError(Untranslated("-sv2interval must be at least one second"));
}

if (!g_wallet_init_interface.ParameterInteraction()) return false;

// Option to startup with mocktime set (used for regression testing):
Expand Down
5 changes: 5 additions & 0 deletions src/node/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class CScript;
class Chainstate;
class ChainstateManager;

/** Default for -sv2interval **/
static constexpr unsigned int DEFAULT_SV2_INTERVAL{30};
/** Default for -sv2feedelta */
static constexpr unsigned int DEFAULT_SV2_FEE_DELTA{1000};

namespace Consensus { struct Params; };

namespace node {
Expand Down
50 changes: 50 additions & 0 deletions src/node/sv2_template_provider.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <node/sv2_template_provider.h>

#include <common/args.h>
#include <consensus/merkle.h>
#include <txmempool.h>
#include <util/thread.h>
Expand Down Expand Up @@ -52,6 +53,7 @@ bool Sv2TemplateProvider::Start(const Sv2TemplateProviderOptions& options)

void Sv2TemplateProvider::Init(const Sv2TemplateProviderOptions& options)
{
m_minimum_fee_delta = gArgs.GetIntArg("-sv2feedelta", DEFAULT_SV2_FEE_DELTA);
m_port = options.port;
m_protocol_version = options.protocol_version;
m_optional_features = options.optional_features;
Expand Down Expand Up @@ -114,6 +116,27 @@ std::shared_ptr<Sock> Sv2TemplateProvider::BindListenPort(uint16_t port) const

return sock;
}
class Timer {
private:
std::chrono::seconds m_interval;
std::chrono::steady_clock::time_point m_last_triggered;

public:
Timer() {
m_interval = std::chrono::seconds(gArgs.GetIntArg("-sv2interval", DEFAULT_SV2_INTERVAL));
// Initialize the timer to a time point far in the past
m_last_triggered = std::chrono::steady_clock::now() - std::chrono::hours(1);
}

bool trigger() {
auto now = std::chrono::steady_clock::now();
if (now - m_last_triggered >= m_interval) {
m_last_triggered = now;
return true;
}
return false;
}
};

void Sv2TemplateProvider::DisconnectFlagged()
{
Expand All @@ -126,6 +149,10 @@ void Sv2TemplateProvider::DisconnectFlagged()

void Sv2TemplateProvider::ThreadSv2Handler()
{
Timer timer;
unsigned int mempool_last_update = 0;
unsigned int template_last_update = 0;

while (!m_flag_interrupt_sv2) {
if (m_chainman.IsInitialBlockDownload()) {
m_interrupt_sv2.sleep_for(std::chrono::milliseconds(100));
Expand Down Expand Up @@ -159,6 +186,11 @@ void Sv2TemplateProvider::ThreadSv2Handler()
return false;
}();


/** TODO: only look for mempool updates that (likely) impact the next block.
* See `doc/stratum-v2.md#mempool-monitoring`
*/
mempool_last_update = m_mempool.GetTransactionsUpdated();
bool should_make_template = false;

if (best_block_changed) {
Expand All @@ -167,8 +199,15 @@ void Sv2TemplateProvider::ThreadSv2Handler()
BlockCache block_cache;
m_block_cache.swap(block_cache);

for (auto& client : m_sv2_clients) {
client->m_latest_submitted_template_fees = 0;
}

// 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) {
should_make_template = true;
}

if (should_make_template) {
Expand Down Expand Up @@ -348,6 +387,15 @@ bool Sv2TemplateProvider::SendWork(Sv2Client& client, bool send_new_prevhash)
++m_template_id;
auto new_work_set = BuildNewWorkSet(/*future_template=*/send_new_prevhash, client.m_coinbase_tx_outputs_size);

// Do not submit new template if the fee increase is insufficient:
CAmount fees = 0;
for (CAmount fee : new_work_set.block_template->vTxFees) {
// Skip coinbase
if (fee < 0) continue;
fees += fee;
}
if (!send_new_prevhash && client.m_latest_submitted_template_fees + m_minimum_fee_delta > fees) return true;

m_block_cache.insert({m_template_id, std::move(new_work_set.block_template)});

LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Send 0x71 NewTemplate\n");
Expand All @@ -358,6 +406,8 @@ bool Sv2TemplateProvider::SendWork(Sv2Client& client, bool send_new_prevhash)
client.m_send_messages.emplace_back(Sv2NetMsg{new_work_set.prev_hash});
}

client.m_latest_submitted_template_fees = fees;

return true;
}

Expand Down
12 changes: 12 additions & 0 deletions src/node/sv2_template_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ struct Sv2Client

explicit Sv2Client(std::shared_ptr<Sock> sock, std::unique_ptr<Sv2Transport> transport) :
m_sock{std::move(sock)}, m_transport{std::move(transport)} {};

/**
* Fees in sat paid by the last submitted template
*/
CAmount m_latest_submitted_template_fees = 0;

};

struct Sv2TemplateProviderOptions
Expand Down Expand Up @@ -101,6 +107,12 @@ class Sv2TemplateProvider
*/
std::shared_ptr<Sock> m_listening_socket;

/**
* Minimum fee delta required before submitting an updated template.
* This may be negative.
*/
int m_minimum_fee_delta;

/**
* The main thread for the template provider.
*/
Expand Down

0 comments on commit e625634

Please sign in to comment.