void AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) { // LCL must be flag ledger assert((lastClosedLedger->getLedgerSeq () % 256) == 0); AmendmentSet amendmentSet (lastClosedLedger->getParentCloseTimeNC ()); // get validations for ledger before flag ledger ValidationSet valSet = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ()); for (auto const& entry : valSet) { auto const& val = *entry.second; if (val.isTrusted ()) { amendmentSet.addVoter (); if (val.isFieldPresent (sfAmendments)) { for (auto const& amendment : val.getFieldV256 (sfAmendments)) { amendmentSet.addVote (amendment); } } } } reportValidations (amendmentSet); amendmentList_t lAmendments = getToEnable (lastClosedLedger->getCloseTimeNC ()); for (auto const& uAmendment : lAmendments) { if (m_journal.warning) m_journal.warning << "Voting for amendment: " << uAmendment; // Create the transaction to enable the amendment STTx trans (ttAMENDMENT); trans.setFieldAccount (sfAccount, Account ()); trans.setFieldH256 (sfAmendment, uAmendment); uint256 txID = trans.getTransactionID (); if (m_journal.warning) m_journal.warning << "Vote ID: " << txID; // Inject the transaction into our initial proposal Serializer s; trans.add (s, true); #if RIPPLE_PROPOSE_AMENDMENTS SHAMapItem::pointer tItem = std::make_shared<SHAMapItem> (txID, s.peekData ()); if (!initialPosition->addGiveItem (tItem, true, false)) { if (m_journal.warning) m_journal.warning << "Ledger already had amendment transaction"; } #endif } }
void dostartvoting(ledger::ref lastclosedledger, shamap::ref initialposition) override { // lcl must be validation ledger assert (isstartledger(lastclosedledger)); std::uint32_t dividendledger = lastclosedledger->getledgerseq(); std::map<std::pair<uint64_t, uint64_t>, int> votemap; // get validations for validation ledger validationset const set = getapp().getvalidations ().getvalidations (lastclosedledger->gethash ()); for (auto const& e : set) { stvalidation const& val = *e.second; if (val.istrusted ()) { if (val.isfieldpresent (sfdividendledger) && val.isfieldpresent (sfdividendcoins) && val.isfieldpresent (sfdividendcoinsvbc)) { uint32_t ledgerseq = val.getfieldu32 (sfdividendledger); if (ledgerseq != dividendledger) { m_journal.warning << "mismatch ledger seq " << ledgerseq << " from validator " << val.getnodeid() << " ours: " << dividendledger << " in " << lastclosedledger->gethash(); continue; } ++votemap[std::make_pair(val.getfieldu64 (sfdividendcoins), val.getfieldu64 (sfdividendcoinsvbc))]; } } } std::pair<uint64_t, uint64_t> ourvote = std::make_pair(0, 0); int weight = 0; for (auto const& e : votemap) { // take most voted value if (e.second > weight) { ourvote = e.first; weight = e.second; } } if (weight < getapp().getledgermaster().getminvalidations()) { m_journal.warning << weight << " votes are not enough to start dividend for " << dividendledger; return; } if (ourvote.first==0 && ourvote.second==0) { if (m_journal.warning) m_journal.warning << "not voting for a dividend start because both vrp and vbc voted are 0"; return; } if (ourvote.first + lastclosedledger->gettotalcoins() > vrp_increase_max && ourvote.second + lastclosedledger->gettotalcoinsvbc() > vbc_increase_max) { if (m_journal.error) m_journal.error << "not voting for a dividend start because both vrp and vbc will exceed max."; return; } if (m_journal.warning) m_journal.warning << "we are voting for a dividend start based " << dividendledger << " with vrp " << ourvote.first << " vbc " << ourvote.second << " with " << weight << " same votes in " << lastclosedledger->gethash(); sttx trans(ttdividend); trans.setfieldu8(sfdividendtype, dividendmaster::divtype_start); trans.setfieldaccount(sfaccount, account()); trans.setfieldu32(sfdividendledger, dividendledger); trans.setfieldu64(sfdividendcoins, ourvote.first); trans.setfieldu64(sfdividendcoinsvbc, ourvote.second); uint256 txid = trans.gettransactionid(); if (m_journal.warning) m_journal.warning << "vote: " << txid; serializer s; trans.add (s, true); shamapitem::pointer titem = std::make_shared<shamapitem> (txid, s.peekdata ()); if (!initialposition->addgiveitem (titem, true, false)) { if (m_journal.warning) m_journal.warning << "ledger already had dividend start"; } }
bool shamap::compare (shamap::ref othermap, delta& differences, int maxcount) { // compare two hash trees, add up to maxcount differences to the difference table // return value: true=complete table of differences given, false=too many differences // throws on corrupt tables or missing nodes // caution: othermap is not locked and must be immutable assert (isvalid () && othermap && othermap->isvalid ()); using stackentry = std::pair <shamaptreenode*, shamaptreenode*>; std::stack <stackentry, std::vector<stackentry>> nodestack; // track nodes we've pushed if (gethash () == othermap->gethash ()) return true; nodestack.push ({root.get(), othermap->root.get()}); while (!nodestack.empty ()) { shamaptreenode* ournode = nodestack.top().first; shamaptreenode* othernode = nodestack.top().second; nodestack.pop (); if (!ournode || !othernode) { assert (false); throw shamapmissingnode (mtype, uint256 ()); } if (ournode->isleaf () && othernode->isleaf ()) { // two leaves if (ournode->gettag () == othernode->gettag ()) { if (ournode->peekdata () != othernode->peekdata ()) { differences.insert (std::make_pair (ournode->gettag (), deltaref (ournode->peekitem (), othernode->peekitem ()))); if (--maxcount <= 0) return false; } } else { differences.insert (std::make_pair(ournode->gettag (), deltaref(ournode->peekitem(), shamapitem::pointer ()))); if (--maxcount <= 0) return false; differences.insert(std::make_pair(othernode->gettag (), deltaref(shamapitem::pointer(), othernode->peekitem ()))); if (--maxcount <= 0) return false; } } else if (ournode->isinner () && othernode->isleaf ()) { if (!walkbranch (ournode, othernode->peekitem (), true, differences, maxcount)) return false; } else if (ournode->isleaf () && othernode->isinner ()) { if (!othermap->walkbranch (othernode, ournode->peekitem (), false, differences, maxcount)) return false; } else if (ournode->isinner () && othernode->isinner ()) { for (int i = 0; i < 16; ++i) if (ournode->getchildhash (i) != othernode->getchildhash (i)) { if (othernode->isemptybranch (i)) { // we have a branch, the other tree does not shamaptreenode* inode = descendthrow (ournode, i); if (!walkbranch (inode, shamapitem::pointer (), true, differences, maxcount)) return false; } else if (ournode->isemptybranch (i)) { // the other tree has a branch, we do not shamaptreenode* inode = othermap->descendthrow(othernode, i); if (!othermap->walkbranch (inode, shamapitem::pointer(), false, differences, maxcount)) return false; } else // the two trees have different non-empty branches nodestack.push ({descendthrow (ournode, i), othermap->descendthrow (othernode, i)}); } } else assert (false); } return true; }
void FeeVoteImpl::doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) { // LCL must be flag ledger assert ((lastClosedLedger->getLedgerSeq () % 256) == 0); detail::VotableInteger<std::uint64_t> baseFeeVote ( lastClosedLedger->getBaseFee (), target_.reference_fee); detail::VotableInteger<std::uint32_t> baseReserveVote ( lastClosedLedger->getReserve (0), target_.account_reserve); detail::VotableInteger<std::uint32_t> incReserveVote ( lastClosedLedger->getReserveInc (), target_.owner_reserve); // get validations for ledger before flag ValidationSet const set = getApp().getValidations ().getValidations ( lastClosedLedger->getParentHash ()); for (auto const& e : set) { SerializedValidation const& val = *e.second; if (val.isTrusted ()) { if (val.isFieldPresent (sfBaseFee)) { baseFeeVote.addVote (val.getFieldU64 (sfBaseFee)); } else { baseFeeVote.noVote (); } if (val.isFieldPresent (sfReserveBase)) { baseReserveVote.addVote (val.getFieldU32 (sfReserveBase)); } else { baseReserveVote.noVote (); } if (val.isFieldPresent (sfReserveIncrement)) { incReserveVote.addVote (val.getFieldU32 (sfReserveIncrement)); } else { incReserveVote.noVote (); } } } // choose our positions std::uint64_t const baseFee = baseFeeVote.getVotes (); std::uint32_t const baseReserve = baseReserveVote.getVotes (); std::uint32_t const incReserve = incReserveVote.getVotes (); // add transactions to our position if ((baseFee != lastClosedLedger->getBaseFee ()) || (baseReserve != lastClosedLedger->getReserve (0)) || (incReserve != lastClosedLedger->getReserveInc ())) { if (journal_.warning) journal_.warning << "We are voting for a fee change: " << baseFee << "/" << baseReserve << "/" << incReserve; SerializedTransaction trans (ttFEE); trans.setFieldAccount (sfAccount, Account ()); trans.setFieldU64 (sfBaseFee, baseFee); trans.setFieldU32 (sfReferenceFeeUnits, 10); trans.setFieldU32 (sfReserveBase, baseReserve); trans.setFieldU32 (sfReserveIncrement, incReserve); uint256 txID = trans.getTransactionID (); if (journal_.warning) journal_.warning << "Vote: " << txID; Serializer s; trans.add (s, true); SHAMapItem::pointer tItem = std::make_shared<SHAMapItem> ( txID, s.peekData ()); if (!initialPosition->addGiveItem (tItem, true, false)) { if (journal_.warning) journal_.warning << "Ledger already had fee change"; } } }