Skip to content

Commit 9819d1b

Browse files
authored
Track Soroban in-memory state size and store it in p23. (#4809)
# Description This adds the state size tracking mechanism to InMemorySorobanState. The size includes the size of the parsed Wasm modules and thus has to be recomputed on the protocol and relevant setting upgrades. We'll start tracking the state size as soon as we're in Soroban protocol, but will only use it in p23. Because of that we can use p23 host to compute the memory cost for contract code entries eagerly. This does a few non-trivial things on upgrades: - When we perform a memory cost settings upgrade (even in p22) we recompute the contract code in-memory size. If we are in p23+, we also fill the state size window with the current in-memory state size. - When we upgrade to p23, we immediately fill the state size window with the current in-memory state size, but don't recompute the contract code size (it's already up to date) - When we upgrade to p24+, we recompute the contract code size and fill the state window with the current in-memory state size All these cases are covered in the respective new tests. There is also a bunch of test-related TODOs here that can be addressed later - they shouldn't influence the change coverage significantly. # Checklist - [ ] Reviewed the [contributing](https://github.com/stellar/stellar-core/blob/master/CONTRIBUTING.md#submitting-changes) document - [ ] Rebased on top of master (no merge commits) - [ ] Ran `clang-format` v8.0.0 (via `make format` or the Visual Studio extension) - [ ] Compiles - [ ] Ran all tests - [ ] If change impacts performance, include supporting evidence per the [performance document](https://github.com/stellar/stellar-core/blob/master/performance-eval/performance-eval.md)
2 parents 54a9c76 + 55a3bc2 commit 9819d1b

40 files changed

+3062
-2138
lines changed

Builds/VisualStudio/stellar-core.vcxproj.filters

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,9 @@
14111411
<ClCompile Include="..\..\src\transactions\ParallelApplyUtils.cpp">
14121412
<Filter>transactions</Filter>
14131413
</ClCompile>
1414-
<ClCompile Include="..\..\src\ledger\InMemorySorobanState.cpp" />
1414+
<ClCompile Include="..\..\src\ledger\InMemorySorobanState.cpp">
1415+
<Filter>ledger</Filter>
1416+
</ClCompile>
14151417
</ItemGroup>
14161418
<ItemGroup>
14171419
<ClInclude Include="..\..\lib\util\cpptoml.h">
@@ -2504,6 +2506,9 @@
25042506
<Filter>transactions</Filter>
25052507
</ClInclude>
25062508
<ClInclude Include="..\..\src\ledger\InMemorySorobanState.h" />
2509+
<ClInclude Include="..\..\src\ledger\InMemorySorobanState.h">
2510+
<Filter>ledger</Filter>
2511+
</ClInclude>
25072512
</ItemGroup>
25082513
<ItemGroup>
25092514
<None Include="..\..\AUTHORS" />

src/bucket/HotArchiveBucketIndex.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class HotArchiveBucketIndex : public NonMovableOrCopyable
9494
uint32_t
9595
getPageSize() const
9696
{
97-
return mDiskIndex.getPageSize();
97+
return static_cast<uint32_t>(mDiskIndex.getPageSize());
9898
}
9999

100100
IterT
@@ -118,4 +118,4 @@ class HotArchiveBucketIndex : public NonMovableOrCopyable
118118
bool operator==(HotArchiveBucketIndex const& in) const;
119119
#endif
120120
};
121-
}
121+
}

src/bucket/test/BucketIndexTests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,8 @@ TEST_CASE("soroban cache population", "[soroban][bucketindex]")
11591159

11601160
// Now wipe cache and repopulate from scratch to test initialization on
11611161
// a non-empty bucketlist.
1162-
lm.rebuildInMemorySorobanStateForTesting();
1162+
lm.rebuildInMemorySorobanStateForTesting(
1163+
lm.getLastClosedLedgerHeader().header.ledgerVersion);
11631164
testCache();
11641165
};
11651166

src/bucket/test/BucketListTests.cpp

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -878,10 +878,13 @@ TEST_CASE("BucketList check bucket sizes", "[bucket][bucketlist][count]")
878878
}
879879
}
880880

881-
TEST_CASE_VERSIONS("network config snapshots BucketList size", "[bucketlist]")
881+
TEST_CASE_VERSIONS("network config snapshots Soroban state size", "[soroban]")
882882
{
883883
VirtualClock clock;
884-
Config cfg(getTestConfig(0, Config::TESTDB_IN_MEMORY));
884+
// TODO(https://github.com/stellar/stellar-core/issues/4816): We should
885+
// be using the default DB mode here, and also update the window size to
886+
// make sure the upgrades work correctly.
887+
Config cfg(getTestConfig(0, Config::TestDbMode::TESTDB_IN_MEMORY));
885888
cfg.USE_CONFIG_FOR_GENESIS = true;
886889

887890
auto app = createTestApplication<BucketTestApplication>(clock, cfg);
@@ -891,6 +894,11 @@ TEST_CASE_VERSIONS("network config snapshots BucketList size", "[bucketlist]")
891894
auto networkConfig = [&]() {
892895
return app->getLedgerManager().getLastClosedSorobanNetworkConfig();
893896
};
897+
// Take snapshots more frequently for faster testing.
898+
modifySorobanNetworkConfig(*app, [](SorobanNetworkConfig& cfg) {
899+
cfg.mStateArchivalSettings.liveSorobanStateSizeWindowSamplePeriod =
900+
7;
901+
});
894902

895903
uint32_t windowSize = networkConfig()
896904
.stateArchivalSettings()
@@ -901,19 +909,28 @@ TEST_CASE_VERSIONS("network config snapshots BucketList size", "[bucketlist]")
901909
correctWindow.push_back(0);
902910
}
903911

904-
auto check = [&]() {
912+
auto check = [&](bool init = false) {
905913
// Check in-memory average from BucketManager
906914
uint64_t sum = 0;
907-
for (auto e : correctWindow)
915+
for (int i = 0; i < correctWindow.size(); ++i)
908916
{
909-
sum += e;
917+
// Ensure that we're actually increasing the state size.
918+
if (i < correctWindow.size() - 1 && correctWindow[i] != 0)
919+
{
920+
REQUIRE(correctWindow[i] < correctWindow[i + 1]);
921+
}
922+
sum += correctWindow[i];
910923
}
911924

912925
uint64_t correctAverage = sum / correctWindow.size();
926+
if (!init)
927+
{
928+
REQUIRE(correctAverage > 0);
929+
}
913930

914931
LedgerTxn ltx(app->getLedgerTxnRoot());
915-
REQUIRE(networkConfig().getAverageBucketListSize() ==
916-
correctAverage);
932+
auto const& networkCfg = networkConfig();
933+
REQUIRE(networkCfg.getAverageSorobanStateSize() == correctAverage);
917934

918935
// Check on-disk sliding window
919936
LedgerKey key(CONFIG_SETTING);
@@ -930,13 +947,7 @@ TEST_CASE_VERSIONS("network config snapshots BucketList size", "[bucketlist]")
930947
};
931948

932949
// Check initial conditions
933-
check();
934-
935-
// Take snapshots more frequently for faster testing
936-
modifySorobanNetworkConfig(*app, [](SorobanNetworkConfig& cfg) {
937-
cfg.mStateArchivalSettings.liveSorobanStateSizeWindowSamplePeriod =
938-
64;
939-
});
950+
check(true);
940951

941952
// Generate enough ledgers to fill sliding window
942953
auto ledgersToGenerate =
@@ -945,6 +956,7 @@ TEST_CASE_VERSIONS("network config snapshots BucketList size", "[bucketlist]")
945956
.liveSorobanStateSizeWindowSamplePeriod;
946957
auto lclSeq = lm.getLastClosedLedgerHeader().header.ledgerSeq;
947958
UnorderedSet<LedgerKey> generatedKeys;
959+
int const entryCount = 10;
948960
for (uint32_t ledger = lclSeq; ledger < ledgersToGenerate; ++ledger)
949961
{
950962
// Note: BucketList size in the sliding window is snapshotted before
@@ -957,16 +969,33 @@ TEST_CASE_VERSIONS("network config snapshots BucketList size", "[bucketlist]")
957969
0)
958970
{
959971
correctWindow.pop_front();
960-
correctWindow.push_back(
961-
app->getBucketManager().getLiveBucketList().getSize());
972+
uint64_t sizeSnapshot = 0;
973+
if (protocolVersionStartsFrom(app->getLedgerManager()
974+
.getLastClosedLedgerHeader()
975+
.header.ledgerVersion,
976+
ProtocolVersion::V_23))
977+
{
978+
sizeSnapshot =
979+
app->getLedgerManager().getSorobanInMemoryStateSize();
980+
}
981+
else
982+
{
983+
sizeSnapshot =
984+
app->getBucketManager().getLiveBucketList().getSize();
985+
}
986+
correctWindow.push_back(sizeSnapshot);
962987
}
963988

964-
// Exclude soroban types to avoid TTL invariants
965-
lm.setNextLedgerEntryBatchForBucketTesting(
966-
LedgerTestUtils::generateValidUniqueLedgerEntriesWithExclusions(
967-
{CONFIG_SETTING, TTL, CONTRACT_DATA, CONTRACT_CODE}, 10,
968-
generatedKeys),
969-
{}, {});
989+
auto entries =
990+
LedgerTestUtils::generateValidUniqueLedgerEntriesWithTypes(
991+
{CONTRACT_DATA, CONTRACT_CODE}, entryCount, generatedKeys);
992+
for (int i = 0; i < entryCount; ++i)
993+
{
994+
entries.push_back(
995+
getTTLEntryForTTLKey(getTTLKey(entries[i]), 100'000));
996+
}
997+
998+
lm.setNextLedgerEntryBatchForBucketTesting(entries, {}, {});
970999
closeLedger(*app);
9711000
if ((ledger + 1) % networkConfig()
9721001
.stateArchivalSettings()

src/bucket/test/BucketTestUtils.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,10 @@ LedgerManagerForBucketTests::sealLedgerTxnAndTransferEntriesToBucketList(
275275
}
276276
mApp.getLedgerManager()
277277
.getMutableSorobanNetworkConfigForApply()
278-
.maybeSnapshotBucketListSize(lh.ledgerSeq, ltx, mApp);
278+
.maybeSnapshotSorobanStateSize(
279+
lh.ledgerSeq,
280+
mApp.getLedgerManager().getSorobanInMemoryStateSize(), ltx,
281+
mApp);
279282
}
280283

281284
ltx.getAllEntries(init, live, dead);

src/herder/Upgrades.cpp

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,16 +1182,16 @@ void
11821182
Upgrades::applyVersionUpgrade(Application& app, AbstractLedgerTxn& ltx,
11831183
uint32_t newVersion)
11841184
{
1185-
auto header = ltx.loadHeader();
1186-
uint32_t prevVersion = header.current().ledgerVersion;
1185+
uint32_t prevVersion = ltx.loadHeader().current().ledgerVersion;
11871186

1188-
header.current().ledgerVersion = newVersion;
1187+
ltx.loadHeader().current().ledgerVersion = newVersion;
11891188
if (needUpgradeToVersion(ProtocolVersion::V_10, prevVersion, newVersion))
11901189
{
1190+
auto header = ltx.loadHeader();
11911191
prepareLiabilities(ltx, header);
11921192
}
1193-
if (protocolVersionEquals(header.current().ledgerVersion,
1194-
ProtocolVersion::V_16) &&
1193+
1194+
if (protocolVersionEquals(newVersion, ProtocolVersion::V_16) &&
11951195
protocolVersionEquals(prevVersion, ProtocolVersion::V_15))
11961196
{
11971197
upgradeFromProtocol15To16(ltx);
@@ -1212,6 +1212,7 @@ Upgrades::applyVersionUpgrade(Application& app, AbstractLedgerTxn& ltx,
12121212
}
12131213
#endif
12141214
}
1215+
12151216
if (needUpgradeToVersion(ProtocolVersion::V_21, prevVersion, newVersion))
12161217
{
12171218
SorobanNetworkConfig::createCostTypesForV21(ltx, app);
@@ -1224,6 +1225,15 @@ Upgrades::applyVersionUpgrade(Application& app, AbstractLedgerTxn& ltx,
12241225
{
12251226
SorobanNetworkConfig::createAndUpdateLedgerEntriesForV23(ltx, app);
12261227
}
1228+
1229+
// Starting from protocol 23 we need to fully override the Soroban in-memory
1230+
// state size on upgrade, as before protocol 23 bucket list size has bene
1231+
// used.
1232+
if (protocolVersionStartsFrom(newVersion, ProtocolVersion::V_23))
1233+
{
1234+
app.getLedgerManager().handleUpgradeAffectingSorobanInMemoryStateSize(
1235+
ltx);
1236+
}
12271237
}
12281238

12291239
void
@@ -1391,32 +1401,42 @@ void
13911401
ConfigUpgradeSetFrame::applyTo(AbstractLedgerTxn& ltx, Application& app) const
13921402
{
13931403
bool writeLiveSorobanStateSizeWindow = false;
1404+
bool hasMemorySettingsUpgrade = false;
13941405
for (auto const& updatedEntry : mConfigUpgradeSet.updatedEntry)
13951406
{
13961407
LedgerKey key(LedgerEntryType::CONFIG_SETTING);
13971408
auto const id = updatedEntry.configSettingID();
13981409
key.configSetting().configSettingID = id;
13991410
auto& currentEntry = ltx.load(key).current().data.configSetting();
1400-
if (currentEntry.configSettingID() ==
1401-
ConfigSettingID::CONFIG_SETTING_STATE_ARCHIVAL &&
1411+
if (id == ConfigSettingID::CONFIG_SETTING_STATE_ARCHIVAL &&
14021412
currentEntry.stateArchivalSettings()
14031413
.liveSorobanStateSizeWindowSampleSize !=
14041414
updatedEntry.stateArchivalSettings()
14051415
.liveSorobanStateSizeWindowSampleSize)
14061416
{
14071417
writeLiveSorobanStateSizeWindow = true;
14081418
}
1419+
if (id ==
1420+
ConfigSettingID::CONFIG_SETTING_CONTRACT_COST_PARAMS_MEMORY_BYTES)
1421+
{
1422+
hasMemorySettingsUpgrade = true;
1423+
}
14091424
currentEntry = updatedEntry;
14101425
}
1411-
1426+
// If there was an upgrade for the Soroban state size window, we need to
1427+
// truncate or increase the size snapshot window respectively.
14121428
if (writeLiveSorobanStateSizeWindow)
14131429
{
14141430
SorobanNetworkConfig networkConfig;
1415-
networkConfig.loadFromLedger(
1416-
ltx, app.getConfig().CURRENT_LEDGER_PROTOCOL_VERSION,
1417-
mLedgerVersion);
1418-
1419-
networkConfig.maybeUpdateBucketListWindowSize(ltx);
1431+
networkConfig.loadFromLedger(ltx);
1432+
networkConfig.maybeUpdateSorobanStateSizeWindowSize(ltx);
1433+
}
1434+
// If there was an upgrade for the memory cost settings, we need to
1435+
// recompute the current state size and override the old sizes.
1436+
if (hasMemorySettingsUpgrade)
1437+
{
1438+
app.getLedgerManager().handleUpgradeAffectingSorobanInMemoryStateSize(
1439+
ltx);
14201440
}
14211441
}
14221442

0 commit comments

Comments
 (0)