Skip to content

Commit

Permalink
339 constant key manager (#340)
Browse files Browse the repository at this point in the history
Co-authored-by: BenRey <[email protected]>
  • Loading branch information
gregLibert and Ben-Rey authored May 24, 2024
1 parent 3594583 commit 3f1d3b9
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 12 deletions.
54 changes: 54 additions & 0 deletions assembly/helpers/__tests__/constantKeyManager.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Address } from '../../std';
import { resetStorage } from '../../vm-mock';
import { u256 } from 'as-bignum/assembly';
import { ConstantManager } from '../constantKeyManager';
import { KeyIncrementer } from '../keyIncrementer';

beforeEach(() => {
resetStorage();
});

describe('ConstantManager - use cases', () => {
test('executes a basic scenario - one key', () => {
const bins = new ConstantManager<Array<u64>>();

bins.set([1, 2, 3, 4, 5]);

expect(bins.mustValue()).toStrictEqual([1, 2, 3, 4, 5]);
});

test('executes a basic scenario - multiple keys', () => {
// a key manager instance is needed to generate unique keys
const keyManager = new KeyIncrementer<u8>();
const owner = new ConstantManager<Address>(keyManager);
const fee = new ConstantManager<u64>(keyManager);
const usdc = new ConstantManager<u256>(keyManager);

owner.set(
new Address('AU12UBnqTHDQALpocVBnkPNy7y5CndUJQTLutaVDDFgMJcq5kQiKq'),
);
fee.set(100);
usdc.set(u256.fromU64(1000000));

expect(owner.mustValue().toString()).toBe(
'AU12UBnqTHDQALpocVBnkPNy7y5CndUJQTLutaVDDFgMJcq5kQiKq',
);
expect(fee.mustValue()).toBe(100);
expect(usdc.mustValue().toString()).toBe('1000000');
});
});

describe('ConstantManager - unit tests', () => {
test('mustValue - key not found', () => {
expect(() => {
const cst = new ConstantManager<u64>();
cst.mustValue();
}).toThrow('Key not found');
});

test('tryValue - key not found', () => {
const cst = new ConstantManager<Array<u64>>();
expect(cst.tryValue().isErr()).toBe(true);
expect(cst.tryValue().error).toBe('Key not found');
});
});
20 changes: 20 additions & 0 deletions assembly/helpers/__tests__/keyIncrementer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { KeyIncrementer } from '../keyIncrementer';
import { resetStorage } from '../../vm-mock';

beforeEach(() => {
resetStorage();
});

describe('KeyIncrementer - unit tests', () => {
test('nextKey - u8', () => {
const keyInc = new KeyIncrementer<u8>();
expect(keyInc.nextKey()).toStrictEqual([0]);
expect(keyInc.nextKey()).toStrictEqual([1]);
});

test('nextKey - u64', () => {
const keyInc = new KeyIncrementer<u64>();
expect(keyInc.nextKey()).toStrictEqual([0, 0, 0, 0, 0, 0, 0, 0]);
expect(keyInc.nextKey()).toStrictEqual([1, 0, 0, 0, 0, 0, 0, 0]);
});
});
54 changes: 54 additions & 0 deletions assembly/helpers/constantKeyManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Args, Result } from '@massalabs/as-types';
import { KeyIncrementer, KeySequenceManager } from './keyIncrementer';
import { Storage } from '../std';

/**
* Manages a constant value in storage.
*
* @typeParam TValue - The type of the value stored.
* @typeParam TKey - The type of the key used to store the value.
* @typeParam TArray - When value is an array of serializable, the underlying serializable type.
*/
export class ConstantManager<TValue, TKey = u8, TArray = void> {
public key: StaticArray<u8>;

constructor(manager: KeySequenceManager = new KeyIncrementer<TKey>(0)) {
this.key = manager.nextKey();
}

/**
* Retrieves the value from storage and panics in case of failure.
*
* @returns the value stored.
* @throws if the key is not found in storage.
* @throws if the value is not found in storage.
*/
public mustValue(): TValue {
return new Args(Storage.get(this.key)).next<TValue, TArray>().unwrap();
}

/**
* Retrieves the value from storage and returns a result.
*
* @returns the value stored wrapped in a result.
*/
public tryValue(): Result<TValue> {
if (!Storage.has(this.key)) {
if (isManaged<TValue>()) {
return new Result<TValue>(instantiate<TValue>(), 'Key not found');
}
return new Result<TValue>(0, 'Key not found');
}

return new Args(Storage.get(this.key)).next<TValue, TArray>();
}

/**
* Sets the value in storage.
*
* @param value - The value to store. Must be an A
*/
public set(value: TValue): void {
Storage.set(this.key, new Args().add(value).serialize());
}
}
2 changes: 2 additions & 0 deletions assembly/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './constantKeyManager';
export * from './keyIncrementer';
31 changes: 31 additions & 0 deletions assembly/helpers/keyIncrementer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Args } from '@massalabs/as-types';
/**
* Manages key sequences for storage.
*/
export interface KeySequenceManager {
nextKey(): StaticArray<u8>;
}

/**
* A key sequence manager that simply increments a counter each time a key is requested.
*
* @typeParam T - The type of the counter, defaults to `u8`.
*/
export class KeyIncrementer<T = u8> implements KeySequenceManager {
constructor(public counter: T = 0) {}

/**
* Generates the next key in the sequence.
*
* @remarks
* The `Args` class is used to serialize the counter into a key. Ideally, this serialization should
* be done outside of the `Args` object as we are allocating an object simply to get a proper serialization
* of the counter.
*
* @returns A unique storage key.
*/
@inline
public nextKey(): StaticArray<u8> {
return new Args().add(this.counter++).serialize();
}
}
2 changes: 2 additions & 0 deletions assembly/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export { env };
import * as security from './security/index';
export { security };

export * from './helpers/index';

// massa std functionalities
export * from './std';

Expand Down
34 changes: 23 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"devDependencies": {
"@as-pect/cli": "^8.1.0",
"@massalabs/as-transformer": "^0.3.2",
"@massalabs/as-types": "^2.0.0",
"@massalabs/as-types": "^2.0.1-dev.20240521132240",
"@massalabs/eslint-config": "^0.0.8",
"@massalabs/prettier-config-as": "^0.0.2",
"as-bignum": "^0.2.40",
Expand Down

0 comments on commit 3f1d3b9

Please sign in to comment.