diff --git a/src/HTMLRegistry.sol b/src/HTMLRegistry.sol
index 7a67d4c..62b0e61 100644
--- a/src/HTMLRegistry.sol
+++ b/src/HTMLRegistry.sol
@@ -2,7 +2,8 @@
pragma solidity ^0.8.13;
import {SSTORE2} from "solady/utils/SSTORE2.sol";
-
+import {LibBytes} from "solady/utils/LibBytes.sol";
+import {LibZip} from "solady/utils/LibZip.sol";
interface IOwnable {
function owner() external view returns (address);
}
@@ -44,7 +45,11 @@ contract HTMLRegistry {
function _html(address author, address target, uint256 version) internal view returns (bytes memory) {
address ptr = sPtrs[author][target][version];
if (ptr == address(0)) return new bytes(0);
- return SSTORE2.read(ptr);
+ bytes memory data = SSTORE2.read(ptr);
+
+ if (bytes4(bytes32(data)) == bytes4(0xffffffff)) return LibZip.flzDecompress(LibBytes.slice(data, 4));
+
+ return data;
}
function setHtml(address target, bytes calldata htmlData) external onlyAuthorized(target) {
diff --git a/test/HTMLRegistry.t.sol b/test/HTMLRegistry.t.sol
index 40a9a93..231a395 100644
--- a/test/HTMLRegistry.t.sol
+++ b/test/HTMLRegistry.t.sol
@@ -2,7 +2,9 @@
pragma solidity ^0.8.13;
import {Test} from "forge-std/Test.sol";
+import {console2} from "forge-std/console2.sol";
import {HTMLRegistry} from "../src/HTMLRegistry.sol";
+import {LibZip} from "solady/utils/LibZip.sol";
contract HTMLRegistryTest is Test {
HTMLRegistry public registry;
@@ -101,6 +103,54 @@ contract HTMLRegistryTest is Test {
assertEq(registry.html(alice, alice, 2), new bytes(0));
}
+ function test_html_decompressesWhenPrefixed() public {
+ bytes memory compressed = bytes.concat(bytes4(0xffffffff), LibZip.flzCompress(_HTML));
+ vm.prank(alice);
+ registry.setHtml(alice, compressed);
+
+ assertEq(registry.html(alice, alice), _HTML);
+ }
+
+ function test_html_returnsRawWhenPrefixDoesNotMatch() public {
+ bytes memory payload = bytes.concat(bytes4(0xdeadbeef), bytes("raw bytes"));
+ vm.prank(alice);
+ registry.setHtml(alice, payload);
+
+ assertEq(registry.html(alice, alice), payload);
+ }
+
+ function test_html_returnsRawWhenDataTooShortForPrefix() public {
+ bytes memory payload = hex"010203";
+ vm.prank(alice);
+ registry.setHtml(alice, payload);
+
+ assertEq(registry.html(alice, alice), payload);
+ }
+
+ function test_storageMetrics_plainVsCompressed() public {
+ bytes memory compressedBody = LibZip.flzCompress(_HTML);
+ bytes memory compressedPayload = bytes.concat(bytes4(0xffffffff), compressedBody);
+
+ vm.startPrank(alice);
+ uint256 gasStartPlain = gasleft();
+ registry.setHtml(alice, _HTML);
+ uint256 gasUsedPlain = gasStartPlain - gasleft();
+
+ uint256 gasStartCompressed = gasleft();
+ registry.setHtml(alice, compressedPayload);
+ uint256 gasUsedCompressed = gasStartCompressed - gasleft();
+ vm.stopPrank();
+
+ assertEq(registry.html(alice, alice, 1), _HTML);
+ assertEq(registry.html(alice, alice, 2), _HTML);
+
+ console2.log("plain length", _HTML.length);
+ console2.log("compressed length", compressedBody.length);
+ console2.log("compressed+selector length", compressedPayload.length);
+ console2.log("plain write gas", gasUsedPlain);
+ console2.log("compressed write gas", gasUsedCompressed);
+ }
+
function test_emitsHtmlSet() public {
vm.startPrank(alice);
vm.expectEmit(true, true, false, true);