Skip to content

Commit

Permalink
Add applyLoad
Browse files Browse the repository at this point in the history
  • Loading branch information
sisuresh committed Jul 30, 2024
1 parent 4fda7ef commit 5b3fcd4
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 95 deletions.
2 changes: 1 addition & 1 deletion docs/stellar-core_example.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ MANUAL_CLOSE=false

# ARTIFICIALLY_GENERATE_LOAD_FOR_TESTING (true or false) defaults to false
# Enables synthetic load generation on demand.
# The load is triggered by the `generateload` runtime command.
# The load is triggered by the `generateload` runtime command or the `apply-load` command line command.
# This option only exists for stress-testing and should not be enabled in
# production networks.
ARTIFICIALLY_GENERATE_LOAD_FOR_TESTING=false
Expand Down
42 changes: 42 additions & 0 deletions src/main/CommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
#include "main/SettingsUpgradeUtils.h"
#include "main/StellarCoreVersion.h"
#include "main/dumpxdr.h"
#include "medida/metrics_registry.h"
#include "overlay/OverlayManager.h"
#include "rust/RustBridge.h"
#include "scp/QuorumSetUtils.h"
#include "simulation/ApplyLoad.h"
#include "transactions/TransactionUtils.h"
#include "util/Logging.h"
#include "util/types.h"
Expand Down Expand Up @@ -1820,6 +1822,45 @@ runGenFuzz(CommandLineArgs const& args)
return 0;
});
}

int
runApplyLoad(CommandLineArgs const& args)
{
CommandLine::ConfigOption configOption;

return runWithHelp(args, {configurationParser(configOption)}, [&] {
auto config = configOption.getConfig();
config.RUN_STANDALONE = true;

VirtualClock clock(VirtualClock::REAL_TIME);
int result;
auto appPtr = Application::create(clock, config);

auto& app = *appPtr;
{
auto& lm = app.getLedgerManager();
app.start();
ApplyLoad al(app);

auto& ledgerClose =
app.getMetrics().NewTimer({"ledger", "ledger", "close"});
ledgerClose.Clear();

// TODO: Make this configurable
for (size_t i = 0; i < 20; ++i)
{
al.benchmark();
}

CLOG_INFO(Perf, "Max ledger close: {} milliseconds",
ledgerClose.max());
CLOG_INFO(Perf, "Mean ledger close: {} milliseconds",
ledgerClose.mean());
}

return result;
});
}
#endif

int
Expand Down Expand Up @@ -1892,6 +1933,7 @@ handleCommandLine(int argc, char* const* argv)
{"fuzz", "run a single fuzz input and exit", runFuzz},
{"gen-fuzz", "generate a random fuzzer input file", runGenFuzz},
{"test", "execute test suite", runTest},
{"apply-load", "run apply time load test", runApplyLoad},
#endif
{"version", "print version information", runVersion}}};

Expand Down
240 changes: 240 additions & 0 deletions src/simulation/ApplyLoad.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
#include "simulation/ApplyLoad.h"
#include "herder/Herder.h"
#include "ledger/LedgerManager.h"
#include "test/TxTests.h"
#include "transactions/TransactionBridge.h"
#include "transactions/TransactionUtils.h"

#include "medida/meter.h"
#include "medida/metrics_registry.h"

#include "util/XDRCereal.h"
#include <crypto/SHA.h>

namespace stellar
{

uint64_t NUM_ACCOUNTS = 400;

ApplyLoad::ApplyLoad(Application& app) : TxGenerator(app)
{
// TODO: add command line options to set these values?
mUpgradeConfig.maxContractSizeBytes = 65536;
mUpgradeConfig.maxContractDataKeySizeBytes = 250;
mUpgradeConfig.maxContractDataEntrySizeBytes = 65536;
mUpgradeConfig.ledgerMaxInstructions = 500000000;
mUpgradeConfig.txMaxInstructions = 100000000;
mUpgradeConfig.txMemoryLimit = 41943040;
mUpgradeConfig.ledgerMaxReadLedgerEntries = 200;
mUpgradeConfig.ledgerMaxReadBytes = 500000;
mUpgradeConfig.ledgerMaxWriteLedgerEntries = 125;
mUpgradeConfig.ledgerMaxWriteBytes = 70000;
mUpgradeConfig.ledgerMaxTxCount = 100;
mUpgradeConfig.txMaxReadLedgerEntries = 40;
mUpgradeConfig.txMaxReadBytes = 200000;
mUpgradeConfig.txMaxWriteLedgerEntries = 25;
mUpgradeConfig.txMaxWriteBytes = 66560;
mUpgradeConfig.txMaxContractEventsSizeBytes = 8198;
mUpgradeConfig.ledgerMaxTransactionsSizeBytes = 71680;
mUpgradeConfig.txMaxSizeBytes = 71680;
mUpgradeConfig.bucketListSizeWindowSampleSize = 30;
mUpgradeConfig.evictionScanSize = 100000;
mUpgradeConfig.startingEvictionScanLevel = 7;

createRootAccount();
updateMinBalance();

releaseAssert(mRoot);

setupAccountsAndUpgradeProtocol();

setupUpgradeContract();

upgradeSettings();

setupLoadContracts();

// One contract per account
releaseAssert(mApplySorobanSuccess.count() == NUM_ACCOUNTS + 4);
releaseAssert(mApplySorobanFailure.count() == 0);
}

void
ApplyLoad::closeLedger(std::vector<TransactionFrameBasePtr> const& txs,
xdr::xvector<UpgradeType, 6> const& upgrades)
{
auto txSet = makeTxSetFromTransactions(txs, mApp, 0, UINT64_MAX);

auto sv =
mApp.getHerder().makeStellarValue(txSet.first->getContentsHash(), 1,
upgrades, mApp.getConfig().NODE_SEED);

auto& lm = mApp.getLedgerManager();
LedgerCloseData lcd(lm.getLastClosedLedgerNum() + 1, txSet.first, sv);
lm.closeLedger(lcd);
}

void
ApplyLoad::setupAccountsAndUpgradeProtocol()
{
auto const& lm = mApp.getLedgerManager();
std::vector<Operation> creationOps =
createAccounts(0, NUM_ACCOUNTS, lm.getLastClosedLedgerNum() + 1, true);

auto initTx =
createTransactionFramePtr(mRoot, creationOps, false, std::nullopt);

// Upgrade to latest protocol as well
auto upgrade = xdr::xvector<UpgradeType, 6>{};
auto ledgerUpgrade = LedgerUpgrade{LEDGER_UPGRADE_VERSION};
ledgerUpgrade.newLedgerVersion() = Config::CURRENT_LEDGER_PROTOCOL_VERSION;
auto v = xdr::xdr_to_opaque(ledgerUpgrade);
upgrade.push_back(UpgradeType{v.begin(), v.end()});

closeLedger({initTx}, upgrade);
}

void
ApplyLoad::setupUpgradeContract()
{
auto wasm = rust_bridge::get_write_bytes();
xdr::opaque_vec<> wasmBytes;
wasmBytes.assign(wasm.data.begin(), wasm.data.end());

LedgerKey contractCodeLedgerKey;
contractCodeLedgerKey.type(CONTRACT_CODE);
contractCodeLedgerKey.contractCode().hash = sha256(wasmBytes);

mUpgradeCodeKey = contractCodeLedgerKey;

auto const& lm = mApp.getLedgerManager();
auto uploadTx = createUploadWasmTransaction(
lm.getLastClosedLedgerNum() + 1, 0, wasmBytes, contractCodeLedgerKey,
std::nullopt);

closeLedger({uploadTx.second});

auto salt = sha256("upgrade contract salt preimage");

auto createTx = createContractTransaction(
lm.getLastClosedLedgerNum() + 1, 0, contractCodeLedgerKey,
wasmBytes.size() + 160, salt, std::nullopt);
closeLedger({createTx.second});

mUpgradeInstanceKey =
createTx.second->sorobanResources().footprint.readWrite.back();
}

// To upgrade settings, just modify mUpgradeConfig and then call
// upgradeSettings()
void
ApplyLoad::upgradeSettings()
{
auto const& lm = mApp.getLedgerManager();
auto upgradeBytes = getConfigUpgradeSetFromLoadConfig(mUpgradeConfig);

auto invokeTx = invokeSorobanCreateUpgradeTransaction(
lm.getLastClosedLedgerNum() + 1, 0, upgradeBytes, mUpgradeCodeKey,
mUpgradeInstanceKey, std::nullopt);

auto upgradeSetKey = getConfigUpgradeSetKey(
mUpgradeConfig,
mUpgradeInstanceKey.contractData().contract.contractId());

auto upgrade = xdr::xvector<UpgradeType, 6>{};
auto ledgerUpgrade = LedgerUpgrade{LEDGER_UPGRADE_CONFIG};
ledgerUpgrade.newConfig() = upgradeSetKey;
auto v = xdr::xdr_to_opaque(ledgerUpgrade);
upgrade.push_back(UpgradeType{v.begin(), v.end()});

closeLedger({invokeTx.second}, upgrade);
}

void
ApplyLoad::setupLoadContracts()
{
auto wasm = rust_bridge::get_test_wasm_loadgen();
xdr::opaque_vec<> wasmBytes;
wasmBytes.assign(wasm.data.begin(), wasm.data.end());

LedgerKey contractCodeLedgerKey;
contractCodeLedgerKey.type(CONTRACT_CODE);
contractCodeLedgerKey.contractCode().hash = sha256(wasmBytes);

mLoadCodeKey = contractCodeLedgerKey;

auto const& lm = mApp.getLedgerManager();
auto uploadTx = createUploadWasmTransaction(
lm.getLastClosedLedgerNum() + 1, 0, wasmBytes, contractCodeLedgerKey,
std::nullopt);

closeLedger({uploadTx.second});

for (auto kvp : mAccounts)
{
auto salt = sha256("Load contract " + std::to_string(kvp.first));

auto createTx = createContractTransaction(
lm.getLastClosedLedgerNum() + 1, 0, contractCodeLedgerKey,
wasmBytes.size() + 160, salt, std::nullopt);
closeLedger({createTx.second});

auto instanceKey =
createTx.second->sorobanResources().footprint.readWrite.back();

ContractInstance instance;
instance.readOnlyKeys.emplace_back(mLoadCodeKey);
instance.readOnlyKeys.emplace_back(instanceKey);
instance.contractID = instanceKey.contractData().contract;
mLoadInstances.emplace(kvp.first, instance);
}
}

void
ApplyLoad::benchmark()
{
auto& lm = mApp.getLedgerManager();
std::vector<TransactionFrameBasePtr> txs;

auto resources =
multiplyByDouble(lm.maxLedgerResources(true),
2 /*TODO: use TRANSACTION_QUEUE_SIZE_MULTIPLIER*/);

std::vector<uint64_t> shuffledAccounts(mAccounts.size());
std::iota(shuffledAccounts.begin(), shuffledAccounts.end(), 0);
stellar::shuffle(std::begin(shuffledAccounts), std::end(shuffledAccounts),
gRandomEngine);

for (auto accountIndex : shuffledAccounts)
{
auto it = mAccounts.find(accountIndex);
releaseAssert(it != mAccounts.end());

auto instanceIter = mLoadInstances.find(it->first);
releaseAssert(instanceIter != mLoadInstances.end());
auto const& instance = instanceIter->second;
auto tx = invokeSorobanLoadTransaction(
lm.getLastClosedLedgerNum() + 1, it->first, instance,
rust_bridge::get_write_bytes().data.size() + 160, std::nullopt);

if (!anyGreater(tx.second->getResources(false), resources))
{
resources -= tx.second->getResources(false);
}
else
{
break;
}

txs.emplace_back(tx.second);
}

closeLedger(txs);

CLOG_INFO(Perf, "mApplySorobanSuccess count {}",
mApplySorobanSuccess.count());
CLOG_INFO(Perf, "mApplySorobanFailure count {}",
mApplySorobanFailure.count());
}

}
33 changes: 33 additions & 0 deletions src/simulation/ApplyLoad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "main/Application.h"
#include "simulation/TxGenerator.h"
#include "test/TestAccount.h"

namespace stellar
{
class ApplyLoad : public TxGenerator
{
public:
ApplyLoad(Application& app);
void benchmark();

private:
void closeLedger(std::vector<TransactionFrameBasePtr> const& txs,
xdr::xvector<UpgradeType, 6> const& upgrades = {});

void setupAccountsAndUpgradeProtocol();
void setupUpgradeContract();
void setupLoadContracts();

// Upgrades using mUpgradeConfig
void upgradeSettings();

LedgerKey mUpgradeCodeKey;
LedgerKey mUpgradeInstanceKey;

LedgerKey mLoadCodeKey;
UnorderedMap<uint64_t, ContractInstance> mLoadInstances;

SorobanUpgradeConfig mUpgradeConfig;
};

}
2 changes: 0 additions & 2 deletions src/simulation/LoadGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,8 +800,6 @@ LoadGenerator::generateLoad(GeneratedLoadConfig cfg)
txPair.second->sorobanResources()
.footprint.readWrite.back();

CLOG_ERROR(LoadGen, "lklklk {}",
xdrToCerealString(instanceLk, "instanceLk"));
mContractInstanceKeys.emplace(instanceLk);

return txPair;
Expand Down
Loading

0 comments on commit 5b3fcd4

Please sign in to comment.