Skip to content

Commit

Permalink
Merge pull request #75 from firstbatchxyz/erhant/set-state
Browse files Browse the repository at this point in the history
Add setState to SetSDK & contract
  • Loading branch information
erhant authored Feb 26, 2024
2 parents ae6936d + 7f0c9cd commit 1a7e6c6
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hollowdb",
"version": "1.4.1",
"version": "1.4.2",
"description": "A decentralized privacy-preserving key-value database",
"license": "MIT",
"homepage": "https://github.com/firstbatchxyz/hollowdb#readme",
Expand Down
14 changes: 8 additions & 6 deletions src/contracts/build/hollowdb-htx.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
var InvalidFunctionError = new ContractError("Invalid function.");
var ArrayLengthMismatchError = new ContractError("Key and value counts mismatch.");

// src/contracts/modifiers/apply.ts
async function apply(caller, input, state, ...modifiers) {
for (const modifier of modifiers) {
input = await modifier(caller, input, state);
}
return input;
}

// src/contracts/utils/index.ts
var verifyProof = async (proof, psignals, verificationKey) => {
if (!verificationKey) {
Expand Down Expand Up @@ -54,12 +62,6 @@
return input;
};
};
async function apply(caller, input, state, ...modifiers) {
for (const modifier of modifiers) {
input = await modifier(caller, input, state);
}
return input;
}

// src/contracts/hollowdb-htx.contract.ts
var handle = async (state, action) => {
Expand Down
19 changes: 13 additions & 6 deletions src/contracts/build/hollowdb-set.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
var InvalidFunctionError = new ContractError("Invalid function.");
var ArrayLengthMismatchError = new ContractError("Key and value counts mismatch.");

// src/contracts/modifiers/apply.ts
async function apply(caller, input, state, ...modifiers) {
for (const modifier of modifiers) {
input = await modifier(caller, input, state);
}
return input;
}

// src/contracts/utils/index.ts
var verifyProof = async (proof, psignals, verificationKey) => {
if (!verificationKey) {
Expand Down Expand Up @@ -80,12 +88,6 @@
return input;
};
};
async function apply(caller, input, state, ...modifiers) {
for (const modifier of modifiers) {
input = await modifier(caller, input, state);
}
return input;
}

// src/contracts/hollowdb-set.contract.ts
var handle = async (state, action) => {
Expand Down Expand Up @@ -207,6 +209,11 @@
state.evolve = srcTxId;
return { state };
}
case "seState": {
const newState = await apply(caller, input.value, state, onlyOwner);
state = newState;
return { state };
}
default:
input;
throw InvalidFunctionError;
Expand Down
14 changes: 8 additions & 6 deletions src/contracts/build/hollowdb.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
var InvalidFunctionError = new ContractError("Invalid function.");
var ArrayLengthMismatchError = new ContractError("Key and value counts mismatch.");

// src/contracts/modifiers/apply.ts
async function apply(caller, input, state, ...modifiers) {
for (const modifier of modifiers) {
input = await modifier(caller, input, state);
}
return input;
}

// src/contracts/utils/index.ts
var verifyProof = async (proof, psignals, verificationKey) => {
if (!verificationKey) {
Expand Down Expand Up @@ -80,12 +88,6 @@
return input;
};
};
async function apply(caller, input, state, ...modifiers) {
for (const modifier of modifiers) {
input = await modifier(caller, input, state);
}
return input;
}

// src/contracts/hollowdb.contract.ts
var handle = async (state, action) => {
Expand Down
18 changes: 16 additions & 2 deletions src/contracts/hollowdb-set.contract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {CantEvolveError, InvalidFunctionError, KeyExistsError} from './errors';
import {apply, onlyNonNullValue, onlyNonNullValues, onlyOwner, onlyProofVerified, onlyWhitelisted} from './modifiers';
import type {ContractHandle} from './types';
import type {ContractHandle, ContractState} from './types';
import {hashToGroup} from './utils';

type Mode = {proofs: ['auth']; whitelists: ['put', 'update', 'set']};
Expand All @@ -22,7 +22,15 @@ export type SetManyInput<V> = {
};
};

export const handle: ContractHandle<Value, Mode, SetInput<Value> | SetManyInput<Value>> = async (state, action) => {
export type SetStateInput = {
function: 'seState';
value: ContractState<Mode>;
};

export const handle: ContractHandle<Value, Mode, SetInput<Value> | SetManyInput<Value> | SetStateInput> = async (
state,
action
) => {
const {caller, input} = action;
switch (input.function) {
case 'get': {
Expand Down Expand Up @@ -158,6 +166,12 @@ export const handle: ContractHandle<Value, Mode, SetInput<Value> | SetManyInput<
return {state};
}

case 'seState': {
const newState = await apply(caller, input.value, state, onlyOwner);
state = newState;
return {state};
}

default:
// type-safe way to make sure all switch cases are handled
input satisfies never;
Expand Down
17 changes: 16 additions & 1 deletion src/hollowdb-set.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {BaseSDK} from '.';
import {SetInput, SetManyInput} from './contracts/hollowdb-set.contract';
import {SetInput, SetManyInput, SetStateInput} from './contracts/hollowdb-set.contract';

/** Just like HollowDB SDK, but supports `Set` and `SetMany` operations.
* The user must be whitelisted for `set` separately to use them.
Expand Down Expand Up @@ -42,4 +42,19 @@ export class SetSDK<V = unknown> extends BaseSDK<V, {proofs: ['auth']; whitelist
},
});
}

/**
* Overwrites the contract state.
*
* Note that this is an owner-only operation, and a wrongfully
* overwritten state may break some of the contract methods.
*
* @param state the key of the value to be inserted
*/
async setState(state: Awaited<ReturnType<this['getState']>>): Promise<void> {
await this.base.dryWriteInteraction<SetStateInput>({
function: 'seState',
value: state,
});
}
}
20 changes: 20 additions & 0 deletions tests/set.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,24 @@ describe('set tests', () => {
expect(results[i]?.val).toBe(values[i].val);
}
});

it('should allow overwriting contract state', async () => {
const oldState = await owner.getState();
const newVersion = 'im-overwritten-oh-no';
await owner.setState({
...oldState,
version: newVersion,
});

const newState = await owner.getState();
expect(newState.version).toBe(newVersion);

// this kind of acts like a kill switch
// you should NOT reset the state like this
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
await owner.setState({});
const emptyState = await owner.getState();
expect(JSON.stringify(emptyState)).toBe('{}');
});
});

0 comments on commit 1a7e6c6

Please sign in to comment.