pooled staking: renamed contributor cut to portions

This commit is contained in:
jcktm 2018-07-31 12:46:12 +10:00
parent aab30bb9e0
commit dcf1cc54d9
12 changed files with 97 additions and 92 deletions

View File

@ -535,13 +535,13 @@ namespace cryptonote
bool add_service_node_register_to_tx_extra(
std::vector<uint8_t>& tx_extra,
const std::vector<cryptonote::account_public_address>& addresses,
const std::vector<uint32_t>& shares,
const std::vector<uint32_t>& portions,
uint64_t expiration_timestamp,
const crypto::signature& service_node_signature)
{
if (addresses.size() != shares.size())
if (addresses.size() != portions.size())
{
LOG_ERROR("Tried to serialize registration with more addresses than shares, this should never happen");
LOG_ERROR("Tried to serialize registration with more addresses than portions, this should never happen");
return false;
}
std::vector<crypto::public_key> public_view_keys(addresses.size());
@ -556,7 +556,7 @@ namespace cryptonote
tx_extra_service_node_register{
public_spend_keys,
public_view_keys,
shares,
portions,
expiration_timestamp,
service_node_signature
};
@ -1017,19 +1017,19 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, const std::vector<uint32_t>& shares, uint64_t expiration_timestamp, crypto::hash& hash)
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, const std::vector<uint32_t>& portions, uint64_t expiration_timestamp, crypto::hash& hash)
{
if (addresses.size() != shares.size())
if (addresses.size() != portions.size())
{
LOG_ERROR("get_registration_hash addresses.size() != shares.size()");
LOG_ERROR("get_registration_hash addresses.size() != portions.size()");
return false;
}
uint64_t total_shares = 0;
for (uint32_t share : shares)
total_shares += share;
if (total_shares > STAKING_SHARES)
uint64_t total_portions = 0;
for (uint32_t portion : portions)
total_portions += portion;
if (total_portions > STAKING_PORTIONS)
{
LOG_ERROR(tr("Your registration has more than ") << STAKING_SHARES << tr(" shares, this registration is invalid!"));
LOG_ERROR(tr("Your registration has more than ") << STAKING_PORTIONS << tr(" portions, this registration is invalid!"));
return false;
}
size_t size = addresses.size() * (sizeof(cryptonote::account_public_address) + sizeof(uint32_t)) + sizeof(uint64_t);
@ -1039,7 +1039,7 @@ namespace cryptonote
{
memcpy(buffer_iter, &addresses[i], sizeof(cryptonote::account_public_address));
buffer_iter += sizeof(cryptonote::account_public_address);
memcpy(buffer_iter, &shares[i], sizeof(uint32_t));
memcpy(buffer_iter, &portions[i], sizeof(uint32_t));
buffer_iter += sizeof(uint32_t);
}
memcpy(buffer_iter, &expiration_timestamp, sizeof(expiration_timestamp));

View File

@ -75,7 +75,7 @@ namespace cryptonote
bool get_service_node_deregister_from_tx_extra(const std::vector<uint8_t>& tx_extra, tx_extra_service_node_deregister& deregistration);
bool get_service_node_pubkey_from_tx_extra(const std::vector<uint8_t>& tx_extra, crypto::public_key& pubkey);
bool get_service_node_contributor_from_tx_extra(const std::vector<uint8_t>& tx_extra, cryptonote::account_public_address& address);
bool add_service_node_register_to_tx_extra(std::vector<uint8_t>& tx_extra, const std::vector<cryptonote::account_public_address>& addresses, const std::vector<uint32_t>& shares, uint64_t expiration_timestamp, const crypto::signature& signature);
bool add_service_node_register_to_tx_extra(std::vector<uint8_t>& tx_extra, const std::vector<cryptonote::account_public_address>& addresses, const std::vector<uint32_t>& portions, uint64_t expiration_timestamp, const crypto::signature& signature);
void add_service_node_winner_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::public_key& winner);
void add_service_node_pubkey_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::public_key& pubkey);
void add_service_node_contributor_to_tx_extra(std::vector<uint8_t>& tx_extra, const cryptonote::account_public_address& address);
@ -108,7 +108,7 @@ namespace cryptonote
crypto::hash get_blob_hash(const blobdata& blob);
std::string short_hash_str(const crypto::hash& h);
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, const std::vector<uint32_t>& shares, uint64_t expiration_timestamp, crypto::hash& hash);
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, const std::vector<uint32_t>& portions, uint64_t expiration_timestamp, crypto::hash& hash);
crypto::hash get_transaction_hash(const transaction& t);
bool get_transaction_hash(const transaction& t, crypto::hash& res);

View File

@ -206,14 +206,14 @@ namespace cryptonote
{
std::vector<crypto::public_key> m_public_spend_keys;
std::vector<crypto::public_key> m_public_view_keys;
std::vector<uint32_t> m_shares;
std::vector<uint32_t> m_portions;
uint64_t m_expiration_timestamp;
crypto::signature m_service_node_signature;
BEGIN_SERIALIZE()
FIELD(m_public_spend_keys)
FIELD(m_public_view_keys)
FIELD(m_shares)
FIELD(m_portions)
FIELD(m_expiration_timestamp)
FIELD(m_service_node_signature)
END_SERIALIZE()

View File

@ -52,7 +52,9 @@
#define STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS 20
#define STAKING_REQUIREMENT_LOCK_BLOCKS (30*24*31)
#define STAKING_RELOCK_WINDOW_BLOCKS (30*6)
#define STAKING_SHARES UINT32_MAX
#define STAKING_PORTIONS UINT32_MAX
#define MAX_NUMBER_OF_CONTRIBUTORS 10
#define STAKING_AUTHORIZATION_EXPIRATION_WINDOW (60*60*24*7*2) // 2 weeks

View File

@ -1332,7 +1332,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
uint8_t hf_version = m_hardfork->get_current_version();
crypto::public_key winner = m_service_node_list.select_winner(b.prev_id);
std::vector<std::pair<account_public_address, uint32_t>> service_node_addresses = m_service_node_list.get_winner_addresses_and_shares(b.prev_id);
std::vector<std::pair<account_public_address, uint32_t>> service_node_addresses = m_service_node_list.get_winner_addresses_and_portions(b.prev_id);
bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, hf_version, m_nettype, winner, service_node_addresses);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance");

View File

@ -1706,13 +1706,13 @@ namespace cryptonote
std::string core::prepare_registration(const std::vector<std::string>& args)
{
std::vector<cryptonote::account_public_address> addresses;
std::vector<uint32_t> shares;
bool r = service_nodes::convert_registration_args(m_nettype, args, addresses, shares);
std::vector<uint32_t> portions;
bool r = service_nodes::convert_registration_args(m_nettype, args, addresses, portions);
CHECK_AND_ASSERT_MES(r, "", tr("Failed to convert registration args"));
assert(addresses.size() == shares.size());
assert(addresses.size() == portions.size());
uint64_t exp_timestamp = time(nullptr) + STAKING_AUTHORIZATION_EXPIRATION_WINDOW;
crypto::hash hash;
r = cryptonote::get_registration_hash(addresses, shares, exp_timestamp, hash);
r = cryptonote::get_registration_hash(addresses, portions, exp_timestamp, hash);
CHECK_AND_ASSERT_MES(r, "", tr("Failed to get the registration hash"));
crypto::signature signature;
crypto::generate_signature(hash, m_service_node_pubkey, m_service_node_key, signature);
@ -1721,7 +1721,7 @@ namespace cryptonote
ss << "register_service_node ";
ss << std::setprecision(17);
for (size_t i = 0; i < addresses.size(); i++)
ss << get_account_address_as_str(m_nettype, false, addresses[i]) << " " << (shares[i]/(double)STAKING_SHARES) << " ";
ss << get_account_address_as_str(m_nettype, false, addresses[i]) << " " << (portions[i]/(double)STAKING_PORTIONS) << " ";
ss << exp_timestamp << " " << epee::string_tools::pod_to_hex(m_service_node_pubkey) << " " << epee::string_tools::pod_to_hex(signature) << "\n\n";
time_t tt = exp_timestamp;
struct tm tm;

View File

@ -992,7 +992,7 @@ namespace cryptonote
* @brief Prepare a registration tx using the service node keys for this
* daemon.
*
* @param args The arguments, as a string. <address1> <shares1> [<address2> <shares2> [...]]
* @param args The arguments, as a string. <address1> <fraction1> [<address2> <fraction2> [...]]
*
* @return whether or not the command was able to prepare the registration.
*/

View File

@ -107,19 +107,19 @@ namespace cryptonote
return hard_fork_version >= 9 ? base_reward / 2 : 0;
}
uint64_t get_share_of_reward(uint32_t shares, uint64_t total_service_node_reward)
uint64_t get_portion_of_reward(uint32_t portions, uint64_t total_service_node_reward)
{
uint64_t hi, lo, rewardhi, rewardlo;
lo = mul128(total_service_node_reward, shares, &hi);
div128_32(hi, lo, STAKING_SHARES, &rewardhi, &rewardlo);
lo = mul128(total_service_node_reward, portions, &hi);
div128_32(hi, lo, STAKING_PORTIONS, &rewardhi, &rewardlo);
return rewardlo;
}
static uint64_t calculate_sum_of_shares(const std::vector<std::pair<cryptonote::account_public_address, uint32_t>>& shares, uint64_t total_service_node_reward)
static uint64_t calculate_sum_of_portions(const std::vector<std::pair<cryptonote::account_public_address, uint32_t>>& portions, uint64_t total_service_node_reward)
{
uint64_t reward = 0;
for (size_t i = 0; i < shares.size(); i++)
reward += get_share_of_reward(shares[i].second, total_service_node_reward);
for (size_t i = 0; i < portions.size(); i++)
reward += get_portion_of_reward(portions[i].second, total_service_node_reward);
return reward;
}
@ -223,7 +223,7 @@ namespace cryptonote
{
governance_reward = get_governance_reward(height, block_reward);
total_service_node_reward = get_service_node_reward(height, block_reward, hard_fork_version);
total_paid_service_node_reward = calculate_sum_of_shares(service_node_info, total_service_node_reward);
total_paid_service_node_reward = calculate_sum_of_portions(service_node_info, total_service_node_reward);
block_reward -= governance_reward;
block_reward -= total_paid_service_node_reward;
}
@ -265,7 +265,7 @@ namespace cryptonote
tk.key = out_eph_public_key;
tx_out out;
summary_amounts += out.amount = get_share_of_reward(service_node_info[i].second, total_service_node_reward);
summary_amounts += out.amount = get_portion_of_reward(service_node_info[i].second, total_service_node_reward);
out.target = tk;
tx.vout.push_back(out);
}

View File

@ -49,12 +49,12 @@ namespace cryptonote
uint8_t hard_fork_version = 1,
network_type nettype = MAINNET,
const crypto::public_key& service_node_key = crypto::null_pkey,
const std::vector<std::pair<account_public_address, uint32_t>>& service_node_info={ std::pair<account_public_address, uint32_t>({ crypto::null_pkey, crypto::null_pkey }, STAKING_SHARES) }
const std::vector<std::pair<account_public_address, uint32_t>>& service_node_info={ std::pair<account_public_address, uint32_t>({ crypto::null_pkey, crypto::null_pkey }, STAKING_PORTIONS) }
);
keypair get_deterministic_keypair_from_height(uint64_t height);
uint64_t get_share_of_reward(uint32_t shares, uint64_t total_service_node_reward);
uint64_t get_portion_of_reward(uint32_t portions, uint64_t total_service_node_reward);
uint64_t get_governance_reward(uint64_t height, uint64_t base_reward);
uint64_t get_service_node_reward(uint64_t height, uint64_t base_reward, int hard_fork_version);

View File

@ -140,7 +140,7 @@ namespace service_nodes
return tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && tx.unlock_time >= block_height + STAKING_REQUIREMENT_LOCK_BLOCKS;
}
bool service_node_list::reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& shares, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key) const
bool service_node_list::reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& portions, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key) const
{
cryptonote::tx_extra_service_node_register registration;
if (!get_service_node_register_from_tx_extra(tx.extra, registration))
@ -153,7 +153,7 @@ namespace service_nodes
for (size_t i = 0; i < registration.m_public_spend_keys.size(); i++)
addresses.push_back(cryptonote::account_public_address{ registration.m_public_spend_keys[i], registration.m_public_view_keys[i] });
shares = registration.m_shares;
portions = registration.m_portions;
expiration_timestamp = registration.m_expiration_timestamp;
signature = registration.m_service_node_signature;
tx_pub_key = cryptonote::get_tx_pub_key_from_extra(tx.extra);
@ -242,30 +242,30 @@ namespace service_nodes
{
crypto::public_key tx_pub_key, service_node_key;
std::vector<cryptonote::account_public_address> service_node_addresses;
std::vector<uint32_t> service_node_shares;
std::vector<uint32_t> service_node_portions;
uint64_t expiration_timestamp;
crypto::signature signature;
if (!reg_tx_extract_fields(tx, service_node_addresses, service_node_shares, expiration_timestamp, service_node_key, signature, tx_pub_key))
if (!reg_tx_extract_fields(tx, service_node_addresses, service_node_portions, expiration_timestamp, service_node_key, signature, tx_pub_key))
return false;
assert(service_node_shares.size() == service_node_addresses.size());
assert(service_node_portions.size() == service_node_addresses.size());
uint64_t total = 0;
for (size_t i = 0; i < service_node_shares.size(); i++)
total += service_node_shares[i];
if (total > STAKING_SHARES)
for (size_t i = 0; i < service_node_portions.size(); i++)
total += service_node_portions[i];
if (total > STAKING_PORTIONS)
return false;
crypto::hash hash;
if (!get_registration_hash(service_node_addresses, service_node_shares, expiration_timestamp, hash))
if (!get_registration_hash(service_node_addresses, service_node_portions, expiration_timestamp, hash))
return false;
if (!crypto::check_signature(hash, service_node_key, signature))
return false;
if (expiration_timestamp < block_timestamp)
return false;
if (service_node_addresses.size() > MAX_NUMBER_OF_SHAREHOLDERS)
if (service_node_addresses.size() > MAX_NUMBER_OF_CONTRIBUTORS)
return false;
key = service_node_key;
@ -273,7 +273,7 @@ namespace service_nodes
info.last_reward_block_height = block_height;
info.last_reward_transaction_index = index;
info.addresses = service_node_addresses;
info.shares = service_node_shares;
info.portions = service_node_portions;
info.total_contributions = 0;
info.staking_requirement = m_blockchain.get_staking_requirement(block_height);
@ -487,28 +487,28 @@ namespace service_nodes
return staking_requirement / 10;
}
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> service_node_list::get_winner_addresses_and_shares(const crypto::hash& prev_id) const
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> service_node_list::get_winner_addresses_and_portions(const crypto::hash& prev_id) const
{
crypto::public_key key = select_winner(prev_id);
if (key == crypto::null_pkey)
return { std::make_pair(null_address, STAKING_SHARES) };
return { std::make_pair(null_address, STAKING_PORTIONS) };
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> winners;
uint64_t remaining_shares = STAKING_SHARES;
auto add_to_winners = [&winners](cryptonote::account_public_address address, uint64_t amount_of_shares) {
if (amount_of_shares == 0) return;
uint64_t remaining_portions = STAKING_PORTIONS;
auto add_to_winners = [&winners](cryptonote::account_public_address address, uint64_t amount_of_portions) {
if (amount_of_portions == 0) return;
auto iter = std::find_if(std::begin(winners), std::end(winners),
[&address](const std::pair<cryptonote::account_public_address, uint32_t>& winner) {
return winner.first == address;
});
if (iter == winners.end())
winners.push_back(std::make_pair(address, amount_of_shares));
winners.push_back(std::make_pair(address, amount_of_portions));
else
iter->second += amount_of_shares;
iter->second += amount_of_portions;
};
for (size_t i = 0; i < m_service_nodes_infos.at(key).addresses.size(); i++)
{
add_to_winners(m_service_nodes_infos.at(key).addresses[i], m_service_nodes_infos.at(key).shares[i]);
remaining_shares -= m_service_nodes_infos.at(key).shares[i];
add_to_winners(m_service_nodes_infos.at(key).addresses[i], m_service_nodes_infos.at(key).portions[i]);
remaining_portions -= m_service_nodes_infos.at(key).portions[i];
}
uint64_t remaining_staking_requirement = m_service_nodes_infos.at(key).staking_requirement;
for (const auto& contribution : m_service_nodes_infos.at(key).contributions)
@ -517,7 +517,7 @@ namespace service_nodes
remaining_staking_requirement -= actual_contribution;
uint64_t hi, lo, resulthi, resultlo;
lo = mul128(actual_contribution, remaining_shares, &hi);
lo = mul128(actual_contribution, remaining_portions, &hi);
div128_64(hi, lo, m_service_nodes_infos.at(key).staking_requirement, &resulthi, &resultlo);
add_to_winners(contribution.address, resultlo);
@ -557,16 +557,16 @@ namespace service_nodes
if (check_winner_pubkey != winner)
return false;
const std::vector<std::pair<cryptonote::account_public_address, uint32_t>> addresses_and_shares = get_winner_addresses_and_shares(prev_id);
const std::vector<std::pair<cryptonote::account_public_address, uint32_t>> addresses_and_portions = get_winner_addresses_and_portions(prev_id);
if (miner_tx.vout.size() - 1 < addresses_and_shares.size())
if (miner_tx.vout.size() - 1 < addresses_and_portions.size())
return false;
for (size_t i = 0; i < addresses_and_shares.size(); i++)
for (size_t i = 0; i < addresses_and_portions.size(); i++)
{
size_t vout_index = miner_tx.vout.size() - 1 /* governance */ - addresses_and_shares.size() + i;
size_t vout_index = miner_tx.vout.size() - 1 /* governance */ - addresses_and_portions.size() + i;
uint64_t reward = cryptonote::get_share_of_reward(addresses_and_shares[i].second, total_service_node_reward);
uint64_t reward = cryptonote::get_portion_of_reward(addresses_and_portions[i].second, total_service_node_reward);
if (miner_tx.vout[vout_index].amount != reward)
{
@ -584,10 +584,10 @@ namespace service_nodes
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
cryptonote::keypair gov_key = cryptonote::get_deterministic_keypair_from_height(height);
bool r = crypto::generate_key_derivation(addresses_and_shares[i].first.m_view_public_key, gov_key.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << addresses_and_shares[i].first.m_view_public_key << ", " << gov_key.sec << ")");
r = crypto::derive_public_key(derivation, vout_index, addresses_and_shares[i].first.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << vout_index << ", "<< addresses_and_shares[i].first.m_spend_public_key << ")");
bool r = crypto::generate_key_derivation(addresses_and_portions[i].first.m_view_public_key, gov_key.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << addresses_and_portions[i].first.m_view_public_key << ", " << gov_key.sec << ")");
r = crypto::derive_public_key(derivation, vout_index, addresses_and_portions[i].first.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << vout_index << ", "<< addresses_and_portions[i].first.m_spend_public_key << ")");
if (boost::get<cryptonote::txout_to_key>(miner_tx.vout[vout_index].target).key != out_eph_public_key)
{
@ -704,16 +704,21 @@ namespace service_nodes
return false;
}
bool convert_registration_args(cryptonote::network_type nettype, const std::vector<std::string>& args, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& shares)
bool convert_registration_args(cryptonote::network_type nettype, const std::vector<std::string>& args, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& portions)
{
if (args.size() % 2 != 0)
{
MERROR(tr("Expected an even number of arguments: [<address> <share> [<address> <share> [...]]]"));
MERROR(tr("Expected an even number of arguments: [<address> <fraction> [<address> <fraction> [...]]]"));
return false;
}
if (args.size() / 2 > MAX_NUMBER_OF_CONTRIBUTORS)
{
MERROR(tr("Exceeds the maximum number of contributors, which is ") << MAX_NUMBER_OF_CONTRIBUTORS);
return false;
}
addresses.clear();
shares.clear();
uint64_t total_shares = 0;
portions.clear();
uint64_t total_portions = 0;
for (size_t i = 0; i < args.size(); i += 2)
{
cryptonote::address_parse_info info;
@ -739,26 +744,26 @@ namespace service_nodes
try
{
double share_fraction = boost::lexical_cast<double>(args[i+1]);
if (share_fraction <= 0 || share_fraction > 1)
double portion_fraction = boost::lexical_cast<double>(args[i+1]);
if (portion_fraction <= 0 || portion_fraction > 1)
{
MERROR(tr("Invalid share amount: ") << args[i+1] << tr(". ") << tr("Must be more than 0 and no greater than 1"));
MERROR(tr("Invalid portion amount: ") << args[i+1] << tr(". ") << tr("Must be more than 0 and no greater than 1"));
return false;
}
uint32_t num_shares = STAKING_SHARES * share_fraction;
shares.push_back(num_shares);
total_shares += num_shares;
uint32_t num_portions = STAKING_PORTIONS * portion_fraction;
portions.push_back(num_portions);
total_portions += num_portions;
}
catch (const std::exception &e)
{
MERROR(tr("Invalid share amount: ") << args[i+1] << tr(". ") << tr("Must be more than 0 and no greater than 1"));
MERROR(tr("Invalid portion amount: ") << args[i+1] << tr(". ") << tr("Must be more than 0 and no greater than 1"));
return false;
}
}
if (total_shares > (uint64_t)STAKING_SHARES)
if (total_portions > (uint64_t)STAKING_PORTIONS)
{
MERROR(tr("Invalid share amounts, shares must sum to at most 1."));
MERROR(tr("If it looks correct, this may be because of rounding. Try reducing one of the shareholders shares by a very tiny amount"));
MERROR(tr("Invalid portion amounts, portions must sum to at most 1."));
MERROR(tr("If it looks correct, this may be because of rounding. Try reducing one of the portionholders portions by a very tiny amount"));
return false;
}
return true;

View File

@ -53,8 +53,6 @@ namespace service_nodes
public cryptonote::Blockchain::ValidateMinerTxHook
{
public:
const size_t MAX_NUMBER_OF_SHAREHOLDERS = 10;
service_node_list(cryptonote::Blockchain& blockchain);
void block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs);
void blockchain_detached(uint64_t height);
@ -63,7 +61,7 @@ namespace service_nodes
std::vector<crypto::public_key> get_expired_nodes(uint64_t block_height) const;
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> get_winner_addresses_and_shares(const crypto::hash& prev_id) const;
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> get_winner_addresses_and_portions(const crypto::hash& prev_id) const;
crypto::public_key select_winner(const crypto::hash& prev_id) const;
bool is_service_node(const crypto::public_key& pubkey) const;
@ -88,7 +86,7 @@ namespace service_nodes
uint64_t last_reward_block_height;
int last_reward_transaction_index;
std::vector<cryptonote::account_public_address> addresses;
std::vector<uint32_t> shares;
std::vector<uint32_t> portions;
std::vector<contribution> contributions;
uint64_t total_contributions;
uint64_t staking_requirement;
@ -108,7 +106,7 @@ namespace service_nodes
void block_added_generic(const cryptonote::block& block, const T& txs);
bool reg_tx_has_correct_unlock_time(const cryptonote::transaction& tx, uint64_t block_height) const;
bool reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& shares, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key) const;
bool reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& portions, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key) const;
uint64_t get_reg_tx_staking_output_contribution(const cryptonote::transaction& tx, int i, crypto::key_derivation derivation, hw::device& hwdev) const;
uint64_t get_min_contribution(uint64_t height) const;
@ -160,7 +158,7 @@ namespace service_nodes
std::map<block_height, std::shared_ptr<quorum_state>> m_quorum_states;
};
bool convert_registration_args(cryptonote::network_type nettype, const std::vector<std::string>& args, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& shares);
bool convert_registration_args(cryptonote::network_type nettype, const std::vector<std::string>& args, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& portions);
const static cryptonote::account_public_address null_address{ crypto::null_pkey, crypto::null_pkey };
}

View File

@ -2024,7 +2024,7 @@ simple_wallet::simple_wallet()
tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used."));
m_cmd_binder.set_handler("register_service_node",
boost::bind(&simple_wallet::register_service_node, this, _1),
tr("register_service_node [index=<N1>[,<N2>,...]] [priority] [<address1> <shares1> [<address2> <shares2> [...]]] <expiration timestamp> <pubkey> <signature>"),
tr("register_service_node [index=<N1>[,<N2>,...]] [priority] [<address1> <fraction1> [<address2> <fraction2> [...]]] <expiration timestamp> <pubkey> <signature>"),
tr("Send all unlocked balance to the same address. Lock it for [lockblocks] (max. 1000000). If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet stakes outputs received by those address indices. <priority> is the priority of the stake. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used."));
m_cmd_binder.set_handler("stake_all",
boost::bind(&simple_wallet::stake_all, this, _1),
@ -4726,20 +4726,20 @@ bool simple_wallet::register_service_node(const std::vector<std::string> &args_)
if (local_args.size() < 3)
{
fail_msg_writer() << tr("Usage: register_service_node [index=<N1>[,<N2>,...]] [priority] [<address1> <shares1> [<address2> <shares2> [...]]] <expiration timestamp> <service node pubkey> <signature>");
fail_msg_writer() << tr("Usage: register_service_node [index=<N1>[,<N2>,...]] [priority] [<address1> <fraction1> [<address2> <fraction2> [...]]] <expiration timestamp> <service node pubkey> <signature>");
fail_msg_writer() << tr("");
fail_msg_writer() << tr("Prepare this command with the service node using:");
fail_msg_writer() << tr("");
fail_msg_writer() << tr("./lokid --prepare-registration <address> <shares> [<address2> <shares2> [...]]");
fail_msg_writer() << tr("./lokid --prepare-registration <address> <fraction> [<address2> <fraction2> [...]]");
fail_msg_writer() << tr("");
fail_msg_writer() << tr("This command must be run from the daemon that will be acting as a service node");
return true;
}
std::vector<std::string> address_shares_args(local_args.begin(), local_args.begin() + local_args.size() - 3);
std::vector<std::string> address_portions_args(local_args.begin(), local_args.begin() + local_args.size() - 3);
std::vector<cryptonote::account_public_address> addresses;
std::vector<uint32_t> shares;
if (!service_nodes::convert_registration_args(m_wallet->nettype(), address_shares_args, addresses, shares))
std::vector<uint32_t> portions;
if (!service_nodes::convert_registration_args(m_wallet->nettype(), address_portions_args, addresses, portions))
{
fail_msg_writer() << tr("Could not convert registration args");
return true;
@ -4785,7 +4785,7 @@ bool simple_wallet::register_service_node(const std::vector<std::string> &args_)
add_service_node_pubkey_to_tx_extra(extra, service_node_key);
if (!add_service_node_register_to_tx_extra(extra, addresses, shares, expiration_timestamp, signature))
if (!add_service_node_register_to_tx_extra(extra, addresses, portions, expiration_timestamp, signature))
{
fail_msg_writer() << tr("failed to serialize service node registration tx extra");
return true;