Skip to content

Commit 3cf2844

Browse files
committed
Refund for parallel soroban
1 parent 9822c59 commit 3cf2844

12 files changed

+209
-67
lines changed

src/ledger/LedgerCloseMetaFrame.cpp

+76-13
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@ namespace stellar
1414
{
1515
LedgerCloseMetaFrame::LedgerCloseMetaFrame(uint32_t protocolVersion)
1616
{
17-
// The LedgerCloseMeta v() switch can be in 2 positions, 0 and 1. We
17+
// The LedgerCloseMeta v() switch can be in 3 positions, 0, 1, and 2. We
1818
// currently support all of these cases, depending on both compile time
1919
// and runtime conditions.
2020
mVersion = 0;
2121

22-
if (protocolVersionStartsFrom(protocolVersion, SOROBAN_PROTOCOL_VERSION))
22+
if (protocolVersionStartsFrom(protocolVersion,
23+
PARALLEL_SOROBAN_PHASE_PROTOCOL_VERSION))
24+
{
25+
mVersion = 2;
26+
}
27+
else if (protocolVersionStartsFrom(protocolVersion,
28+
SOROBAN_PROTOCOL_VERSION))
2329
{
2430
mVersion = 1;
2531
}
@@ -35,6 +41,8 @@ LedgerCloseMetaFrame::ledgerHeader()
3541
return mLedgerCloseMeta.v0().ledgerHeader;
3642
case 1:
3743
return mLedgerCloseMeta.v1().ledgerHeader;
44+
case 2:
45+
return mLedgerCloseMeta.v2().ledgerHeader;
3846
default:
3947
releaseAssert(false);
4048
}
@@ -51,6 +59,9 @@ LedgerCloseMetaFrame::reserveTxProcessing(size_t n)
5159
case 1:
5260
mLedgerCloseMeta.v1().txProcessing.reserve(n);
5361
break;
62+
case 2:
63+
mLedgerCloseMeta.v2().txProcessing.reserve(n);
64+
break;
5465
default:
5566
releaseAssert(false);
5667
}
@@ -67,6 +78,9 @@ LedgerCloseMetaFrame::pushTxProcessingEntry()
6778
case 1:
6879
mLedgerCloseMeta.v1().txProcessing.emplace_back();
6980
break;
81+
case 2:
82+
mLedgerCloseMeta.v2().txProcessing.emplace_back();
83+
break;
7084
default:
7185
releaseAssert(false);
7286
}
@@ -84,6 +98,9 @@ LedgerCloseMetaFrame::setLastTxProcessingFeeProcessingChanges(
8498
case 1:
8599
mLedgerCloseMeta.v1().txProcessing.back().feeProcessing = changes;
86100
break;
101+
case 2:
102+
mLedgerCloseMeta.v2().txProcessing.back().feeProcessing = changes;
103+
break;
87104
default:
88105
releaseAssert(false);
89106
}
@@ -109,11 +126,27 @@ LedgerCloseMetaFrame::setTxProcessingMetaAndResultPair(
109126
txp.result = std::move(rp);
110127
}
111128
break;
129+
case 2:
130+
{
131+
auto& txp = mLedgerCloseMeta.v2().txProcessing.at(index);
132+
txp.txApplyProcessing = tm;
133+
txp.result = std::move(rp);
134+
}
135+
break;
112136
default:
113137
releaseAssert(false);
114138
}
115139
}
116140

141+
void
142+
LedgerCloseMetaFrame::setPostTxApplyFeeProcessingChanges(
143+
LedgerEntryChanges const& changes, int index)
144+
{
145+
releaseAssert(mVersion == 2);
146+
mLedgerCloseMeta.v2().txProcessing.at(index).postTxApplyFeeProcessing =
147+
changes;
148+
}
149+
117150
xdr::xvector<UpgradeEntryMeta>&
118151
LedgerCloseMetaFrame::upgradesProcessing()
119152
{
@@ -123,6 +156,8 @@ LedgerCloseMetaFrame::upgradesProcessing()
123156
return mLedgerCloseMeta.v0().upgradesProcessing;
124157
case 1:
125158
return mLedgerCloseMeta.v1().upgradesProcessing;
159+
case 2:
160+
return mLedgerCloseMeta.v2().upgradesProcessing;
126161
default:
127162
releaseAssert(false);
128163
}
@@ -139,6 +174,9 @@ LedgerCloseMetaFrame::populateTxSet(TxSetXDRFrame const& txSet)
139174
case 1:
140175
txSet.toXDR(mLedgerCloseMeta.v1().txSet);
141176
break;
177+
case 2:
178+
txSet.toXDR(mLedgerCloseMeta.v2().txSet);
179+
break;
142180
default:
143181
releaseAssert(false);
144182
}
@@ -148,35 +186,60 @@ void
148186
LedgerCloseMetaFrame::populateEvictedEntries(
149187
EvictedStateVectors const& evictedState)
150188
{
151-
releaseAssert(mVersion == 1);
189+
releaseAssert(mVersion == 1 || mVersion == 2);
190+
auto& evictedTemporaryLedgerKeys =
191+
mVersion == 1 ? mLedgerCloseMeta.v1().evictedTemporaryLedgerKeys
192+
: mLedgerCloseMeta.v2().evictedTemporaryLedgerKeys;
152193
for (auto const& key : evictedState.deletedKeys)
153194
{
154195
releaseAssertOrThrow(isTemporaryEntry(key) || key.type() == TTL);
155-
mLedgerCloseMeta.v1().evictedTemporaryLedgerKeys.emplace_back(key);
196+
evictedTemporaryLedgerKeys.emplace_back(key);
156197
}
157198
for (auto const& entry : evictedState.archivedEntries)
158199
{
159200
releaseAssertOrThrow(isPersistentEntry(entry.data));
160201
// Unfortunately, for legacy purposes, evictedTemporaryLedgerKeys is
161202
// misnamed and stores all evicted keys, both temp and persistent.
162-
mLedgerCloseMeta.v1().evictedTemporaryLedgerKeys.emplace_back(
163-
LedgerEntryKey(entry));
203+
evictedTemporaryLedgerKeys.emplace_back(LedgerEntryKey(entry));
164204
}
165205
}
166206

167207
void
168208
LedgerCloseMetaFrame::setNetworkConfiguration(
169209
SorobanNetworkConfig const& networkConfig, bool emitExtV1)
170210
{
171-
releaseAssert(mVersion == 1);
172-
mLedgerCloseMeta.v1().totalByteSizeOfBucketList =
173-
networkConfig.getAverageBucketListSize();
211+
releaseAssert(mVersion == 1 || mVersion == 2);
174212

175-
if (emitExtV1)
213+
switch (mVersion)
214+
{
215+
case 1:
176216
{
177-
mLedgerCloseMeta.v1().ext.v(1);
178-
auto& ext = mLedgerCloseMeta.v1().ext.v1();
179-
ext.sorobanFeeWrite1KB = networkConfig.feeWrite1KB();
217+
mLedgerCloseMeta.v1().totalByteSizeOfBucketList =
218+
networkConfig.getAverageBucketListSize();
219+
220+
if (emitExtV1)
221+
{
222+
mLedgerCloseMeta.v1().ext.v(1);
223+
auto& ext = mLedgerCloseMeta.v1().ext.v1();
224+
ext.sorobanFeeWrite1KB = networkConfig.feeWrite1KB();
225+
}
226+
break;
227+
}
228+
case 2:
229+
{
230+
mLedgerCloseMeta.v2().totalByteSizeOfBucketList =
231+
networkConfig.getAverageBucketListSize();
232+
233+
if (emitExtV1)
234+
{
235+
mLedgerCloseMeta.v2().ext.v(1);
236+
auto& ext = mLedgerCloseMeta.v1().ext.v1();
237+
ext.sorobanFeeWrite1KB = networkConfig.feeWrite1KB();
238+
}
239+
break;
240+
}
241+
default:
242+
releaseAssert(false);
180243
}
181244
}
182245

src/ledger/LedgerCloseMetaFrame.h

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class LedgerCloseMetaFrame
2626
TransactionResultPair&& rp,
2727
int index);
2828

29+
void setPostTxApplyFeeProcessingChanges(LedgerEntryChanges const& changes,
30+
int index);
31+
2932
xdr::xvector<UpgradeEntryMeta>& upgradesProcessing();
3033

3134
void populateTxSet(TxSetXDRFrame const& txSet);

src/ledger/LedgerManagerImpl.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -1952,10 +1952,8 @@ LedgerManagerImpl::applySorobanStage(AppConnector& app, AbstractLedgerTxn& ltx,
19521952
}
19531953
}
19541954

1955-
// Need to processPostApply after entries are updated because the refund can
1956-
// update an account entry that was updated during apply.
1957-
1958-
// TODO: Change this so the refund is observable after a transaction.
1955+
// processPostApply is a noop starting from v23 because the refund happens
1956+
// in processPostTxApplyFeeProcessing. Should we still keep this?
19591957
for (auto const& thread : stage)
19601958
{
19611959
for (auto const& txBundle : thread)
@@ -2057,6 +2055,14 @@ LedgerManagerImpl::applyTransactions(
20572055
{
20582056
for (auto const& txBundle : thread)
20592057
{
2058+
// TODO: This should actually be done after all phases.
2059+
// Soroban is the last phase, so this works for now,
2060+
// but it is a footgun.
2061+
auto refundChanges =
2062+
txBundle.getTx()->processPostTxApplyFeeProcessing(
2063+
mApp.getAppConnector(), ltx,
2064+
txBundle.getResPayload());
2065+
20602066
TransactionResultPair results;
20612067
results.transactionHash =
20622068
txBundle.getTx()->getContentsHash();
@@ -2091,6 +2097,9 @@ LedgerManagerImpl::applyTransactions(
20912097
ledgerCloseMeta->setTxProcessingMetaAndResultPair(
20922098
txBundle.getEffects().getMeta().getXDR(),
20932099
std::move(results), txBundle.getTxNum());
2100+
2101+
ledgerCloseMeta->setPostTxApplyFeeProcessingChanges(
2102+
refundChanges, txBundle.getTxNum());
20942103
}
20952104
}
20962105
}

src/transactions/FeeBumpTransactionFrame.cpp

+23-6
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,29 @@ FeeBumpTransactionFrame::processPostApply(AppConnector& app,
220220
TransactionMetaFrame& meta,
221221
MutableTxResultPtr txResult) const
222222
{
223-
// We must forward the Fee-bump source so the refund is applied to the
224-
// correct account
225-
// Note that we are not calling TransactionFrame::processPostApply, so if
226-
// any logic is added there, we would have to reason through if that logic
227-
// should also be reflected here.
228-
mInnerTx->processRefund(app, ltx, meta, getFeeSourceID(), *txResult);
223+
uint32_t ledgerVersion = ltx.loadHeader().current().ledgerVersion;
224+
if (protocolVersionIsBefore(ledgerVersion, ProtocolVersion::V_23))
225+
{
226+
// We must forward the Fee-bump source so the refund is applied to the
227+
// correct account
228+
// Note that we are not calling TransactionFrame::processPostApply, so
229+
// if any logic is added there, we would have to reason through if that
230+
// logic should also be reflected here.
231+
auto changes =
232+
mInnerTx->processRefund(app, ltx, getFeeSourceID(), *txResult);
233+
if (!changes.empty())
234+
{
235+
meta.pushTxChangesAfter(std::move(changes));
236+
}
237+
}
238+
}
239+
240+
LedgerEntryChanges
241+
FeeBumpTransactionFrame::processPostTxApplyFeeProcessing(
242+
AppConnector& app, AbstractLedgerTxn& ltx,
243+
MutableTxResultPtr txResult) const
244+
{
245+
return mInnerTx->processRefund(app, ltx, getFeeSourceID(), *txResult);
229246
}
230247

231248
bool

src/transactions/FeeBumpTransactionFrame.h

+4
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ class FeeBumpTransactionFrame : public TransactionFrameBase
9393
TransactionMetaFrame& meta,
9494
MutableTxResultPtr txResult) const override;
9595

96+
LedgerEntryChanges
97+
processPostTxApplyFeeProcessing(AppConnector& app, AbstractLedgerTxn& ltx,
98+
MutableTxResultPtr txResult) const override;
99+
96100
MutableTxResultPtr
97101
checkValid(AppConnector& app, LedgerSnapshot const& ls,
98102
SequenceNumber current, uint64_t lowerBoundCloseTimeOffset,

src/transactions/TransactionFrame.cpp

+23-7
Original file line numberDiff line numberDiff line change
@@ -2405,33 +2405,49 @@ TransactionFrame::processPostApply(AppConnector& app,
24052405
AbstractLedgerTxn& ltxOuter,
24062406
TransactionMetaFrame& meta,
24072407
MutableTxResultPtr txResult) const
2408+
{
2409+
uint32_t ledgerVersion = ltxOuter.loadHeader().current().ledgerVersion;
2410+
if (protocolVersionIsBefore(ledgerVersion, ProtocolVersion::V_23))
2411+
{
2412+
releaseAssertOrThrow(txResult);
2413+
auto changes = processRefund(app, ltxOuter, getSourceID(), *txResult);
2414+
if (!changes.empty())
2415+
{
2416+
meta.pushTxChangesAfter(std::move(changes));
2417+
}
2418+
}
2419+
}
2420+
2421+
LedgerEntryChanges
2422+
TransactionFrame::processPostTxApplyFeeProcessing(
2423+
AppConnector& app, AbstractLedgerTxn& ltx,
2424+
MutableTxResultPtr txResult) const
24082425
{
24092426
releaseAssertOrThrow(txResult);
2410-
processRefund(app, ltxOuter, meta, getSourceID(), *txResult);
2427+
return processRefund(app, ltx, getSourceID(), *txResult);
24112428
}
24122429

24132430
// This is a TransactionFrame specific function that should only be used by
24142431
// FeeBumpTransactionFrame to forward a different account for the refund.
2415-
int64_t
2432+
LedgerEntryChanges
24162433
TransactionFrame::processRefund(AppConnector& app, AbstractLedgerTxn& ltxOuter,
2417-
TransactionMetaFrame& meta,
24182434
AccountID const& feeSource,
24192435
MutableTransactionResultBase& txResult) const
24202436
{
24212437
ZoneScoped;
24222438

24232439
if (!isSoroban())
24242440
{
2425-
return 0;
2441+
return {};
24262442
}
24272443
// Process Soroban resource fee refund (this is independent of the
24282444
// transaction success).
24292445
LedgerTxn ltx(ltxOuter);
2430-
int64_t refund = refundSorobanFee(ltx, feeSource, txResult);
2431-
meta.pushTxChangesAfter(ltx.getChanges());
2446+
refundSorobanFee(ltx, feeSource, txResult);
2447+
auto changes = ltx.getChanges();
24322448
ltx.commit();
24332449

2434-
return refund;
2450+
return changes;
24352451
}
24362452

24372453
std::shared_ptr<StellarMessage const>

src/transactions/TransactionFrame.h

+11-6
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,18 @@ class TransactionFrame : public TransactionFrameBase
277277
TransactionMetaFrame& meta,
278278
MutableTxResultPtr txResult) const override;
279279

280+
// After all transactions have been applied. Currently only used
281+
// for refunds in parallel Soroban.
282+
LedgerEntryChanges
283+
processPostTxApplyFeeProcessing(AppConnector& app, AbstractLedgerTxn& ltx,
284+
MutableTxResultPtr txResult) const override;
285+
280286
// TransactionFrame specific function that allows fee bumps to forward a
281-
// different account for the refund. It also returns the refund so
282-
// FeeBumpTransactionFrame can adjust feeCharged.
283-
int64_t processRefund(AppConnector& app, AbstractLedgerTxn& ltx,
284-
TransactionMetaFrame& meta,
285-
AccountID const& feeSource,
286-
MutableTransactionResultBase& txResult) const;
287+
// different account for the refund.
288+
LedgerEntryChanges
289+
processRefund(AppConnector& app, AbstractLedgerTxn& ltx,
290+
AccountID const& feeSource,
291+
MutableTransactionResultBase& txResult) const;
287292

288293
// version without meta
289294
bool apply(AppConnector& app, AbstractLedgerTxn& ltx,

src/transactions/TransactionFrameBase.h

+6
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,16 @@ class TransactionFrameBase
286286
processFeeSeqNum(AbstractLedgerTxn& ltx,
287287
std::optional<int64_t> baseFee) const = 0;
288288

289+
// After this transaction has been applied
289290
virtual void processPostApply(AppConnector& app, AbstractLedgerTxn& ltx,
290291
TransactionMetaFrame& meta,
291292
MutableTxResultPtr txResult) const = 0;
292293

294+
// After all transactions have been applied
295+
virtual LedgerEntryChanges
296+
processPostTxApplyFeeProcessing(AppConnector& app, AbstractLedgerTxn& ltx,
297+
MutableTxResultPtr txResult) const = 0;
298+
293299
virtual std::shared_ptr<StellarMessage const> toStellarMessage() const = 0;
294300

295301
virtual bool hasDexOperations() const = 0;

0 commit comments

Comments
 (0)