From bace10c3a04de8097bfd3b6b7bee9bfc5577e60c Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 8 Nov 2026 22:07:24 -0800 Subject: [PATCH] fix(auth-eth): report the current root epoch in wrong-kind rejections _checkAuthorization returned on a wrong-kind operation before filling in the current root epoch and chain hash, so the rejection reported (0, 0x0). The KMS then failed with "Root epoch not registered" instead of the rejection reason. Fill both in first, as the KMS README states and as auth-simple, auth-mock and dstack-auth already do. Found by a Halmos symbolic test. Signed-off-by: Kevin Wang --- dstack/kms/auth-eth/contracts/DstackKms.sol | 15 +++++++-------- dstack/kms/auth-eth/test/DstackKms.t.sol | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/dstack/kms/auth-eth/contracts/DstackKms.sol b/dstack/kms/auth-eth/contracts/DstackKms.sol index d4c5b37c2..55161d29a 100644 --- a/dstack/kms/auth-eth/contracts/DstackKms.sol +++ b/dstack/kms/auth-eth/contracts/DstackKms.sol @@ -489,20 +489,19 @@ contract DstackKms is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, E { result.gatewayAppId = gatewayAppId; result.currentAppEpoch = isKms ? 0 : currentAppEpoch(request.appInfo.appId); + if (_rootEpochs.length > 0) { + result.currentRootEpoch = _currentRootEpoch; + result.currentRootEpochHash = _rootEpochs[_currentRootEpoch].chainHash; + } if (!(isKms ? AuthorizationOperation.isKms(request.operation) : AuthorizationOperation.isApp(request.operation))) { result.rejectionReason = "Invalid authorization operation"; return result; } - if (_rootEpochs.length == 0) { - if (request.operation != AuthorizationOperation.KMS_BOOTSTRAP) { - result.rejectionReason = "Root epoch not registered"; - return result; - } - } else { - result.currentRootEpoch = _currentRootEpoch; - result.currentRootEpochHash = _rootEpochs[_currentRootEpoch].chainHash; + if (_rootEpochs.length == 0 && request.operation != AuthorizationOperation.KMS_BOOTSTRAP) { + result.rejectionReason = "Root epoch not registered"; + return result; } uint256 latestAllowedRoot = isKms ? _latestRootEpoch() : _currentRootEpoch; if (request.requestedRootEpoch.isSet && request.requestedRootEpoch.value > latestAllowedRoot) { diff --git a/dstack/kms/auth-eth/test/DstackKms.t.sol b/dstack/kms/auth-eth/test/DstackKms.t.sol index c5defef38..a12c3782d 100644 --- a/dstack/kms/auth-eth/test/DstackKms.t.sol +++ b/dstack/kms/auth-eth/test/DstackKms.t.sol @@ -659,13 +659,23 @@ contract DstackKmsTest is Test { kms.activateRootEpoch(1, chainHash(chainHash(bytes32(0), ca(0xa0), k256(0xb0)), ca(0xa1), k256(0xb1))); vm.stopPrank(); + bytes32 hash1 = chainHash(chainHash(bytes32(0), ca(0xa0), k256(0xb0)), ca(0xa1), k256(0xb1)); DstackKms.AuthorizationResult memory result = authorize(authorizationInfo(user), false); assertFalse(result.isAllowed); assertEq(result.rejectionReason, "App not registered"); assertEq(result.currentRootEpoch, 1); - assertEq( - result.currentRootEpochHash, chainHash(chainHash(bytes32(0), ca(0xa0), k256(0xb0)), ca(0xa1), k256(0xb1)) + assertEq(result.currentRootEpochHash, hash1); + + DstackKms.AuthorizationRequest memory request = DstackKms.AuthorizationRequest( + authorizationInfo(user), + keccak256("kms_serve"), + DstackKms.OptionalUint256(false, 0), + DstackKms.OptionalUint256(false, 0) ); + result = kms.authorizeApp(request); + assertEq(result.rejectionReason, "Invalid authorization operation"); + assertEq(result.currentRootEpoch, 1); + assertEq(result.currentRootEpochHash, hash1); } function test_IsKmsAllowed() public {