Skip to content

Commit

Permalink
comments + more fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dmkozh committed Jun 25, 2024
1 parent 8d7b2fb commit c10675f
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 71 deletions.
27 changes: 14 additions & 13 deletions src/herder/TxSetFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,8 @@ makeTxSetFromTransactions(PerPhaseTransactionList const& txPhases,
.header.ledgerVersion,
PARALLEL_SOROBAN_PHASE_PROTOCOL_VERSION))
{
validatedPhases.emplace_back(std::move(includedTxs),
inclusionFeeMap);
validatedPhases.emplace_back(
TxSetPhaseFrame(std::move(includedTxs), inclusionFeeMap));
}
// This is a temporary stub for building a valid parallel tx set
// without any parallelization.
Expand All @@ -800,7 +800,8 @@ makeTxSetFromTransactions(PerPhaseTransactionList const& txPhases,
{
stages.emplace_back().emplace_back().push_back(includedTxs);
}
validatedPhases.emplace_back(std::move(stages), inclusionFeeMap);
validatedPhases.emplace_back(
TxSetPhaseFrame(std::move(stages), inclusionFeeMap));
}
}

Expand Down Expand Up @@ -940,9 +941,10 @@ makeTxSetFromTransactions(TxFrameList txs, Application& app,
std::vector<TxSetPhaseFrame> overridePhases;
for (auto i = 0; i < resPhases.size(); ++i)
{
overridePhases.emplace_back(std::move(perPhaseTxs[i]),
std::make_shared<InclusionFeeMap>(
resPhases[i].getInclusionFeeMap()));
overridePhases.emplace_back(
TxSetPhaseFrame(std::move(perPhaseTxs[i]),
std::make_shared<InclusionFeeMap>(
resPhases[i].getInclusionFeeMap())));
}
res.second->mApplyOrderPhases = overridePhases;
res.first->mApplicableTxSetOverride = std::move(res.second);
Expand Down Expand Up @@ -1076,6 +1078,7 @@ TxSetXDRFrame::sizeTxTotal() const
totalSize += component.txsMaybeDiscountedFee().txs.size();
}
break;
#ifdef ENABLE_NEXT_PROTOCOL_VERSION_UNSAFE_FOR_PRODUCTION
case 1:
for (auto const& stage :
phase.parallelTxsComponent().executionStages)
Expand All @@ -1089,6 +1092,7 @@ TxSetXDRFrame::sizeTxTotal() const
}
}
break;
#endif
default:
break;
}
Expand Down Expand Up @@ -1422,8 +1426,7 @@ TxSetPhaseFrame::makeFromWire(Hash const& networkID,
break;
}
}
return std::make_optional<TxSetPhaseFrame>(std::move(txList),
inclusionFeeMapPtr);
return TxSetPhaseFrame(std::move(txList), inclusionFeeMapPtr);
}
#ifdef ENABLE_NEXT_PROTOCOL_VERSION_UNSAFE_FOR_PRODUCTION
case 1:
Expand Down Expand Up @@ -1492,8 +1495,7 @@ TxSetPhaseFrame::makeFromWire(Hash const& networkID,
return std::nullopt;
}
}
return std::make_optional<TxSetPhaseFrame>(std::move(stages),
inclusionFeeMapPtr);
return TxSetPhaseFrame(std::move(stages), inclusionFeeMapPtr);
}
#endif
}
Expand Down Expand Up @@ -1522,8 +1524,7 @@ TxSetPhaseFrame::makeFromWireLegacy(
{
inclusionFeeMap[tx] = baseFee;
}
return std::make_optional<TxSetPhaseFrame>(std::move(txList),
inclusionFeeMapPtr);
return TxSetPhaseFrame(std::move(txList), inclusionFeeMapPtr);
}

TxSetPhaseFrame
Expand Down Expand Up @@ -1720,7 +1721,7 @@ ApplicableTxSetFrame::getContentsHash() const
}

TxSetPhaseFrame const&
ApplicableTxSetFrame::getTxsForPhase(TxSetPhase phaseTxs) const
ApplicableTxSetFrame::getPhase(TxSetPhase phaseTxs) const
{
releaseAssert(static_cast<size_t>(phaseTxs) < mPhases.size());
return mPhases.at(static_cast<size_t>(phaseTxs));
Expand Down
170 changes: 136 additions & 34 deletions src/herder/TxSetFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ makeTxSetFromTransactions(TxFrameList txs, Application& app,
//
// Before even trying to validate and apply a TxSetXDRFrame it has
// to be interpreted and prepared for apply using the ledger state
// this TxSetXDRFrame refers to. This is typically performed by
// `prepareForApply` method.
// this TxSetXDRFrame refers to. This is performed by `prepareForApply` method.
class TxSetXDRFrame : public NonMovableOrCopyable
{
public:
Expand Down Expand Up @@ -151,8 +150,11 @@ class TxSetXDRFrame : public NonMovableOrCopyable
// Returns the hash of this tx set.
Hash const& getContentsHash() const;

// Returns the hash of the previous ledger that this tx set refers to.
Hash const& previousLedgerHash() const;

// Returns the total number of transactions in this tx set (even if it's
// not structurally valid).
size_t sizeTxTotal() const;

// Gets the size of this transaction set in operations.
Expand Down Expand Up @@ -187,37 +189,70 @@ class TxSetXDRFrame : public NonMovableOrCopyable
Hash mHash;
};

// The following definitions are used to represent the 'parallel' phase of the
// transaction set.
//
// The structure of this phase is as follows:
// - The whole phase (`TxStageFrameList`) consists of several sequential
// 'stages' (`TxStageFrame`). A stage has to be executed after every
// transaction in the previous stage has been applied.
// - A 'stage' (`TxStageFrame`) consists of several parallel 'threads'
// (`TxThreadFrame`). Transactions in different 'threads' are independent of
// each other and can be applied in parallel.
// - A 'thread' (`TxThreadFrame`) consists of several 'clusters' (every one is
// just a list of transactions, `TxFrameList`). Transactions in the same
// 'cluster' are dependent on each other and must be applied in deterministic
// order. The clusters are independent of each other and may be applied in
// *different* threads in parallel.
//
// This structure mimics the XDR structure of the `ParallelTxsComponent`.
using TxThreadFrame = std::vector<TxFrameList>;
using TxStageFrame = std::vector<TxThreadFrame>;
using TxStageFrameList = std::vector<TxStageFrame>;

// Alias for the map from transaction to its inclusion fee as defined by the
// transaction set.
using InclusionFeeMap =
std::unordered_map<TransactionFrameBaseConstPtr, std::optional<int64_t>>;

// `TxSetPhaseFrame` represents a single phase of the `ApplicableTxSetFrame`.
//
// Phases can only be created as a part of the `ApplicableTxSetFrame` and thus
// don't have any public constructors.
//
// Phase may either wrap the corresponding `TransactionPhase` XDR for
// generalized transactions sets, or represent all the transactions in the
// 'legacy' transaction set (which is considered to have only a single phase).
//
// This does not assume any specific order of transactions by default - the
// phase in 'apply' order has to be explicitly requested from the parent
// `ApplicableTxSetFrame` via `getPhasesInApplyOrder` method.
class TxSetPhaseFrame
{
public:
static std::optional<TxSetPhaseFrame>
makeFromWire(Hash const& networkID, TransactionPhase const& xdrPhase);

static std::optional<TxSetPhaseFrame>
makeFromWireLegacy(LedgerHeader const& lclHeader, Hash const& networkID,
xdr::xvector<TransactionEnvelope> const& xdrTxs);

static TxSetPhaseFrame makeEmpty(bool isParallel);

TxSetPhaseFrame(TxFrameList&& txs,
std::shared_ptr<InclusionFeeMap> inclusionFeeMap);
TxSetPhaseFrame(TxStageFrameList&& txs,
std::shared_ptr<InclusionFeeMap> inclusionFeeMap);

// Returns true when this phase can be applied in parallel.
// Currently only Soroban phase can be parallel, and only starting from
// PARALLEL_SOROBAN_PHASE_PROTOCOL_VERSION protocol
bool isParallel() const;

// Returns the parallel stages of this phase.
//
// This may only be called when `isParallel()` is true.
TxStageFrameList const& getParallelStages() const;
// Returns all the transactions in this phase if it's not parallel.
//
// This may only be called when `isParallel()` is false.
TxFrameList const& getNonParallelTxs() const;

// Serializes this phase to the provided XDR.
void toXDR(TransactionPhase& xdrPhase) const;

// Iterator over the all transactions in this phase.
// The order of iteration is defined by the parent `ApplicableTxSetFrame`.
// If the phase is sorted for apply, then the iteration order can be used
// to determine a stable index of every transaction in the phase, even if
// the phase is parallel and can have certain transaction applied in
// arbitrary order.
class Iterator
{
public:
Expand Down Expand Up @@ -251,14 +286,57 @@ class TxSetPhaseFrame
size_t size() const;
bool empty() const;

// Get _inclusion_ fee map for a given phase. The map contains lowest base
// Get _inclusion_ fee map for this phase. The map contains lowest base
// fee for each transaction (lowest base fee is identical for all
// transactions in the same lane)
InclusionFeeMap const& getInclusionFeeMap() const;

private:
friend class TxSetXDRFrame;
friend class ApplicableTxSetFrame;

friend std::pair<TxSetXDRFrameConstPtr, ApplicableTxSetFrameConstPtr>
makeTxSetFromTransactions(PerPhaseTransactionList const& txPhases,
Application& app,
uint64_t lowerBoundCloseTimeOffset,
uint64_t upperBoundCloseTimeOffset,
PerPhaseTransactionList& invalidTxsPerPhase
#ifdef BUILD_TESTS
,
bool skipValidation
#endif
);
#ifdef BUILD_TESTS
friend std::pair<TxSetXDRFrameConstPtr, ApplicableTxSetFrameConstPtr>
makeTxSetFromTransactions(TxFrameList txs, Application& app,
uint64_t lowerBoundCloseTimeOffset,
uint64_t upperBoundCloseTimeOffset,
TxFrameList& invalidTxs,
bool enforceTxsApplyOrder);
#endif

TxSetPhaseFrame(TxFrameList&& txs,
std::shared_ptr<InclusionFeeMap> inclusionFeeMap);
TxSetPhaseFrame(TxStageFrameList&& txs,
std::shared_ptr<InclusionFeeMap> inclusionFeeMap);

// Creates a new phase from `TransactionPhase` XDR coming from a
// `GeneralizedTransactionSet`.
static std::optional<TxSetPhaseFrame>
makeFromWire(Hash const& networkID, TransactionPhase const& xdrPhase);

// Creates a new phase from all the transactions in the legacy
// `TransactionSet` XDR.
static std::optional<TxSetPhaseFrame>
makeFromWireLegacy(LedgerHeader const& lclHeader, Hash const& networkID,
xdr::xvector<TransactionEnvelope> const& xdrTxs);

// Creates a valid empty phase with given `isParallel` flag.
static TxSetPhaseFrame makeEmpty(bool isParallel);

// Returns a copy of this phase with transactions sorted for apply.
TxSetPhaseFrame sortedForApply(Hash const& txSetHash) const;

private:
std::shared_ptr<InclusionFeeMap> mInclusionFeeMap;
std::variant<TxFrameList, TxStageFrameList> mTxs;
};
Expand All @@ -280,47 +358,61 @@ class ApplicableTxSetFrame
std::optional<int64_t>
getTxBaseFee(TransactionFrameBaseConstPtr const& tx) const;

// Gets all the transactions belonging to this frame in arbitrary order.
TxSetPhaseFrame const& getTxsForPhase(TxSetPhase phase) const;
// Gets the phase frame for the given phase in arbitrary order.
TxSetPhaseFrame const& getPhase(TxSetPhase phase) const;

// Gets all the phases of this tx set with transactions in arbitrary order.
// Gets all the phases of this transaction set with transactions in
// arbitrary order.
std::vector<TxSetPhaseFrame> const& getPhases() const;

// Build a list of transaction ready to be applied to the last closed
// ledger, based on the transaction set.
// Gets all the phases of this transaction set, each phase with
// transactions sorted for apply.
//
// For the generalized transaction sets, the order is defined by shuffling
// all the transactions that are applied sequentially relatively to each
// other using the hash of the transaction set.
//
// The order satisfies:
// * transactions for an account are sorted by sequence number (ascending)
// * the order between accounts is randomized
// For the legacy transaction sets, the apply order satisfies :
// - Transactions for an account are sorted by sequence number (ascending).
// - The order between accounts is randomized.
std::vector<TxSetPhaseFrame> const& getPhasesInApplyOrder() const;

// Checks if this tx set frame is valid in the context of the current LCL.
// Checks if this transaction set frame is valid in the context of the
// current LCL.
// This can be called when LCL does not match `previousLedgerHash`, but
// then validation will never pass.
bool checkValid(Application& app, uint64_t lowerBoundCloseTimeOffset,
uint64_t upperBoundCloseTimeOffset) const;

// Returns the size of this whole transaction set, or the specified phase
// in operations or transactions (for older protocol versions).
size_t size(LedgerHeader const& lh,
std::optional<TxSetPhase> phase = std::nullopt) const;

// Returns the total number of transactions in the given phase.
size_t sizeTx(TxSetPhase phase) const;
// Returns the total number of transactions in this tx set.
size_t sizeTxTotal() const;

// Returns the total number of operations in the given phase.
size_t sizeOp(TxSetPhase phase) const;
// Returns the total number of operations in this tx set.
size_t sizeOpTotal() const;

// Returns whether this transaction set is empty.
bool
empty() const
{
return sizeTxTotal() == 0;
}

// Returns the number of phases in this tx set.
size_t
numPhases() const
{
return mPhases.size();
}

size_t sizeOp(TxSetPhase phase) const;
size_t sizeOpTotal() const;

// Returns the sum of all fees that this transaction set would take.
int64_t getTotalFees(LedgerHeader const& lh) const;

Expand All @@ -329,15 +421,17 @@ class ApplicableTxSetFrame
int64_t getTotalInclusionFees() const;

// Returns whether this transaction set is generalized, i.e. representable
// by GeneralizedTransactionSet XDR.
// by `GeneralizedTransactionSet` XDR.
bool isGeneralizedTxSet() const;

// Returns a short description of this transaction set.
// Returns a short description of this transaction set for logging.
std::string summary() const;

// Returns the hash of this transaction set.
Hash const& getContentsHash() const;

// This shouldn't be needed for the regular flows, but is useful
// Converts this transaction set to XDR.
// This shouldn't be exposed for the regular flows, but is useful to expose
// to cover XDR roundtrips in tests.
#ifndef BUILD_TESTS
private:
Expand All @@ -346,6 +440,7 @@ class ApplicableTxSetFrame

private:
friend class TxSetXDRFrame;

friend std::pair<TxSetXDRFrameConstPtr, ApplicableTxSetFrameConstPtr>
makeTxSetFromTransactions(PerPhaseTransactionList const& txPhases,
Application& app,
Expand Down Expand Up @@ -384,10 +479,17 @@ class ApplicableTxSetFrame

bool const mIsGeneralized;
Hash const mPreviousLedgerHash;

// All the phases of this transaction set.
//
// There can only be 1 phase (classic) prior to protocol 20.
// Starting with protocol 20, there are 2 phases (classic and Soroban).
std::vector<TxSetPhaseFrame> mPhases;
std::vector<TxSetPhaseFrame> const mPhases;

// The phases with transactions sorted for apply.
//
// This is `mutable` because we want to do the sorting lazily only for the
// transaction sets that are actually applied.
mutable std::vector<TxSetPhaseFrame> mApplyOrderPhases;

std::optional<Hash> mContentsHash;
Expand Down
Loading

0 comments on commit c10675f

Please sign in to comment.