feat: extend mutex methods

This commit is contained in:
Alex 2025-04-25 19:16:05 +03:00
parent 0d5850ec25
commit 5dd0aef472
37 changed files with 469 additions and 186 deletions

View File

@ -1,31 +1,9 @@
import { SELF_REGISTER_HANDLER_NAME } from '@coinweb/contract-kit'; import { constructCwebMain } from 'cwait';
import { selfRegisterHandler } from '@coinweb/self-register';
import { addMethodHandler, ContractHandlers, executeHandler, executor } from 'cwait';
import { PUBLIC_METHODS } from '../offchain/shared'; import { PUBLIC_METHODS } from '../offchain/shared';
import { addWord } from './addWord'; import { addWord } from './addWord';
import { mutexLock } from './mutex/lock';
import { mutexUnlock, mutexUnlockExec } from './mutex/unlock';
const createModule = (): ContractHandlers => { export const cwebMain = constructCwebMain({
const module: ContractHandlers = { handlers: {} }; [PUBLIC_METHODS.ADD_WORD]: addWord,
});
addMethodHandler(module, PUBLIC_METHODS.ADD_WORD, executor(addWord));
addMethodHandler(module, '_lock', mutexLock);
addMethodHandler(module, '_unlock', mutexUnlock);
addMethodHandler(module, '_unlock_exec', mutexUnlockExec);
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
return module;
};
export const cwebMain = () => {
return (async () => {
const module = createModule();
await executeHandler(module);
})();
};

View File

@ -1 +0,0 @@
export const mutexAccess = () => {};

View File

@ -1,43 +0,0 @@
import {
constructClaim,
constructClaimKey,
constructContinueTx,
constructContractIssuer,
constructContractRef,
constructStore,
Context,
extractContractInfo,
getContractId,
} from '@coinweb/contract-kit';
export const mutexLock = (context: Context) => {
const { providedCweb } = extractContractInfo(context.tx);
const issuer = constructContractIssuer(getContractId(context.tx));
return [
constructContinueTx(
context,
[
constructStore(
constructClaim(constructClaimKey('mutex', context.call.txid.slice(0, 8)), { word: 'CLASH' }, '0x0')
),
],
[
{
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: '_unlock',
methodArgs: [],
},
contractInfo: {
providedCweb: providedCweb ? providedCweb - 1000n : 1000n,
authenticated: null,
},
contractArgs: [],
},
},
]
),
];
};

View File

@ -1,59 +0,0 @@
import {
constructContinueTx,
constructContractIssuer,
constructContractRef,
constructRangeRead,
constructTake,
Context,
extractContractArgs,
extractContractInfo,
extractRead,
getContractId,
} from '@coinweb/contract-kit';
export const mutexUnlock = (context: Context) => {
const { providedCweb } = extractContractInfo(context.tx);
const issuer = constructContractIssuer(getContractId(context.tx));
return [
constructContinueTx(
context,
[],
[
{
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: '_unlock_exec',
methodArgs: [],
},
contractInfo: {
providedCweb: (providedCweb ? providedCweb - 1000n : 1000n) / 2n,
authenticated: null,
},
contractArgs: [constructRangeRead(issuer, 'mutex', {}, 10000)],
},
},
{
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: '_unlock',
methodArgs: [],
},
contractInfo: {
providedCweb: (providedCweb ? providedCweb - 1000n : 1000n) / 2n,
authenticated: null,
},
contractArgs: [],
},
},
]
),
];
};
export const mutexUnlockExec = (context: Context) => {
const claim = extractContractArgs(context.tx)[0]!;
const take = extractRead(claim)![0];
return [constructContinueTx(context, [constructTake(take.content.key)])];
};

View File

@ -0,0 +1,27 @@
import { ContractHandlers as ContractHandlersOrig, SELF_REGISTER_HANDLER_NAME } from '@coinweb/contract-kit';
import { selfRegisterHandler } from '@coinweb/self-register';
import { queue } from 'lib/onchain';
import { addMethodHandler, ContractHandlers, executeHandler } from '../contract-kit';
import { executor } from './executor';
import { mutexMethods } from './mutex';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const constructCwebMain = (methods: Record<string, (...args: any[]) => Promise<void>>) => async () => {
const module: ContractHandlers = { handlers: {} };
Object.entries(methods).forEach(([name, handler]) => {
addMethodHandler(module, name, executor(handler));
});
Object.entries(mutexMethods).forEach(([name, handler]) => {
addMethodHandler(module, name, handler);
});
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
queue.applyQueue(module as ContractHandlersOrig, []);
await executeHandler(module);
};

View File

@ -43,7 +43,7 @@ export const executor = (method: (...args: any[]) => Promise<void>) => {
const isFullyExecuted = await execution; const isFullyExecuted = await execution;
return constructTx(isFullyExecuted); return constructTx(isFullyExecuted);
} catch (error) { } catch (error) {
console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error'); console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error');
console.log((error as Error).message); console.log((error as Error).message);
throw error; throw error;
} }

View File

@ -0,0 +1,26 @@
import { ContractIssuer, constructContractRef } from '@coinweb/contract-kit';
import { constructMutexLockClaimRangeRead } from '../claims';
import { getAccessMethodName } from '../methods';
import { MutexGetAccessArgs } from '../types';
export const constructGetAccessCall = (
issuer: ContractIssuer,
...[claimKey, processId, uniqueId]: MutexGetAccessArgs
) => {
return {
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: getAccessMethodName,
methodArgs: [claimKey, processId, uniqueId] satisfies MutexGetAccessArgs,
},
contractInfo: {
providedCweb: 800n,
authenticated: null,
},
contractArgs: [constructMutexLockClaimRangeRead(issuer)],
},
fee: 900n,
};
};

View File

@ -0,0 +1,24 @@
import { ContractIssuer, constructContractRef } from '@coinweb/contract-kit';
import { constructMutexBlockAccessClaimTake, constructMutexLockBlock } from '../claims';
import { lockMethodName } from '../methods';
import { lockFee } from '../settings';
export const constructLockCall = (issuer: ContractIssuer, lockId: string) => {
return {
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: lockMethodName,
methodArgs: [],
},
contractInfo: {
providedCweb: lockFee,
authenticated: null,
},
contractArgs: [],
},
ops: [constructMutexLockBlock(lockId, issuer), constructMutexBlockAccessClaimTake(lockId)],
fee: lockFee + 200n,
};
};

View File

@ -0,0 +1,23 @@
import { constructContractRef, ContractIssuer } from '@coinweb/contract-kit';
import { constructMutexLockClaimRangeRead } from '../claims';
import { tryOpMethodName } from '../methods';
import { MutexTryOpArgs } from '../types';
export const constructTryOpCall = (issuer: ContractIssuer, ...[op, processId]: MutexTryOpArgs) => {
return {
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: tryOpMethodName,
methodArgs: [op, processId] satisfies MutexTryOpArgs,
},
contractInfo: {
providedCweb: 800n,
authenticated: null,
},
contractArgs: [constructMutexLockClaimRangeRead(issuer)],
},
fee: 900n,
};
};

View File

@ -0,0 +1,24 @@
import { constructContractRef, ContractIssuer } from '@coinweb/contract-kit';
import { constructMutexBlockUnlockClaimTake, constructMutexUnlockBlock } from '../claims';
import { unlockMethodName } from '../methods';
import { MutexUnlockArgs } from '../types';
export const constructUnlockCall = (issuer: ContractIssuer, ...[lockId, timestamp, notify]: MutexUnlockArgs) => {
return {
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: unlockMethodName,
methodArgs: [lockId, timestamp] satisfies MutexUnlockArgs,
},
contractInfo: {
providedCweb: 1000n,
authenticated: null,
},
contractArgs: [],
},
ops: notify ? [constructMutexUnlockBlock(lockId, issuer), constructMutexBlockUnlockClaimTake(lockId)] : [],
fee: 1200n,
};
};

View File

@ -0,0 +1,4 @@
export * from './constructGetAccessCall';
export * from './constructLockCall';
export * from './constructTryOpCall';
export * from './constructUnlockCall';

View File

@ -1,26 +0,0 @@
import {
constructClaim,
constructClaimKey,
constructStore,
constructTake,
CwebStore,
GStore,
} from '@coinweb/contract-kit';
import { MutexAccessResult, MutexAccessStatus } from '../types';
export const mutexAccessKey = 'mutex_access';
export const constructMutexAccessFirstPart = () => [mutexAccessKey];
export const constructMutexAccessClaimKey = (uniqueId: string) =>
constructClaimKey(constructMutexAccessFirstPart(), [uniqueId]);
export const constructMutexAccessClaim = (uniqueId: string, status: MutexAccessStatus) =>
constructClaim(constructMutexAccessClaimKey(uniqueId), { status } satisfies MutexAccessResult, '0x0');
export const constructMutexAccessClaimStore = (uniqueId: string, status: MutexAccessStatus): GStore<CwebStore> =>
constructStore(constructMutexAccessClaim(uniqueId, status));
export const constructMutexAccessClaimTake = (uniqueId: string) =>
constructTake(constructMutexAccessClaimKey(uniqueId));

View File

@ -1,2 +1,4 @@
export * from './access'; export * from './mutexBlockAccess';
export * from './lock'; export * from './mutexBlockLock';
export * from './mutexBlockUnlock';
export * from './mutexLock';

View File

@ -0,0 +1,41 @@
import {
BlockFilter,
constructBlock,
constructClaim,
constructClaimKey,
constructStore,
constructTake,
ContractIssuer,
CwebStore,
GStore,
} from '@coinweb/contract-kit';
import { MutexAccessResult, MutexAccessStatus } from '../types';
export const mutexBlockAccessKey = 'mutex_block_access';
export const constructMutexBlockAccessClaimKey = (uniqueId: string) =>
constructClaimKey([mutexBlockAccessKey], [uniqueId]);
export const constructMutexBlockAccessClaim = (uniqueId: string, status: MutexAccessStatus) =>
constructClaim(constructMutexBlockAccessClaimKey(uniqueId), { status } satisfies MutexAccessResult, '0x0');
export const constructMutexBlockAccessClaimStore = (uniqueId: string, status: MutexAccessStatus): GStore<CwebStore> =>
constructStore(constructMutexBlockAccessClaim(uniqueId, status));
export const constructMutexBlockAccessClaimTake = (uniqueId: string) =>
constructTake(constructMutexBlockAccessClaimKey(uniqueId));
export const constructMutexBlockAccessBlockFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
const { first_part: first, second_part: second } = constructMutexBlockAccessClaimKey(lockId);
return {
issuer,
first,
second,
};
};
export const constructMutexAccessBlock = (lockId: string, issuer: ContractIssuer) => {
return constructBlock([constructMutexBlockAccessBlockFilter(lockId, issuer)]);
};

View File

@ -0,0 +1,36 @@
import {
BlockFilter,
constructBlock,
constructClaim,
constructClaimKey,
constructStore,
constructTake,
ContractIssuer,
} from '@coinweb/contract-kit';
export const mutexBlockLockKey = 'mutex_block_lock';
export const constructMutexBlockLockClaimKey = (lockId: string) => constructClaimKey([mutexBlockLockKey], [lockId]);
export const constructMutexBlockLockClaim = ({ lockId }: { lockId: string }) =>
constructClaim(constructMutexBlockLockClaimKey(lockId), {}, '0x0');
export const constructMutexBlockLockClaimStore = ({ lockId }: { lockId: string }) =>
constructStore(constructMutexBlockLockClaim({ lockId }));
export const constructMutexBlockLockClaimTake = (lockId: string) =>
constructTake(constructMutexBlockLockClaimKey(lockId));
export const constructMutexLockBlockFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
const { first_part: first, second_part: second } = constructMutexBlockLockClaimKey(lockId);
return {
issuer,
first,
second,
};
};
export const constructMutexLockBlock = (lockId: string, issuer: ContractIssuer) => {
return constructBlock([constructMutexLockBlockFilter(lockId, issuer)]);
};

View File

@ -0,0 +1,39 @@
import {
BlockFilter,
constructBlock,
constructClaim,
constructClaimKey,
constructStore,
constructTake,
ContractIssuer,
CwebStore,
GStore,
} from '@coinweb/contract-kit';
export const mutexBlockUnlockKey = 'mutex_block_unlock';
export const constructMutexBlockUnlockClaimKey = (uniqueId: string) =>
constructClaimKey([mutexBlockUnlockKey], [uniqueId]);
export const constructMutexBlockUnlockClaim = (uniqueId: string) =>
constructClaim(constructMutexBlockUnlockClaimKey(uniqueId), {}, '0x0');
export const constructMutexBlockUnlockClaimStore = (uniqueId: string): GStore<CwebStore> =>
constructStore(constructMutexBlockUnlockClaim(uniqueId));
export const constructMutexBlockUnlockClaimTake = (uniqueId: string) =>
constructTake(constructMutexBlockUnlockClaimKey(uniqueId));
export const constructMutexUnlockBlockFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
const { first_part: first, second_part: second } = constructMutexBlockUnlockClaimKey(lockId);
return {
issuer,
first,
second,
};
};
export const constructMutexUnlockBlock = (lockId: string, issuer: ContractIssuer) => {
return constructBlock([constructMutexUnlockBlockFilter(lockId, issuer)]);
};

View File

@ -1,11 +1,9 @@
import { import {
constructClaim, constructClaim,
constructClaimKey, constructClaimKey,
constructContractIssuer,
constructRangeRead, constructRangeRead,
constructStore, constructStore,
Context, ContractIssuer,
getContractId,
GRead, GRead,
} from '@coinweb/contract-kit'; } from '@coinweb/contract-kit';
import { CwebRead } from '@coinweb/contract-kit/dist/esm/operations/read'; import { CwebRead } from '@coinweb/contract-kit/dist/esm/operations/read';
@ -58,13 +56,8 @@ export const constructMutexLockClaimStore = ({
processId: string; processId: string;
}) => constructStore(constructMutexLockClaim({ fee, keys, locked, lockId, timestamp, processId })); }) => constructStore(constructMutexLockClaim({ fee, keys, locked, lockId, timestamp, processId }));
export const constructMutexLockClaimRangeRead = (context: Context): GRead<CwebRead> => export const constructMutexLockClaimRangeRead = (issuer: ContractIssuer): GRead<CwebRead> =>
constructRangeRead( constructRangeRead(issuer, constructMutexLockFirstPart(), {}, rangeReadLimit);
constructContractIssuer(getContractId(context.tx)),
constructMutexLockFirstPart(),
{},
rangeReadLimit
);
// export const constructMutexLockClaimTake = (lockId: string, timestamp: number) => // export const constructMutexLockClaimTake = (lockId: string, timestamp: number) =>
// constructTake(constructMutexLockClaimKey(lockId, timestamp)); // constructTake(constructMutexLockClaimKey(lockId, timestamp));

View File

@ -16,7 +16,7 @@ import { lockFee } from '../settings';
import { MutexLockState } from '../types'; import { MutexLockState } from '../types';
import { isMatchLockKeys } from '../utils'; import { isMatchLockKeys } from '../utils';
import { lockMethodName } from './names'; import { lockMethodName, notifyLockMethodName } from './names';
export const mutexExecLock = (context: Context) => { export const mutexExecLock = (context: Context) => {
const { availableCweb } = getCallParameters(context); const { availableCweb } = getCallParameters(context);
@ -69,6 +69,20 @@ export const mutexExecLock = (context: Context) => {
contractArgs: [], contractArgs: [],
}, },
}, },
{
callInfo: {
ref: constructContractRef(issuer, []),
methodInfo: {
methodName: notifyLockMethodName,
methodArgs: [(lockCandidate.key.second_part as [number, string])[1]],
},
contractInfo: {
providedCweb: 200n,
authenticated: null,
},
contractArgs: [],
},
},
] ]
), ),
]; ];

View File

@ -2,7 +2,7 @@ import { constructContinueTx, Context, extractContractArgs, extractRead } from '
import { getContractArguments } from 'lib/onchain'; import { getContractArguments } from 'lib/onchain';
import { TypedClaim } from 'lib/shared'; import { TypedClaim } from 'lib/shared';
import { constructMutexAccessClaimStore } from '../claims'; import { constructMutexBlockAccessClaimStore } from '../claims';
import { MutexAccessStatus, MutexGetAccessArgs, MutexLockState } from '../types'; import { MutexAccessStatus, MutexGetAccessArgs, MutexLockState } from '../types';
import { isMatchLockKeys } from '../utils'; import { isMatchLockKeys } from '../utils';
@ -23,7 +23,7 @@ export const mutexGetAccess = (context: Context) => {
return [ return [
constructContinueTx(context, [ constructContinueTx(context, [
constructMutexAccessClaimStore( constructMutexBlockAccessClaimStore(
uniqueId, uniqueId,
isLockedByOtherProcess ? MutexAccessStatus.DENIED : MutexAccessStatus.GRANTED isLockedByOtherProcess ? MutexAccessStatus.DENIED : MutexAccessStatus.GRANTED
), ),

View File

@ -2,4 +2,6 @@ export * from './execLock';
export * from './getAccess'; export * from './getAccess';
export * from './lock'; export * from './lock';
export * from './names'; export * from './names';
export * from './notifyLock';
export * from './tryOp';
export * from './unlock'; export * from './unlock';

View File

@ -25,7 +25,7 @@ export const mutexLock = (context: Context) => {
providedCweb: availableCweb - 700n, providedCweb: availableCweb - 700n,
authenticated: null, authenticated: null,
}, },
contractArgs: [constructMutexLockClaimRangeRead(context)], contractArgs: [constructMutexLockClaimRangeRead(issuer)],
}, },
}, },
] ]

View File

@ -2,3 +2,5 @@ export const lockMethodName = '_mutex_lock';
export const execLockMethodName = '_mutex_execLock'; export const execLockMethodName = '_mutex_execLock';
export const getAccessMethodName = '_mutex_get_access'; export const getAccessMethodName = '_mutex_get_access';
export const unlockMethodName = '_mutex_unlock'; export const unlockMethodName = '_mutex_unlock';
export const tryOpMethodName = '_mutex_try_op';
export const notifyLockMethodName = '_mutex_notify_lock';

View File

@ -0,0 +1,11 @@
import { constructContinueTx, Context } from '@coinweb/contract-kit';
import { getContractArguments } from 'lib/onchain';
import { constructMutexBlockLockClaimStore } from '../claims/mutexBlockLock';
import { MutexNotifyLockArgs } from '../types';
export const notifyLock = (context: Context) => {
const [lockId] = getContractArguments<MutexNotifyLockArgs>(context);
return [constructContinueTx(context, [constructMutexBlockLockClaimStore({ lockId })])];
};

View File

@ -0,0 +1,30 @@
import { constructContinueTx, Context, extractContractArgs, extractRead } from '@coinweb/contract-kit';
import { getContractArguments } from 'lib/onchain';
import { TypedClaim } from 'lib/shared';
import { MutexLockState, MutexTryOpArgs } from '../types';
import { isMatchLockKeys } from '../utils';
export const tryOp = (context: Context) => {
const [op, processId] = getContractArguments<MutexTryOpArgs>(context);
const claimKey = 'StoreOp' in op ? op.StoreOp.key : op.TakeOp.key;
const lockQueue = extractRead(extractContractArgs(context.tx)[0])?.map(
({ content }) => content as TypedClaim<MutexLockState>
);
if (!lockQueue) {
throw new Error('No lock queue found');
}
const isLockedByOtherProcess = lockQueue.some(
({ body }) => body.locked && body.processId !== processId && body.keys.some((key) => isMatchLockKeys(key, claimKey))
);
if (isLockedByOtherProcess) {
return [];
}
return [constructContinueTx(context, [op])];
};

View File

@ -1,4 +1,4 @@
import { ClaimKey } from '@coinweb/contract-kit'; import { Claim, ClaimKey, GStore, GTake } from '@coinweb/contract-kit';
export type LockedKey = Omit<ClaimKey, 'second_part'> & Partial<Pick<ClaimKey, 'second_part'>>; export type LockedKey = Omit<ClaimKey, 'second_part'> & Partial<Pick<ClaimKey, 'second_part'>>;
@ -19,4 +19,8 @@ export type MutexAccessResult = {
export type MutexGetAccessArgs = [claimKey: ClaimKey, processId: string, uniqueId: string]; export type MutexGetAccessArgs = [claimKey: ClaimKey, processId: string, uniqueId: string];
export type MutexUnlockArgs = [lockId: string, timestamp: number]; export type MutexUnlockArgs = [lockId: string, timestamp: number, notify?: boolean];
export type MutexTryOpArgs = [op: GTake<Claim> | GStore<Claim>, processId: string];
export type MutexNotifyLockArgs = [lockId: string];

View File

@ -27,7 +27,7 @@ export const blockOp = (filters: BlockFilter[]) => {
throw new Error('Block operation not found'); throw new Error('Block operation not found');
} }
const result = op && extractBlock(op); const result = extractBlock(op);
resolve(result); resolve(result);
} }

View File

@ -0,0 +1,42 @@
import { ResolvedLockOp } from '../../../types';
import { opMarker } from '../../global';
import { LockedKey } from '../../mutex';
import { isResolvedLockOp, isResolvedSlotOp, uuid } from '../../utils';
import { pushAwaitedTask } from '../awaited';
import { shiftResolvedOp } from '../resolved';
export const lockOp = (keys: LockedKey[] | LockedKey) => {
console.log('lockOp');
let opMarkerValue = false;
const result = new Promise<ResolvedLockOp['LockOp']>((resolve, reject) => {
try {
const { op, isOp } = shiftResolvedOp();
if (!isOp) {
pushAwaitedTask({ LockOp: { lockId: uuid(), keys: Array.isArray(keys) ? keys : [keys] } });
opMarkerValue = true;
} else {
if (isResolvedSlotOp(op)) {
console.log('storeOp-slotOp');
return;
}
if (!isResolvedLockOp(op)) {
console.log('lockOp-error');
throw new Error('Lock operation not found');
}
const result = op.LockOp;
resolve(result);
}
} catch (error) {
reject(error);
}
});
(result as Promise<ResolvedLockOp['LockOp']> & { [opMarker]: boolean })[opMarker] = opMarkerValue;
return result;
};

View File

@ -34,7 +34,7 @@ export const rangeReadOp = <TClaims extends Claim[] = TypedClaim[]>(
throw new Error('Read operation not found'); throw new Error('Read operation not found');
} }
const claim = op && ((extractRead(op)?.map((result) => result.content) ?? null) as TClaims | null); const claim = (extractRead(op)?.map((result) => result.content) ?? null) as TClaims | null;
resolve(claim); resolve(claim);
} }
} catch (error) { } catch (error) {

View File

@ -29,7 +29,7 @@ export const readOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
throw new Error('Read operation not found'); throw new Error('Read operation not found');
} }
const claim = op && ((extractRead(op)?.[0]?.content ?? null) as TClaim | null); const claim = (extractRead(op)?.[0]?.content ?? null) as TClaim | null;
resolve(claim); resolve(claim);
} }
} catch (error) { } catch (error) {

View File

@ -28,7 +28,7 @@ export const storeOp = (claim: Claim) => {
throw new Error('Store operation not found'); throw new Error('Store operation not found');
} }
const result = op && extractStore(op); const result = extractStore(op);
resolve(result); resolve(result);
} }

View File

@ -28,7 +28,7 @@ export const takeOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
throw new Error('Take operation not found'); throw new Error('Take operation not found');
} }
const claim = op && extractTake(op); const claim = extractTake(op);
resolve(claim as TClaim | null); resolve(claim as TClaim | null);
} }
} catch (error) { } catch (error) {

View File

@ -0,0 +1,38 @@
import { opMarker } from '../../global';
import { isResolvedSlotOp, isResolvedUnlockOp } from '../../utils';
import { pushAwaitedTask } from '../awaited';
import { shiftResolvedOp } from '../resolved';
export const unlock = (lockId: string) => {
console.log('lockOp');
let opMarkerValue = false;
const result = new Promise<void>((resolve, reject) => {
try {
const { op, isOp } = shiftResolvedOp();
if (!isOp) {
pushAwaitedTask({ UnlockOp: { lockId } });
opMarkerValue = true;
} else {
if (isResolvedSlotOp(op)) {
console.log('unlockOp-slotOp');
return;
}
if (!isResolvedUnlockOp(op)) {
console.log('unlockOp-error');
throw new Error('Unlock operation not found');
}
resolve();
}
} catch (error) {
reject(error);
}
});
(result as Promise<void> & { [opMarker]: boolean })[opMarker] = opMarkerValue;
return result;
};

View File

@ -1,2 +0,0 @@
export * from './jumpTx';
export * from './tx';

View File

@ -1 +0,0 @@
export const jumpTx = () => null;

View File

@ -1 +0,0 @@
export const tx = () => null;

View File

@ -13,7 +13,16 @@ import { CwebCallRefResolved, isResolvedCall } from '@coinweb/contract-kit/dist/
import { ResolvedBlock } from '@coinweb/contract-kit/dist/types/operations/block'; import { ResolvedBlock } from '@coinweb/contract-kit/dist/types/operations/block';
import { GBlock, GCall, GRead, GStore, GTake } from '@coinweb/contract-kit/dist/types/operations/generics'; import { GBlock, GCall, GRead, GStore, GTake } from '@coinweb/contract-kit/dist/types/operations/generics';
import { PreparedExecOp, PreparedOp, ResolvedChildOp, ResolvedExecOp, ResolvedOp, ResolvedSlotOp } from '../../types'; import {
PreparedExecOp,
PreparedOp,
ResolvedChildOp,
ResolvedExecOp,
ResolvedLockOp,
ResolvedOp,
ResolvedSlotOp,
ResolvedUnlockOp,
} from '../../types';
export const isResolvedSlotOp = (op?: ResolvedOp | null): op is ResolvedSlotOp => { export const isResolvedSlotOp = (op?: ResolvedOp | null): op is ResolvedSlotOp => {
if (op && 'SlotOp' in op) { if (op && 'SlotOp' in op) {
@ -39,6 +48,22 @@ export const isResolvedChildOp = (op?: ResolvedOp | null): op is ResolvedChildOp
return !!(op && 'ChildOp' in op); return !!(op && 'ChildOp' in op);
}; };
export const isResolvedLockOp = (op?: ResolvedOp | null): op is ResolvedLockOp => {
if (op && 'LockOp' in op) {
console.log('isResolvedLockOp >>> ', JSON.stringify(op));
}
return !!(op && 'LockOp' in op);
};
export const isResolvedUnlockOp = (op?: ResolvedOp | null): op is ResolvedUnlockOp => {
if (op && 'UnlockOp' in op) {
console.log('isResolvedUnlockOp >>> ', JSON.stringify(op));
}
return !!(op && 'UnlockOp' in op);
};
export const isResolvedBlockOp = (op?: ResolvedOp | null): op is GBlock<ResolvedBlock> => { export const isResolvedBlockOp = (op?: ResolvedOp | null): op is GBlock<ResolvedBlock> => {
if (op && 'BlockOp' in op) { if (op && 'BlockOp' in op) {
console.log('isResolvedBlockOp >>> ', JSON.stringify(op)); console.log('isResolvedBlockOp >>> ', JSON.stringify(op));

View File

@ -1,5 +1,7 @@
import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation, User } from '@coinweb/contract-kit'; import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation, User } from '@coinweb/contract-kit';
import { LockedKey } from './onchain/mutex';
export type HexBigInt = `0x${string}`; export type HexBigInt = `0x${string}`;
export type TypedClaim<TBody extends OrdJson = OrdJson, TKey extends ClaimKey = ClaimKey> = Claim & { export type TypedClaim<TBody extends OrdJson = OrdJson, TKey extends ClaimKey = ClaimKey> = Claim & {
@ -22,7 +24,23 @@ export type ResolvedChildOp = {
ChildOp: 0; ChildOp: 0;
}; };
export type ResolvedOp = ResolvedOperation | ResolvedSlotOp | ResolvedExecOp | ResolvedChildOp; export type ResolvedLockOp = {
LockOp: {
lockId: string;
};
};
export type ResolvedUnlockOp = {
UnlockOp: 0;
};
export type ResolvedOp =
| ResolvedOperation
| ResolvedSlotOp
| ResolvedExecOp
| ResolvedChildOp
| ResolvedLockOp
| ResolvedUnlockOp;
export type PreparedExecOp = { export type PreparedExecOp = {
ExecOp: { ExecOp: {
@ -30,7 +48,20 @@ export type PreparedExecOp = {
}; };
}; };
export type PreparedOp = PreparedOperation | PreparedExecOp; export type PreparedLockOp = {
LockOp: {
lockId: string;
keys: LockedKey[];
};
};
export type PreparedUnlockOp = {
UnlockOp: {
lockId: string;
};
};
export type PreparedOp = PreparedOperation | PreparedExecOp | PreparedLockOp | PreparedUnlockOp;
export type Task = { export type Task = {
op: PreparedOp; op: PreparedOp;