Skip to main content

manifestValidity

test_ManifestValidity_invalid_ValidationAlwaysAllow_UserOpValidationFunction

test/account/ManifestValidity.t.sol
function test_ManifestValidity_invalid_ValidationAlwaysAllow_UserOpValidationFunction() public {
BadValidationMagicValue_UserOp_Plugin plugin = new BadValidationMagicValue_UserOp_Plugin();

bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest()));

vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector));
account.installPlugin({
plugin: address(plugin),
manifestHash: manifestHash,
pluginInstallData: "",
dependencies: new FunctionReference[](0)
});
}


解释下代码

整体来看,这个测试函数的目的是确保当一个插件的清单无效时,插件管理系统能够识别这一点并阻止插件的安装。通过预设 expectRevert,测试框架将验证在执行 installPlugin 时是否发生了预期的 revert 操作。如果 installPlugin 函数的执行结果与预期相符,即正确地触发了 revert,那么测试将会通过。如果没有发生预期的 revert,或者发生了一个不同的错误,测试将会失败。

test_ManifestValidity_invalid_ValidationAlwaysAllow_PreRuntimeValidationHook

function test_ManifestValidity_invalid_ValidationAlwaysAllow_PreRuntimeValidationHook() public {
// 1.
BadValidationMagicValue_PreRuntimeValidationHook_Plugin plugin = new BadValidationMagicValue_PreRuntimeValidationHook_Plugin();

bytes32 manifestHash = keccak256(abi.encode(plugin.pluginManifest()));

// 为什么呢?
// 2.
vm.expectRevert(abi.encodeWithSelector(PluginManagerInternals.InvalidPluginManifest.selector));
// 3.
// installPlugin->_installPlugin->_resolveManifestFunction
account.installPlugin({
plugin: address(plugin),
manifestHash: manifestHash,
pluginInstallData: "",
dependencies: new FunctionReference[](0)
});
}

为什么插件验证不通过

contract BadValidationMagicValue_UserOp_Plugin is BaseTestPlugin {
function onInstall(bytes calldata) external override {}

function onUninstall(bytes calldata) external override {}

function foo() external pure returns (bytes32) {
return keccak256("bar");
}

function pluginManifest() external pure override returns (PluginManifest memory) {
PluginManifest memory manifest;

manifest.executionFunctions = new bytes4[](1);
manifest.executionFunctions[0] = this.foo.selector;

manifest.userOpValidationFunctions = new ManifestAssociatedFunction[](1);
manifest.userOpValidationFunctions[0] = ManifestAssociatedFunction({
executionSelector: this.foo.selector,
associatedFunction: ManifestFunction({
// Illegal assignment: validation always allow only usable on runtime validation functions
// 非法赋值:验证始终允许仅可用于运行时验证函数
functionType: ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW,
functionId: 0,
dependencyIndex: 0
})
});

return manifest;
}
}

RUNTIME_VALIDATION_ALWAYS_ALLOW

src/account/PluginManagerInternals.sol
    function _resolveManifestFunction(
ManifestFunction memory manifestFunction,
address plugin,
FunctionReference[] memory dependencies,
// Indicates which magic value, if any, is permissible for the function to resolve.
ManifestAssociatedFunctionType allowedMagicValue
) internal pure returns (FunctionReference) {
if (manifestFunction.functionType == ManifestAssociatedFunctionType.SELF) {
return FunctionReferenceLib.pack(plugin, manifestFunction.functionId);
} else if (manifestFunction.functionType == ManifestAssociatedFunctionType.DEPENDENCY) {
if (manifestFunction.dependencyIndex >= dependencies.length) {
revert InvalidPluginManifest();
}
return dependencies[manifestFunction.dependencyIndex];
} else if (manifestFunction.functionType == ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW)
{
if (allowedMagicValue == ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW) {
return FunctionReferenceLib._RUNTIME_VALIDATION_ALWAYS_ALLOW;
} else {
revert InvalidPluginManifest();
}
} else if (manifestFunction.functionType == ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY) {
if (allowedMagicValue == ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY) {
return FunctionReferenceLib._PRE_HOOK_ALWAYS_DENY;
} else {
revert InvalidPluginManifest();
}
}
return FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE; // Empty checks are done elsewhere
}



这段代码定义了一个名为 _resolveManifestFunction 的内部函数,它用来解析智能合约插件的清单函数。这个函数的目的是将清单中定义的函数解析为可执行的函数引用。这个解析过程根据函数在清单中的定义来确定应该如何处理这个函数。这里的 ManifestFunction 是一个结构体,它包含了函数的类型和其他相关信息。

函数的参数包括:

  • manifestFunction: 清单中定义的函数的信息。
  • plugin: 插件的地址。
  • dependencies: 插件依赖的函数引用数组。
  • allowedMagicValue: 允许的魔法值类型,用于指示某些特殊的函数解析规则。

函数的逻辑如下:

  • 如果 manifestFunction.functionTypeSELF,则函数引用是由插件地址和函数 ID 打包而成的。
  • 如果 manifestFunction.functionTypeDEPENDENCY,则会检查依赖索引是否有效(即是否在 dependencies 数组的长度范围内),如果有效,则返回对应的依赖函数引用。
  • 如果 manifestFunction.functionTypeRUNTIME_VALIDATION_ALWAYS_ALLOW,则会检查 allowedMagicValue 是否也是 RUNTIME_VALIDATION_ALWAYS_ALLOW。如果是,返回一个特殊的函数引用,表示总是允许的运行时验证;如果不是,则抛出 InvalidPluginManifest 异常。
  • 如果 manifestFunction.functionTypePRE_HOOK_ALWAYS_DENY,则会检查 allowedMagicValue 是否也是 PRE_HOOK_ALWAYS_DENY。如果是,返回一个特殊的函数引用,表示总是拒绝的预挂钩;如果不是,则抛出 InvalidPluginManifest 异常。
  • 如果 manifestFunction.functionType 不属于以上任何一种,那么返回一个空的函数引用。空的检查在别处完成。

这个函数的设计是为了确保每个清单函数都能正确地解析,并且符合预期的规则。特别是对于 RUNTIME_VALIDATION_ALWAYS_ALLOWPRE_HOOK_ALWAYS_DENY 这两种特殊的“魔法值”,它们需要特别的处理来确保安全性和正确性。如果不允许这些特殊值,但是清单中却使用了它们,那么会抛出异常来阻止插件的安装或执行,因为这表示插件的清单是无效的。