@@ -1220,6 +1220,30 @@ HerderImpl::setupTriggerNextLedger()
12201220 uint64_t nextIndex = nextConsensusLedgerIndex ();
12211221 auto lastIndex = trackingConsensusLedgerIndex ();
12221222
1223+ // Note, this is not the LCL externalized close time, but the close time of
1224+ // the ledger prior. This should be roughly ledgerCloseTime seconds ago.
1225+ std::optional<uint64_t > externalizedCloseTime = std::nullopt ;
1226+ #ifdef BUILD_TESTS
1227+ if (mApp .getConfig ().EXPERIMENTAL_TRIGGER_TIMER && lastIndex > 0 &&
1228+ mApp .getClock ().getMode () != VirtualClock::VIRTUAL_TIME)
1229+ {
1230+ auto messages = getSCP ().getLatestMessagesSend (lastIndex - 1 );
1231+ for (auto const & env : messages)
1232+ {
1233+ if (env.statement .pledges .type () == SCP_ST_EXTERNALIZE)
1234+ {
1235+ // Extract the close time from the externalized value
1236+ auto const & ext = env.statement .pledges .externalize ();
1237+ auto const & value = ext.commit .value ;
1238+ StellarValue sv;
1239+ xdr::xdr_from_opaque (value, sv);
1240+ externalizedCloseTime = sv.closeTime ;
1241+ break ;
1242+ }
1243+ }
1244+ }
1245+ #endif
1246+
12231247 // if we're in sync, we setup mTriggerTimer
12241248 // it may get cancelled if a more recent ledger externalizes
12251249
@@ -1229,16 +1253,39 @@ HerderImpl::setupTriggerNextLedger()
12291253 // bootstrap with a pessimistic estimate of when
12301254 // the ballot protocol started last
12311255 auto now = mApp .getClock ().now ();
1232- auto lastBallotStart = now - milliseconds;
1233- auto lastStart = mHerderSCPDriver .getPrepareStart (lastIndex);
1234- if (lastStart)
1256+ auto lastLedgerStatingPoint = now - milliseconds;
1257+
1258+ #ifdef BUILD_TESTS
1259+ if (externalizedCloseTime)
1260+ {
1261+ // The externalized close time is a unix timestamp (seconds since
1262+ // epoch). We convert it to steady_clock time by:
1263+ // 1. Converting unix timestamp to system_clock::time_point (wall clock
1264+ // time)
1265+ // 2. Calculating how long ago that was from current system time
1266+ // 3. Subtracting that duration from current steady_clock time
1267+ // (monotonic clock) This avoids clock type mismatches since
1268+ // lastLedgerStatingPoint uses steady_clock
1269+ auto externalizedSystemTime =
1270+ VirtualClock::from_time_t (*externalizedCloseTime);
1271+ auto currentSystemTime = mApp .getClock ().system_now ();
1272+ auto timeSinceExternalized = currentSystemTime - externalizedSystemTime;
1273+ lastLedgerStatingPoint = now - timeSinceExternalized;
1274+ }
1275+ else
1276+ #endif
12351277 {
1236- lastBallotStart = *lastStart;
1278+ // Fall back to prepare start time if available
1279+ auto lastStart = mHerderSCPDriver .getPrepareStart (lastIndex);
1280+ if (lastStart)
1281+ {
1282+ lastLedgerStatingPoint = *lastStart;
1283+ }
12371284 }
12381285
12391286 // Adjust trigger time in case node's clock has drifted.
12401287 // This ensures that next value to nominate is valid
1241- auto triggerTime = lastBallotStart + milliseconds;
1288+ auto triggerTime = lastLedgerStatingPoint + milliseconds;
12421289
12431290 if (triggerTime < now)
12441291 {
0 commit comments