diff --git a/packages/protocol/src/state/AppendOnlyStateSet.ts b/packages/protocol/src/state/AppendOnlyStateSet.ts new file mode 100644 index 000000000..ba4320641 --- /dev/null +++ b/packages/protocol/src/state/AppendOnlyStateSet.ts @@ -0,0 +1,64 @@ +import type { Bool, Field, FlexibleProvablePure } from "o1js"; +import { Mixin } from "ts-mixer"; + +import { Path } from "../model/Path"; + +import { State, WithStateServiceProvider, WithPath } from "./State"; + +/** + * Map-like wrapper for state + */ +export class AppendOnlyStateSet extends Mixin( + WithPath, + WithStateServiceProvider +) { + /** + * Create a new state map with the given key and value types + * + * @param keyType - Type to be used as a key + * @param valueType - Type to be stored as a value + * @returns State map with provided key and value types. + */ + public static from( + valueType: FlexibleProvablePure + ): AppendOnlyStateSet { + return new AppendOnlyStateSet(valueType); + } + + public constructor(public valueType: FlexibleProvablePure) { + super(); + } + + public getPath(value: ValueType): Field { + this.hasPathOrFail(); + return Path.fromKey(this.path, this.valueType, value); + } + + // TODO has? includes? + public async contains(value: ValueType): Promise { + // TODO This does a unnecessary hashing step to determine the leaf value. + // We would be fine with just storing a Bool here, but that means writing a + // custom variant of `State` + const state = State.from(this.valueType); + this.hasPathOrFail(); + this.hasStateServiceOrFail(); + + state.path = this.getPath(value); + state.stateServiceProvider = this.stateServiceProvider; + const stateValue = await state.get(); + return stateValue.isSome; + } + + private async add(value: ValueType): Promise { + const state = State.from(this.valueType); + this.hasPathOrFail(); + this.hasStateServiceOrFail(); + + state.path = this.getPath(value); + state.stateServiceProvider = this.stateServiceProvider; + + return await state.set(value); + } + + // TODO Adding a remove would require State.delete() +} diff --git a/packages/protocol/src/state/StateMap.ts b/packages/protocol/src/state/StateMap.ts index 53fe51be4..7b2761178 100644 --- a/packages/protocol/src/state/StateMap.ts +++ b/packages/protocol/src/state/StateMap.ts @@ -66,7 +66,7 @@ export class StateMap extends Mixin( this.hasPathOrFail(); this.hasStateServiceOrFail(); - state.path = Path.fromKey(this.path, this.keyType, key); + state.path = this.getPath(key); state.stateServiceProvider = this.stateServiceProvider; return await state.set(value); }