Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Ref #19: Finish vote proxying (untested)
Browse files Browse the repository at this point in the history
I think I've implemented all of it, but it's not tested yet so I'm
leaving the issue open for now.
  • Loading branch information
nathanielhourt committed Jun 23, 2017
1 parent 53a0a63 commit 55ce118
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 20 deletions.
3 changes: 2 additions & 1 deletion libraries/chain/include/eos/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@

#define EOS_SYSTEM_CONTRACT_FUNCTIONS (CreateAccount)(DefineStruct)(SetCode)
#define EOS_CONTRACT_FUNCTIONS (Transfer)(TransferToLocked)
#define EOS_STAKED_BALANCE_CONTRACT_FUNCTIONS (CreateProducer)(UpdateProducer)(ApproveProducer)
#define EOS_STAKED_BALANCE_CONTRACT_FUNCTIONS \
(CreateProducer)(UpdateProducer)(ApproveProducer)(SetVoteProxy)(AllowVoteProxying)

namespace eos { namespace chain {
using std::map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,19 @@ class ProxyVoteObject : public chainbase::object<chain::proxy_vote_object_type,
id_type id;
/// The account receiving the proxied voting power
types::AccountName proxyTarget;
/// The list of accounts proxying their voting power to @proxyTarget
/// The list of accounts proxying their voting power to @ref proxyTarget
chain::shared_set<types::AccountName> proxySources;
/// The total stake proxied to @ref proxyTarget. At all times, this should be equal to the sum of stake over all
/// accounts in @ref proxySources
types::ShareType proxiedStake;
types::ShareType proxiedStake = 0;

void addProxySource(const types::AccountName& source, chain::ShareType sourceStake, chainbase::database& db) const;
void removeProxySource(const types::AccountName& source, chain::ShareType sourceStake,
chainbase::database& db) const;
void updateProxiedStake(chain::ShareType stakeDelta, chainbase::database& db) const;

/// Cancel proxying votes to @ref proxyTarget for all @ref proxySources
void cancelProxies(chainbase::database& db) const;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,16 @@ struct ApproveProducer {
static void apply(chain::apply_context& context);
};

struct AllowVoteProxying {
static void validate(chain::message_validate_context& context);
static void validate_preconditions(chain::precondition_validate_context& context);
static void apply(chain::apply_context& context);
};

struct SetVoteProxy {
static void validate(chain::message_validate_context&) {}
static void validate_preconditions(chain::precondition_validate_context& context);
static void apply(chain::apply_context& context);
};

} // namespace eos
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class StakedBalanceObject : public chainbase::object<chain::staked_balance_objec
types::Time lastUnstakingTime = types::Time::maximum();

/// The account's vote on producers. This may either be a list of approved producers, or an account to proxy vote to
fc::static_variant<ProducerSlate, types::AccountName> producerVotes;
fc::static_variant<ProducerSlate, types::AccountName> producerVotes = ProducerSlate{};

/**
* @brief Add the provided stake to this balance, maintaining invariants
Expand All @@ -68,7 +68,17 @@ class StakedBalanceObject : public chainbase::object<chain::staked_balance_objec
*/
void beginUnstakingTokens(types::ShareType amount, chainbase::database& db) const;

void updateVotes(types::ShareType stakeDelta, chainbase::database& db) const;
/**
* @brief Propagate the specified change in stake to the producer votes or the proxy
* @param stakeDelta The change in stake
* @param db Read-write reference to the database
*
* This method will apply the provided delta in voting stake to the next stage in the producer voting pipeline,
* whether that be the producers in the slate, or the account the votes are proxied to.
*
* This method will *not* update this object in any way. It will not adjust @ref stakedBalance, etc
*/
void propagateVotes(types::ShareType stakeDelta, chainbase::database& db) const;
};

struct byOwnerName;
Expand Down
18 changes: 14 additions & 4 deletions libraries/native_contract/producer_objects.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <eos/native_contract/producer_objects.hpp>
#include <eos/native_contract/staked_balance_objects.hpp>

#include <eos/chain/producer_object.hpp>

Expand All @@ -23,7 +24,7 @@ void ProxyVoteObject::addProxySource(const AccountName& source, ShareType source
pvo.proxySources.insert(source);
pvo.proxiedStake += sourceStake;
});
#warning TODO: Update proxy votes
db.get<StakedBalanceObject, byOwnerName>(proxyTarget).propagateVotes(sourceStake, db);
}

void ProxyVoteObject::removeProxySource(const AccountName& source, ShareType sourceStake,
Expand All @@ -32,14 +33,23 @@ void ProxyVoteObject::removeProxySource(const AccountName& source, ShareType sou
pvo.proxySources.erase(source);
pvo.proxiedStake -= sourceStake;
});
#warning TODO: Update proxy votes
db.get<StakedBalanceObject, byOwnerName>(proxyTarget).propagateVotes(sourceStake, db);
}

void ProxyVoteObject::updateProxiedStake(ShareType stakeDelta, chainbase::database& db) const {
db.modify(*this, [stakeDelta](ProxyVoteObject& pvo) {
pvo.proxiedStake += stakeDelta;
});
#warning TODO: Update proxy votes
db.get<StakedBalanceObject, byOwnerName>(proxyTarget).propagateVotes(stakeDelta, db);
}

void ProxyVoteObject::cancelProxies(chainbase::database& db) const {
boost::for_each(proxySources, [&db](const AccountName& source) {
const auto& balance = db.get<StakedBalanceObject, byOwnerName>(source);
db.modify(balance, [](StakedBalanceObject& sbo) {
sbo.producerVotes = ProducerSlate{};
});
});
}

ProducerRound ProducerScheduleObject::calculateNextRound(chainbase::database& db) const {
Expand Down Expand Up @@ -105,7 +115,7 @@ ProducerRound ProducerScheduleObject::calculateNextRound(chainbase::database& db
pso.currentRaceTime = newRaceTime;
});
} else {
wlog("All producers finished race, or race time at maximum; resetting race.");
wlog("Producer race finished; restarting race.");
resetProducerRace(db);
}
} catch (ProducerRaceOverflowException&) {
Expand Down
87 changes: 80 additions & 7 deletions libraries/native_contract/staked_balance_contract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,24 @@ void ApproveProducer::validate_preconditions(precondition_validate_context& cont
void ApproveProducer::apply(apply_context& context) {
auto& db = context.mutable_db;
auto approve = context.msg.as<types::ApproveProducer>();
auto producer = db.find<ProducerVotesObject, byOwnerName>(approve.producer);
auto voter = db.find<StakedBalanceObject, byOwnerName>(context.msg.sender);
const auto& producer = db.get<ProducerVotesObject, byOwnerName>(approve.producer);
const auto& voter = db.get<StakedBalanceObject, byOwnerName>(context.msg.sender);
auto raceTime = ProducerScheduleObject::get(db).currentRaceTime;
auto totalVotingStake = voter.stakedBalance;

// Check if voter is proxied to; if so, we need to add in the proxied stake
if (auto proxy = db.find<ProxyVoteObject, byTargetName>(voter.ownerName))
totalVotingStake += proxy->proxiedStake;

// Add/remove votes from producer
db.modify(*producer,
[approve = approve.approve, amount = voter->stakedBalance, &raceTime](ProducerVotesObject& pvo) {
db.modify(producer, [approve = approve.approve, totalVotingStake, &raceTime](ProducerVotesObject& pvo) {
if (approve)
pvo.updateVotes(amount, raceTime);
pvo.updateVotes(totalVotingStake, raceTime);
else
pvo.updateVotes(-amount, raceTime);
pvo.updateVotes(-totalVotingStake, raceTime);
});
// Add/remove producer from voter's approved producer list
db.modify(*voter, [&approve](StakedBalanceObject& sbo) {
db.modify(voter, [&approve](StakedBalanceObject& sbo) {
auto& slate = sbo.producerVotes.get<ProducerSlate>();
if (approve.approve)
slate.add(approve.producer);
Expand All @@ -191,4 +195,73 @@ void ApproveProducer::apply(apply_context& context) {
});
}

void AllowVoteProxying::validate(message_validate_context& context) {
auto allow = context.msg.as<types::AllowVoteProxying>();
EOS_ASSERT(allow.allow == 0 || allow.allow == 1, message_validate_exception,
"Unknown allow value: ${val}; must be either 0 or 1", ("val", allow.allow));
}

void AllowVoteProxying::validate_preconditions(precondition_validate_context& context) {
auto allow = context.msg.as<types::AllowVoteProxying>();
auto proxy = context.db.find<ProxyVoteObject, byTargetName>(context.msg.sender);
if (allow.allow)
EOS_ASSERT(proxy == nullptr, message_precondition_exception,
"Account '${name}' already allows vote proxying", ("name", context.msg.sender));
else
EOS_ASSERT(proxy != nullptr, message_precondition_exception,
"Account '${name}' already disallows vote proxying", ("name", context.msg.sender));
}

void AllowVoteProxying::apply(apply_context& context) {
auto allow = context.msg.as<types::AllowVoteProxying>();
auto& db = context.mutable_db;
if (allow.allow)
db.create<ProxyVoteObject>([target = context.msg.sender](ProxyVoteObject& pvo) {
pvo.proxyTarget = target;
});
else {
const auto& proxy = db.get<ProxyVoteObject, byTargetName>(context.msg.sender);
proxy.cancelProxies(db);
db.remove(proxy);
}
}

void SetVoteProxy::validate_preconditions(precondition_validate_context& context) {
auto svp = context.msg.as<types::SetVoteProxy>();
const auto& db = context.db;

auto proxy = db.find<ProxyVoteObject, byTargetName>(context.msg.sender);
EOS_ASSERT(proxy == nullptr, message_precondition_exception,
"Account '${src}' cannot proxy its votes, since it allows other accounts to proxy to it",
("src", context.msg.sender));

if (svp.proxy != context.msg.sender) {
// We are trying to enable proxying to svp.proxy
auto proxy = db.find<ProxyVoteObject, byTargetName>(svp.proxy);
EOS_ASSERT(proxy != nullptr, message_precondition_exception,
"Proxy target '${target}' does not allow votes to be proxied to it", ("target", svp.proxy));
} else {
// We are trying to disable proxying to sender.producerVotes.get<AccountName>()
const auto& sender = db.get<StakedBalanceObject, byOwnerName>(context.msg.sender);
EOS_ASSERT(sender.producerVotes.contains<AccountName>(), message_precondition_exception,
"Account '${name}' does not currently proxy its votes to any account", ("name", context.msg.sender));
}
}

void SetVoteProxy::apply(apply_context& context) {
auto svp = context.msg.as<types::SetVoteProxy>();
auto& db = context.mutable_db;
const auto& proxy = db.get<ProxyVoteObject, byTargetName>(svp.proxy);
const auto& balance = db.get<StakedBalanceObject, byOwnerName>(context.msg.sender);

if (svp.proxy != context.msg.sender)
// We are enabling proxying to svp.proxy
proxy.addProxySource(context.msg.sender, balance.stakedBalance, db);
else {
// We are disabling proxying to balance.producerVotes.get<AccountName>()
proxy.removeProxySource(context.msg.sender, balance.stakedBalance, db);
db.modify(balance, [](StakedBalanceObject& sbo) { sbo.producerVotes = ProducerSlate{}; });
}
}

} // namespace eos
4 changes: 2 additions & 2 deletions libraries/native_contract/staked_balance_objects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void StakedBalanceObject::stakeTokens(ShareType newStake, chainbase::database& d
sbo.stakedBalance += newStake;
});

updateVotes(newStake, db);
propagateVotes(newStake, db);
}

void StakedBalanceObject::beginUnstakingTokens(ShareType amount, chainbase::database& db) const {
Expand All @@ -31,7 +31,7 @@ void StakedBalanceObject::beginUnstakingTokens(ShareType amount, chainbase::data
});
}

void StakedBalanceObject::updateVotes(ShareType stakeDelta, chainbase::database& db) const {
void StakedBalanceObject::propagateVotes(ShareType stakeDelta, chainbase::database& db) const {
if (producerVotes.contains<ProducerSlate>())
// This account votes for producers directly; update their stakes
boost::for_each(producerVotes.get<ProducerSlate>().range(), [&db, &stakeDelta](const AccountName& name) {
Expand Down
8 changes: 6 additions & 2 deletions libraries/types/types.eos
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,13 @@ struct UpdateProducer
# implies message.sender account
struct ApproveProducer
producer AccountName
approve Int8 # 0 or 1
approve Int8 # 0 or 1

# implies message.sender account
# implies message.sender account
struct AllowVoteProxying
allow Int8 # 0 or 1

# implies message.sender account
struct SetVoteProxy
proxy AccountName

Expand Down

0 comments on commit 55ce118

Please sign in to comment.