feat: extend mutex methods
This commit is contained in:
parent
0d5850ec25
commit
5dd0aef472
@ -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);
|
|
||||||
})();
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export const mutexAccess = () => {};
|
|
||||||
@ -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: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
@ -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)])];
|
|
||||||
};
|
|
||||||
27
packages/cwait/src/onchain/constructCwebMain.ts
Normal file
27
packages/cwait/src/onchain/constructCwebMain.ts
Normal 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);
|
||||||
|
};
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
};
|
||||||
|
};
|
||||||
24
packages/cwait/src/onchain/mutex/calls/constructLockCall.ts
Normal file
24
packages/cwait/src/onchain/mutex/calls/constructLockCall.ts
Normal 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,
|
||||||
|
};
|
||||||
|
};
|
||||||
23
packages/cwait/src/onchain/mutex/calls/constructTryOpCall.ts
Normal file
23
packages/cwait/src/onchain/mutex/calls/constructTryOpCall.ts
Normal 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,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -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,
|
||||||
|
};
|
||||||
|
};
|
||||||
4
packages/cwait/src/onchain/mutex/calls/index.ts
Normal file
4
packages/cwait/src/onchain/mutex/calls/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './constructGetAccessCall';
|
||||||
|
export * from './constructLockCall';
|
||||||
|
export * from './constructTryOpCall';
|
||||||
|
export * from './constructUnlockCall';
|
||||||
@ -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));
|
|
||||||
@ -1,2 +1,4 @@
|
|||||||
export * from './access';
|
export * from './mutexBlockAccess';
|
||||||
export * from './lock';
|
export * from './mutexBlockLock';
|
||||||
|
export * from './mutexBlockUnlock';
|
||||||
|
export * from './mutexLock';
|
||||||
|
|||||||
41
packages/cwait/src/onchain/mutex/claims/mutexBlockAccess.ts
Normal file
41
packages/cwait/src/onchain/mutex/claims/mutexBlockAccess.ts
Normal 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)]);
|
||||||
|
};
|
||||||
36
packages/cwait/src/onchain/mutex/claims/mutexBlockLock.ts
Normal file
36
packages/cwait/src/onchain/mutex/claims/mutexBlockLock.ts
Normal 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)]);
|
||||||
|
};
|
||||||
39
packages/cwait/src/onchain/mutex/claims/mutexBlockUnlock.ts
Normal file
39
packages/cwait/src/onchain/mutex/claims/mutexBlockUnlock.ts
Normal 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)]);
|
||||||
|
};
|
||||||
@ -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));
|
||||||
@ -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: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|||||||
@ -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
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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';
|
||||||
|
|||||||
@ -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)],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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';
|
||||||
|
|||||||
11
packages/cwait/src/onchain/mutex/methods/notifyLock.ts
Normal file
11
packages/cwait/src/onchain/mutex/methods/notifyLock.ts
Normal 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 })])];
|
||||||
|
};
|
||||||
30
packages/cwait/src/onchain/mutex/methods/tryOp.ts
Normal file
30
packages/cwait/src/onchain/mutex/methods/tryOp.ts
Normal 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])];
|
||||||
|
};
|
||||||
@ -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];
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
42
packages/cwait/src/onchain/promisifiedOps/ops/lock.ts
Normal file
42
packages/cwait/src/onchain/promisifiedOps/ops/lock.ts
Normal 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;
|
||||||
|
};
|
||||||
@ -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) {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
38
packages/cwait/src/onchain/promisifiedOps/ops/unlock.ts
Normal file
38
packages/cwait/src/onchain/promisifiedOps/ops/unlock.ts
Normal 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;
|
||||||
|
};
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from './jumpTx';
|
|
||||||
export * from './tx';
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export const jumpTx = () => null;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export const tx = () => null;
|
|
||||||
@ -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));
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user