Skip to content

Commit

Permalink
store errors
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs committed Sep 21, 2023
1 parent 2def093 commit e23e1e9
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 50 deletions.
23 changes: 11 additions & 12 deletions packages/store/src/IStoreErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@ import { ResourceId } from "./ResourceId.sol";

interface IStoreErrors {
// Errors include a stringified version of the tableId for easier debugging if cleartext tableIds are used
error StoreCore_TableAlreadyExists(ResourceId tableId, string tableIdString);
error StoreCore_TableNotFound(ResourceId tableId, string tableIdString);
error StoreCore_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString);
error Store_TableAlreadyExists(ResourceId tableId, string tableIdString);
error Store_TableNotFound(ResourceId tableId, string tableIdString);
error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString);

error StoreCore_NotImplemented();
error StoreCore_NotDynamicField();
error StoreCore_InvalidStaticDataLength(uint256 expected, uint256 received);
error StoreCore_InvalidDynamicDataLength(uint256 expected, uint256 received);
error StoreCore_InvalidKeyNamesLength(uint256 expected, uint256 received);
error StoreCore_InvalidFieldNamesLength(uint256 expected, uint256 received);
error StoreCore_InvalidValueSchemaLength(uint256 expected, uint256 received);
error StoreCore_DataIndexOverflow(uint256 length, uint256 received);
error StoreCore_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength);
error Store_NotDynamicField();
error Store_InvalidStaticDataLength(uint256 expected, uint256 received);
error Store_InvalidDynamicDataLength(uint256 expected, uint256 received);
error Store_InvalidKeyNamesLength(uint256 expected, uint256 received);
error Store_InvalidFieldNamesLength(uint256 expected, uint256 received);
error Store_InvalidValueSchemaLength(uint256 expected, uint256 received);
error Store_DataIndexOverflow(uint256 length, uint256 received);
error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength);
}
36 changes: 18 additions & 18 deletions packages/store/src/StoreCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ library StoreCore {
function getFieldLayout(ResourceId tableId) internal view returns (FieldLayout fieldLayout) {
fieldLayout = FieldLayout.wrap(Tables._getFieldLayout(ResourceId.unwrap(tableId)));
if (fieldLayout.isEmpty()) {
revert IStoreErrors.StoreCore_TableNotFound(tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_TableNotFound(tableId, string(abi.encodePacked(tableId)));
}
}

Expand All @@ -99,7 +99,7 @@ library StoreCore {
keySchema = Schema.wrap(Tables._getKeySchema(ResourceId.unwrap(tableId)));
// key schemas can be empty for singleton tables, so we can't depend on key schema for table check
if (!ResourceIds._getExists(ResourceId.unwrap(tableId))) {
revert IStoreErrors.StoreCore_TableNotFound(tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_TableNotFound(tableId, string(abi.encodePacked(tableId)));
}
}

Expand All @@ -109,7 +109,7 @@ library StoreCore {
function getValueSchema(ResourceId tableId) internal view returns (Schema valueSchema) {
valueSchema = Schema.wrap(Tables._getValueSchema(ResourceId.unwrap(tableId)));
if (valueSchema.isEmpty()) {
revert IStoreErrors.StoreCore_TableNotFound(tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_TableNotFound(tableId, string(abi.encodePacked(tableId)));
}
}

Expand All @@ -126,7 +126,7 @@ library StoreCore {
) internal {
// Verify the table ID is of type RESOURCE_TABLE
if (tableId.getType() != RESOURCE_TABLE && tableId.getType() != RESOURCE_OFFCHAIN_TABLE) {
revert IStoreErrors.StoreCore_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId)));
}

// Verify the field layout is valid
Expand All @@ -138,22 +138,22 @@ library StoreCore {

// Verify the number of key names matches the number of key schema types
if (keyNames.length != keySchema.numFields()) {
revert IStoreErrors.StoreCore_InvalidKeyNamesLength(keySchema.numFields(), keyNames.length);
revert IStoreErrors.Store_InvalidKeyNamesLength(keySchema.numFields(), keyNames.length);
}

// Verify the number of value names
if (fieldNames.length != fieldLayout.numFields()) {
revert IStoreErrors.StoreCore_InvalidFieldNamesLength(fieldLayout.numFields(), fieldNames.length);
revert IStoreErrors.Store_InvalidFieldNamesLength(fieldLayout.numFields(), fieldNames.length);
}

// Verify the number of value schema types
if (valueSchema.numFields() != fieldLayout.numFields()) {
revert IStoreErrors.StoreCore_InvalidValueSchemaLength(fieldLayout.numFields(), valueSchema.numFields());
revert IStoreErrors.Store_InvalidValueSchemaLength(fieldLayout.numFields(), valueSchema.numFields());
}

// Verify there is no resource with this ID yet
if (ResourceIds._getExists(ResourceId.unwrap(tableId))) {
revert IStoreErrors.StoreCore_TableAlreadyExists(tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_TableAlreadyExists(tableId, string(abi.encodePacked(tableId)));
}

// Register the table metadata
Expand Down Expand Up @@ -182,7 +182,7 @@ library StoreCore {
function registerStoreHook(ResourceId tableId, IStoreHook hookAddress, uint8 enabledHooksBitmap) internal {
// Hooks are only supported for tables, not for offchain tables
if (tableId.getType() != RESOURCE_TABLE) {
revert IStoreErrors.StoreCore_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId)));
}

StoreHooks.push(ResourceId.unwrap(tableId), Hook.unwrap(HookLib.encode(address(hookAddress), enabledHooksBitmap)));
Expand Down Expand Up @@ -476,7 +476,7 @@ library StoreCore {
FieldLayout fieldLayout
) internal {
if (fieldIndex < fieldLayout.numStaticFields()) {
revert IStoreErrors.StoreCore_NotDynamicField();
revert IStoreErrors.Store_NotDynamicField();
}

StoreCoreInternal._pushToDynamicField(tableId, keyTuple, fieldLayout, fieldIndex, dataToPush);
Expand All @@ -493,7 +493,7 @@ library StoreCore {
FieldLayout fieldLayout
) internal {
if (fieldIndex < fieldLayout.numStaticFields()) {
revert IStoreErrors.StoreCore_NotDynamicField();
revert IStoreErrors.Store_NotDynamicField();
}

StoreCoreInternal._popFromDynamicField(tableId, keyTuple, fieldLayout, fieldIndex, byteLengthToPop);
Expand All @@ -511,13 +511,13 @@ library StoreCore {
FieldLayout fieldLayout
) internal {
if (fieldIndex < fieldLayout.numStaticFields()) {
revert IStoreErrors.StoreCore_NotDynamicField();
revert IStoreErrors.Store_NotDynamicField();
}

// index must be checked because it could be arbitrarily large
// (but dataToSet.length can be unchecked - it won't overflow into another slot due to gas costs and hashed slots)
if (startByteIndex > type(uint40).max) {
revert IStoreErrors.StoreCore_DataIndexOverflow(type(uint40).max, startByteIndex);
revert IStoreErrors.Store_DataIndexOverflow(type(uint40).max, startByteIndex);
}

StoreCoreInternal._setDynamicFieldItem(tableId, keyTuple, fieldLayout, fieldIndex, startByteIndex, dataToSet);
Expand Down Expand Up @@ -651,7 +651,7 @@ library StoreCore {
) internal view returns (bytes memory) {
uint8 numStaticFields = uint8(fieldLayout.numStaticFields());
if (fieldIndex < fieldLayout.numStaticFields()) {
revert IStoreErrors.StoreCore_NotDynamicField();
revert IStoreErrors.Store_NotDynamicField();
}

// Get the length and storage location of the dynamic field
Expand Down Expand Up @@ -687,7 +687,7 @@ library StoreCoreInternal {
// Splicing dynamic data is not supported for offchain tables, because it
// requires reading the previous encoded lengths from storage
if (tableId.getType() != RESOURCE_TABLE) {
revert IStoreErrors.StoreCore_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId)));
revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId)));
}

uint256 previousFieldLength = previousEncodedLengths.atIndex(dynamicFieldIndex);
Expand All @@ -696,7 +696,7 @@ library StoreCoreInternal {
// If the total length of the field is changed, the data has to be appended/removed at the end of the field.
// Otherwise offchain indexers would shift the data after inserted data, while onchain the data is truncated at the end.
if (previousFieldLength != updatedFieldLength && startWithinField + deleteCount != previousFieldLength) {
revert IStoreErrors.StoreCore_InvalidSplice(startWithinField, deleteCount, uint40(previousFieldLength));
revert IStoreErrors.Store_InvalidSplice(startWithinField, deleteCount, uint40(previousFieldLength));
}

// Compute start index for the splice
Expand Down Expand Up @@ -894,10 +894,10 @@ library StoreCoreInternal {
bytes memory dynamicData
) internal pure {
if (fieldLayout.staticDataLength() != staticData.length) {
revert IStoreErrors.StoreCore_InvalidStaticDataLength(fieldLayout.staticDataLength(), staticData.length);
revert IStoreErrors.Store_InvalidStaticDataLength(fieldLayout.staticDataLength(), staticData.length);
}
if (encodedLengths.total() != dynamicData.length) {
revert IStoreErrors.StoreCore_InvalidDynamicDataLength(encodedLengths.total(), dynamicData.length);
revert IStoreErrors.Store_InvalidDynamicDataLength(encodedLengths.total(), dynamicData.length);
}
}

Expand Down
26 changes: 9 additions & 17 deletions packages/store/test/StoreCore.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ contract StoreCoreTest is Test, StoreMock {
// Expect a revert when registering a table that already exists
vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_TableAlreadyExists.selector,
IStoreErrors.Store_TableAlreadyExists.selector,
ResourceId.unwrap(tableId),
string(bytes.concat(ResourceId.unwrap(tableId)))
)
Expand Down Expand Up @@ -142,7 +142,7 @@ contract StoreCoreTest is Test, StoreMock {

vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_InvalidResourceType.selector,
IStoreErrors.Store_InvalidResourceType.selector,
RESOURCE_TABLE,
invalidTableId,
string(abi.encodePacked(invalidTableId))
Expand Down Expand Up @@ -182,28 +182,20 @@ contract StoreCoreTest is Test, StoreMock {

vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_TableNotFound.selector,
IStoreErrors.Store_TableNotFound.selector,
tableId2,
string(abi.encodePacked(ResourceId.unwrap(tableId2)))
)
);
IStore(this).getFieldLayout(tableId2);

vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_TableNotFound.selector,
tableId2,
string(abi.encodePacked(tableId2))
)
abi.encodeWithSelector(IStoreErrors.Store_TableNotFound.selector, tableId2, string(abi.encodePacked(tableId2)))
);
IStore(this).getValueSchema(tableId2);

vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_TableNotFound.selector,
tableId2,
string(abi.encodePacked(tableId2))
)
abi.encodeWithSelector(IStoreErrors.Store_TableNotFound.selector, tableId2, string(abi.encodePacked(tableId2)))
);
IStore(this).getKeySchema(tableId2);
}
Expand All @@ -223,11 +215,11 @@ contract StoreCoreTest is Test, StoreMock {
string[] memory oneName = new string[](1);

// Register table with invalid key names
vm.expectRevert(abi.encodeWithSelector(IStoreErrors.StoreCore_InvalidKeyNamesLength.selector, 4, 1));
vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_InvalidKeyNamesLength.selector, 4, 1));
IStore(this).registerTable(tableId, fieldLayout, keySchema, valueSchema, oneName, oneName);

// Register table with invalid value names
vm.expectRevert(abi.encodeWithSelector(IStoreErrors.StoreCore_InvalidFieldNamesLength.selector, 1, 4));
vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_InvalidFieldNamesLength.selector, 1, 4));
IStore(this).registerTable(tableId, fieldLayout, keySchema, valueSchema, fourNames, fourNames);
}

Expand Down Expand Up @@ -333,7 +325,7 @@ contract StoreCoreTest is Test, StoreMock {
keyTuple[0] = "some key";

// This should fail because the data is not 6 bytes long
vm.expectRevert(abi.encodeWithSelector(IStoreErrors.StoreCore_InvalidStaticDataLength.selector, 6, 4));
vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_InvalidStaticDataLength.selector, 6, 4));
IStore(this).setRecord(tableId, keyTuple, staticData, PackedCounter.wrap(bytes32(0)), new bytes(0), fieldLayout);
}

Expand Down Expand Up @@ -1051,7 +1043,7 @@ contract StoreCoreTest is Test, StoreMock {

// startByteIndex must not overflow
vm.expectRevert(
abi.encodeWithSelector(IStoreErrors.StoreCore_DataIndexOverflow.selector, type(uint40).max, type(uint56).max)
abi.encodeWithSelector(IStoreErrors.Store_DataIndexOverflow.selector, type(uint40).max, type(uint56).max)
);
IStore(this).updateInField(data.tableId, data.keyTuple, 2, type(uint56).max, data.thirdDataForUpdate, fieldLayout);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/world/test/World.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ contract WorldTest is Test, GasReporter {
// Expect an error when registering an existing table
vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_TableAlreadyExists.selector,
IStoreErrors.Store_TableAlreadyExists.selector,
tableId,
string(bytes.concat(ResourceId.unwrap(tableId)))
)
Expand Down Expand Up @@ -639,7 +639,7 @@ contract WorldTest is Test, GasReporter {
// Expect an error when trying to register a table at the same ID
vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_InvalidResourceType.selector,
IStoreErrors.Store_InvalidResourceType.selector,
RESOURCE_TABLE,
systemId,
string(abi.encodePacked(systemId))
Expand All @@ -657,7 +657,7 @@ contract WorldTest is Test, GasReporter {
// Expect an error when trying to register a new table at an existing table ID
vm.expectRevert(
abi.encodeWithSelector(
IStoreErrors.StoreCore_TableAlreadyExists.selector,
IStoreErrors.Store_TableAlreadyExists.selector,
ResourceId.unwrap(tableId),
string(bytes.concat(ResourceId.unwrap(tableId)))
)
Expand Down

0 comments on commit e23e1e9

Please sign in to comment.