Core
org.blockchainbench.core is the engine. It accepts batches of configurations through a small public interface, runs them against the Palladio simulator on a background worker, and turns each raw simulator output into a typed, persisted result. Everything Palladio-specific — standalone initialisation, EMF model loading, factory selection, serialisation — is contained here so that the rest of the project never has to see it.
Public interface
Section titled “Public interface”The only type front ends depend on is IBlockchainBench:
int submit(List<SimulationConfig> configs, BaseConfig baseConfig, SimulationMode mode);int submit(List<SimulationConfig> configs, BaseConfig baseConfig, String modelPath, SimulationMode mode);SimulationInfo getSimulation(int simulationId);List<SimulationInfo> listSimulations();void setBaseConfig(BaseConfig baseConfig);void shutdown();submit enqueues a group of runs and returns its simulationId without blocking. Callers observe progress and results through getSimulation, and release the worker thread with shutdown when they are done.
Orchestration: SimulationHandler
Section titled “Orchestration: SimulationHandler”SimulationHandler is the sole implementation of IBlockchainBench. It holds:
- a single-threaded
simulation-workerexecutor (sequential FIFO, EMF-safe), - a registry of submitted groups (
Map<Integer, SimulationInfo>), - a cache of initialised simulators, one per
SimulationMode, - an atomic id sequence, and an optional fallback
BaseConfig.
When a group is submitted, the handler builds one RunInfo per configuration, records a SimulationInfo in state QUEUED, and schedules process(...) on the worker. process sets the group to RUNNING, ensures the simulator for that mode is initialised (once, cached), then iterates the runs. For each run it resolves the model path, calls the simulator, appends the returned SimulationRun to the group’s result list, and marks the run FINISHED or ERROR. A failure in one run is caught and recorded on that run without aborting the rest; a fatal failure (caught as Throwable, so linkage and initialisation errors are included) marks the whole group ERROR.
Model path resolution
Section titled “Model path resolution”Each run needs a path to a blockchain-system model. The handler resolves it in a fixed order and stops at the first value that is present:
- the path already set on the
SimulationConfig, - otherwise the group default from the
BaseConfig, - otherwise the
modelPathpassed tosubmit, - otherwise a deterministic lookup by
config_idviaConfigManager.pickModelPath, which maps todata/testmodels/threesim-<config_id>/Net.blockchainsystem.
Simulator hierarchy
Section titled “Simulator hierarchy”The per-run work sits behind IBlockchainBenchSimulator, whose template implementation is AbstractStandaloneSimulator. The abstract class owns the shared skeleton — standalone initialisation, parameter construction, timing and memory measurement, and result persistence — and leaves three decisions to subclasses.
classDiagram
class IBlockchainBench {
<<interface>>
+submit(...) int
+getSimulation(id) SimulationInfo
+listSimulations() List
+setBaseConfig(BaseConfig)
+shutdown()
}
class SimulationHandler {
-ExecutorService executor
-Map simulations
-Map simulators
-process(info, base, modelPath)
-resolveModelPath(...) String
-ensureInitialized(mode) IBlockchainBenchSimulator
}
class IBlockchainBenchSimulator {
<<interface>>
+initAnalysis() boolean
+runSimulation(config, base, simId, runId) SimulationRun
}
class AbstractStandaloneSimulator {
<<abstract>>
+initAnalysis() boolean
+runSimulation(...) SimulationRun
#runSimulationFactory(...) String
#attackerId() int
#createOutputPath(simId, runId) Path
#registerHk2OsgiResourceLocator() boolean
}
class BlockchainTrilemmaStandalone {
#attackerId() int
}
class BlockchainTrilemmaAttackStandalone {
#attackerId() int
}
IBlockchainBench <|.. SimulationHandler
IBlockchainBenchSimulator <|.. AbstractStandaloneSimulator
AbstractStandaloneSimulator <|-- BlockchainTrilemmaStandalone
AbstractStandaloneSimulator <|-- BlockchainTrilemmaAttackStandalone
SimulationHandler --> IBlockchainBenchSimulator : caches per mode
The two concrete simulators differ only in a few points:
| Aspect | BlockchainTrilemmaStandalone (NORMAL) | BlockchainTrilemmaAttackStandalone (ATTACK) |
|---|---|---|
| Factory used | TrilemmaSimulationFactory | SelfishMiningSimulationFactory |
| Attacker id | 0 | 1 |
| Output folder | indiv_json/ | result_selfishmining/ |
| HK2 resource locator | registered | not registered |
| Stack trace on init failure | printed | suppressed |
AbstractStandaloneSimulator.initAnalysis processes the EMF extension registry and then initialises the standalone environment through StandaloneInitializerBuilder. runSimulation builds the Palladio SimulationParameters (Monte-Carlo or single, chosen from BaseConfig.simulationType), delegates to the subclass factory, measures time and memory with RunMetrics, and hands everything to SimulationResultWriter.
Factories and the platform bridge
Section titled “Factories and the platform bridge”The factories translate a resolved configuration into a concrete Palladio simulation and run it.
TrilemmaSimulationFactorybuilds either aThreesimMonteCarloSimulationor aThreesimSingleSimulation, wires in aLogOutputProviderImpl, runs it, and serialises the result with the Threesim JSON serialiser.SelfishMiningSimulationFactorybuilds aMonteCarloDoubleSpendingAttackSimulationor aSingleDoubleSpendingAttackSimulation, using aLogOutputAttackProviderImpland aSimulationRoundInterpretationImplto classify each round’s outcome, and serialises with Gson.BlockchainSystemFactoryResolveris shared by both. Given aSimulationConfigand anattackerPresentflag, it loads the model, inspects its network topology, and returns the matching Threesim factory (ConnectedSubgraphNetworkBlockchainSystemFactoryorExplicitNetworkBlockchainSystemFactory). An unsupported topology fails fast.
flowchart TB
subgraph NORMAL
N1["BlockchainTrilemmaStandalone"] --> N2["TrilemmaSimulationFactory"]
N2 --> N3["Threesim Single / MonteCarlo simulation"]
end
subgraph ATTACK
A1["BlockchainTrilemmaAttackStandalone"] --> A2["SelfishMiningSimulationFactory"]
A2 --> A3["DoubleSpending Single / MonteCarlo simulation"]
end
N2 --> R["BlockchainSystemFactoryResolver"]
A2 --> R
R --> ML["BlockchainSystemModelLoader"]
R --> TF["Threesim BlockchainSystem factory"]
Model loading
Section titled “Model loading”BlockchainSystemModelLoader reads a BlockchainSystem EMF model and all of its co-located resources — network topology, node allocation, component repository, transactions, and so on — from the model’s folder under data/testmodels/. It registers the XMI resource factory and the relevant EMF packages, loads each of the seven resource extensions, and repeatedly calls EcoreUtil.resolveAll until the resource set stops growing, so that all cross-references are resolved before the model is handed to a factory.
Metrics and result assembly
Section titled “Metrics and result assembly”RunMetrics brackets a run: at start() it triggers a garbage collection and records heap usage and a nanosecond timestamp; stopAndGetUsedMemoryMb() returns the delta in megabytes and captures the stop timestamp.
SimulationResultWriter produces the per-run artifact in three steps: parse the raw simulator JSON into a typed SimulationResult; assemble a SimulationRun that bundles the run metadata, the full input configuration, the base configuration, the typed result, and the timing and memory numbers; then serialise that back to pretty-printed JSON and write it to the run’s output path. The assembled SimulationRun is returned to the handler even if the disk write fails, so the in-memory result is never lost.
One run, end to end
Section titled “One run, end to end”sequenceDiagram
autonumber
participant UI as Front end
participant H as SimulationHandler
participant W as simulation-worker
participant S as AbstractStandaloneSimulator
participant F as Factory
participant P as 3SIM / BSCM
participant D as Disk
UI->>H: submit(configs, baseConfig, mode)
H->>H: build runs, record SimulationInfo (QUEUED)
H->>W: enqueue process(info)
H-->>UI: simulationId
W->>S: ensureInitialized(mode) then initAnalysis()
Note over S,P: standalone init runs once per mode
loop each run
W->>S: runSimulation(config, base, simId, runId)
S->>F: runSimulationFactory(params, config, base)
F->>P: run()
P-->>F: SimulationResult
F-->>S: raw JSON
S->>D: write result_run_simId_runId.json
S-->>W: SimulationRun
W->>W: append to info.results, run FINISHED
end
W->>H: info.status = FINISHED or ERROR
UI->>H: getSimulation(id) (polled)
Related pages
Section titled “Related pages”- The data types exchanged with front ends and written to disk are documented in Utils.
- The cross-layer flow and the status state machine are in Simulation lifecycle.