add: mutex calls
This commit is contained in:
parent
5dd0aef472
commit
02f81660a7
@ -0,0 +1,70 @@
|
||||
import { constructContractRef, ContractIssuer, CwebStore, GStore, GTake } from '@coinweb/contract-kit';
|
||||
import { CwebTake } from '@coinweb/contract-kit/dist/types/operations/take';
|
||||
|
||||
import { PreparedExtendedStoreOp } from '../../../types';
|
||||
import {
|
||||
constructMutexExecOpsBlock,
|
||||
constructMutexExecOpsClaimTake,
|
||||
constructMutexLockClaimRangeRead,
|
||||
} from '../claims';
|
||||
import { execOpsMethodName } from '../methods';
|
||||
import { MutexExecOpArgs } from '../types';
|
||||
|
||||
export const constructExecOpsCall = ({
|
||||
issuer,
|
||||
ops,
|
||||
processId,
|
||||
execId,
|
||||
}: {
|
||||
issuer: ContractIssuer;
|
||||
ops: (GTake<CwebTake> | PreparedExtendedStoreOp)[];
|
||||
processId: string;
|
||||
execId?: string;
|
||||
}) => {
|
||||
const opsFee = BigInt(ops.length) * 100n;
|
||||
const execCallInnerFee = 700n;
|
||||
|
||||
const takeOpsAdditionalFee = BigInt(ops.filter((op) => 'TakeOp' in op).length) * 100n;
|
||||
const prepareTakeOpsInnerFee = takeOpsAdditionalFee > 0n ? 700n : 0n;
|
||||
|
||||
const storedCweb = ops
|
||||
.filter((op) => 'StoreOp' in op)
|
||||
.reduce((total, op) => {
|
||||
if (op.providedCweb) {
|
||||
return total + op.providedCweb;
|
||||
}
|
||||
return total + BigInt(op.StoreOp.fees_stored);
|
||||
}, 0n);
|
||||
|
||||
const callFee = 700n;
|
||||
|
||||
const providedCweb = opsFee + execCallInnerFee + takeOpsAdditionalFee + prepareTakeOpsInnerFee + storedCweb + callFee;
|
||||
const contractArgsFee = 100n;
|
||||
|
||||
const preparedOps: (GTake<CwebTake> | GStore<CwebStore>)[] = ops.map((op) => {
|
||||
if ('StoreOp' in op) {
|
||||
const preparedStoreOp = { ...op };
|
||||
delete preparedStoreOp.providedCweb;
|
||||
return preparedStoreOp;
|
||||
}
|
||||
|
||||
return op;
|
||||
});
|
||||
|
||||
return {
|
||||
callInfo: {
|
||||
ref: constructContractRef(issuer, []),
|
||||
methodInfo: {
|
||||
methodName: execOpsMethodName,
|
||||
methodArgs: [preparedOps, processId, execId] satisfies MutexExecOpArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
providedCweb,
|
||||
authenticated: null,
|
||||
},
|
||||
contractArgs: [constructMutexLockClaimRangeRead(issuer)],
|
||||
},
|
||||
fee: providedCweb + contractArgsFee,
|
||||
ops: execId ? ([constructMutexExecOpsBlock(execId, issuer), constructMutexExecOpsClaimTake(execId)] as const) : [],
|
||||
};
|
||||
};
|
||||
@ -1,26 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { ContractIssuer, constructContractRef } from '@coinweb/contract-kit';
|
||||
|
||||
import { constructMutexBlockAccessClaimTake, constructMutexLockBlock } from '../claims';
|
||||
import { constructMutexBlockLockClaimTake, constructMutexLockBlock } from '../claims';
|
||||
import { lockMethodName } from '../methods';
|
||||
import { lockFee } from '../settings';
|
||||
|
||||
@ -18,7 +18,7 @@ export const constructLockCall = (issuer: ContractIssuer, lockId: string) => {
|
||||
},
|
||||
contractArgs: [],
|
||||
},
|
||||
ops: [constructMutexLockBlock(lockId, issuer), constructMutexBlockAccessClaimTake(lockId)],
|
||||
ops: [constructMutexLockBlock(lockId, issuer), constructMutexBlockLockClaimTake(lockId)] as const,
|
||||
fee: lockFee + 200n,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
@ -18,7 +18,9 @@ export const constructUnlockCall = (issuer: ContractIssuer, ...[lockId, timestam
|
||||
},
|
||||
contractArgs: [],
|
||||
},
|
||||
ops: notify ? [constructMutexUnlockBlock(lockId, issuer), constructMutexBlockUnlockClaimTake(lockId)] : [],
|
||||
ops: notify
|
||||
? ([constructMutexUnlockBlock(lockId, issuer), constructMutexBlockUnlockClaimTake(lockId)] as const)
|
||||
: [],
|
||||
fee: 1200n,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
export * from './constructGetAccessCall';
|
||||
export * from './constructLockCall';
|
||||
export * from './constructTryOpCall';
|
||||
export * from './constructExecOpsCall';
|
||||
export * from './constructUnlockCall';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export * from './mutexBlockAccess';
|
||||
export * from './mutexExecOps';
|
||||
export * from './mutexBlockLock';
|
||||
export * from './mutexBlockUnlock';
|
||||
export * from './mutexLock';
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
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)]);
|
||||
};
|
||||
43
packages/cwait/src/onchain/mutex/claims/mutexExecOps.ts
Normal file
43
packages/cwait/src/onchain/mutex/claims/mutexExecOps.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import {
|
||||
BlockFilter,
|
||||
constructBlock,
|
||||
constructClaim,
|
||||
constructClaimKey,
|
||||
constructStore,
|
||||
constructTake,
|
||||
ContractIssuer,
|
||||
CwebStore,
|
||||
GStore,
|
||||
} from '@coinweb/contract-kit';
|
||||
import { toHex } from 'lib/shared';
|
||||
|
||||
import { MutexExecOpsResult } from '../types';
|
||||
|
||||
export const mutexExecOpsKey = 'mutex_exec_ops';
|
||||
|
||||
export const constructMutexExecOpsClaimKey = (execId: string) => constructClaimKey([mutexExecOpsKey], [execId]);
|
||||
|
||||
export const constructMutexExecOpsClaim = (execId: string, result: MutexExecOpsResult, storeCweb: bigint) =>
|
||||
constructClaim(constructMutexExecOpsClaimKey(execId), result, toHex(storeCweb));
|
||||
|
||||
export const constructMutexExecOpsClaimStore = (
|
||||
execId: string,
|
||||
result: MutexExecOpsResult,
|
||||
storeCweb: bigint = 0n
|
||||
): GStore<CwebStore> => constructStore(constructMutexExecOpsClaim(execId, result, storeCweb));
|
||||
|
||||
export const constructMutexExecOpsClaimTake = (execId: string) => constructTake(constructMutexExecOpsClaimKey(execId));
|
||||
|
||||
export const constructMutexExecOpsFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
|
||||
const { first_part: first, second_part: second } = constructMutexExecOpsClaimKey(lockId);
|
||||
|
||||
return {
|
||||
issuer,
|
||||
first,
|
||||
second,
|
||||
};
|
||||
};
|
||||
|
||||
export const constructMutexExecOpsBlock = (lockId: string, issuer: ContractIssuer) => {
|
||||
return constructBlock([constructMutexExecOpsFilter(lockId, issuer)]);
|
||||
};
|
||||
@ -1,20 +1,27 @@
|
||||
import {
|
||||
execLockMethodName,
|
||||
getAccessMethodName,
|
||||
execOps,
|
||||
execOpsMethodName,
|
||||
lockMethodName,
|
||||
mutexExecLock,
|
||||
mutexGetAccess,
|
||||
mutexLock,
|
||||
mutexUnlock,
|
||||
preReadExecTakeOpsMethodName,
|
||||
saveExecOpResult,
|
||||
saveExecOpResultMethodName,
|
||||
unlockMethodName,
|
||||
} from './methods';
|
||||
import { preReadExecTakeOps } from './methods/preReadExecTakeOps';
|
||||
|
||||
export * from './claims';
|
||||
export * from './types';
|
||||
export * from './calls';
|
||||
|
||||
export const mutexMethods = {
|
||||
[execLockMethodName]: mutexExecLock,
|
||||
[getAccessMethodName]: mutexGetAccess,
|
||||
[lockMethodName]: mutexLock,
|
||||
[unlockMethodName]: mutexUnlock,
|
||||
[execOpsMethodName]: execOps,
|
||||
[preReadExecTakeOpsMethodName]: preReadExecTakeOps,
|
||||
[saveExecOpResultMethodName]: saveExecOpResult,
|
||||
};
|
||||
|
||||
117
packages/cwait/src/onchain/mutex/methods/execOps.ts
Normal file
117
packages/cwait/src/onchain/mutex/methods/execOps.ts
Normal file
@ -0,0 +1,117 @@
|
||||
import {
|
||||
constructContinueTx,
|
||||
constructContractRef,
|
||||
constructRead,
|
||||
Context,
|
||||
extractContractArgs,
|
||||
extractRead,
|
||||
PreparedOperation,
|
||||
} from '@coinweb/contract-kit';
|
||||
import { getCallParameters, getContractArguments, getContractIssuer } from 'lib/onchain';
|
||||
import { TypedClaim } from 'lib/shared';
|
||||
|
||||
import { constructMutexExecOpsClaimStore } from '../claims';
|
||||
import { MutexLockState, MutexExecOpArgs, MutexSaveExecOpResultArgs, MutexPreReadTakeOpsArgs } from '../types';
|
||||
import { isMatchLockKeys } from '../utils';
|
||||
|
||||
import { saveExecOpResultMethodName } from './names';
|
||||
|
||||
export const execOps = (context: Context) => {
|
||||
const { availableCweb } = getCallParameters(context);
|
||||
const issuer = getContractIssuer(context);
|
||||
|
||||
const [ops, processId, execId] = getContractArguments<MutexExecOpArgs>(context);
|
||||
|
||||
const lockQueue = extractRead(extractContractArgs(context.tx)[0])?.map(
|
||||
({ content }) => content as TypedClaim<MutexLockState>
|
||||
);
|
||||
|
||||
let availableOps: PreparedOperation[] = [];
|
||||
const unavailableIndexes: number[] = [];
|
||||
|
||||
if (!lockQueue) {
|
||||
availableOps = ops;
|
||||
} else {
|
||||
ops.forEach((op, i) => {
|
||||
const claimKey = 'StoreOp' in op ? op.StoreOp.key : op.TakeOp.key;
|
||||
const isLockedByOtherProcess = lockQueue.some(
|
||||
({ body }) =>
|
||||
body.locked && body.processId !== processId && body.keys.some((key) => isMatchLockKeys(key, claimKey))
|
||||
);
|
||||
|
||||
if (isLockedByOtherProcess) {
|
||||
unavailableIndexes.push(i);
|
||||
} else {
|
||||
availableOps.push(op);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (availableOps.length === 0) {
|
||||
return execId
|
||||
? [
|
||||
constructContinueTx(context, [
|
||||
constructMutexExecOpsClaimStore(execId, new Array(ops.length).fill({ ok: false })),
|
||||
]),
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
if (!execId) {
|
||||
return [constructContinueTx(context, availableOps)];
|
||||
}
|
||||
|
||||
const preReadTakeOps = availableOps.filter((op) => 'TakeOp' in op).map((op) => constructRead(issuer, op.TakeOp.key));
|
||||
|
||||
if (preReadTakeOps.length > 0) {
|
||||
const fee = 700n + BigInt(preReadTakeOps.length) * 100n;
|
||||
|
||||
return [
|
||||
constructContinueTx(
|
||||
context,
|
||||
[],
|
||||
[
|
||||
{
|
||||
callInfo: {
|
||||
ref: constructContractRef(issuer, []),
|
||||
methodInfo: {
|
||||
methodName: saveExecOpResultMethodName,
|
||||
methodArgs: [execId, unavailableIndexes, availableOps] satisfies MutexPreReadTakeOpsArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
providedCweb: availableCweb - fee,
|
||||
authenticated: null,
|
||||
},
|
||||
contractArgs: preReadTakeOps,
|
||||
},
|
||||
},
|
||||
]
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
const fee = 700n + BigInt(availableOps.length) * 100n;
|
||||
|
||||
return [
|
||||
constructContinueTx(
|
||||
context,
|
||||
[],
|
||||
[
|
||||
{
|
||||
callInfo: {
|
||||
ref: constructContractRef(issuer, []),
|
||||
methodInfo: {
|
||||
methodName: saveExecOpResultMethodName,
|
||||
methodArgs: [execId, unavailableIndexes] satisfies MutexSaveExecOpResultArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
providedCweb: availableCweb - fee,
|
||||
authenticated: null,
|
||||
},
|
||||
contractArgs: availableOps,
|
||||
},
|
||||
},
|
||||
]
|
||||
),
|
||||
];
|
||||
};
|
||||
@ -1,32 +0,0 @@
|
||||
import { constructContinueTx, Context, extractContractArgs, extractRead } from '@coinweb/contract-kit';
|
||||
import { getContractArguments } from 'lib/onchain';
|
||||
import { TypedClaim } from 'lib/shared';
|
||||
|
||||
import { constructMutexBlockAccessClaimStore } from '../claims';
|
||||
import { MutexAccessStatus, MutexGetAccessArgs, MutexLockState } from '../types';
|
||||
import { isMatchLockKeys } from '../utils';
|
||||
|
||||
export const mutexGetAccess = (context: Context) => {
|
||||
const [claimKey, processId, uniqueId] = getContractArguments<MutexGetAccessArgs>(context);
|
||||
|
||||
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))
|
||||
);
|
||||
|
||||
return [
|
||||
constructContinueTx(context, [
|
||||
constructMutexBlockAccessClaimStore(
|
||||
uniqueId,
|
||||
isLockedByOtherProcess ? MutexAccessStatus.DENIED : MutexAccessStatus.GRANTED
|
||||
),
|
||||
]),
|
||||
];
|
||||
};
|
||||
@ -1,7 +1,7 @@
|
||||
export * from './execLock';
|
||||
export * from './getAccess';
|
||||
export * from './lock';
|
||||
export * from './names';
|
||||
export * from './notifyLock';
|
||||
export * from './tryOp';
|
||||
export * from './execOps';
|
||||
export * from './unlock';
|
||||
export * from './saveExecOpResult';
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
export const lockMethodName = '_mutex_lock';
|
||||
export const execLockMethodName = '_mutex_execLock';
|
||||
export const getAccessMethodName = '_mutex_get_access';
|
||||
export const unlockMethodName = '_mutex_unlock';
|
||||
export const tryOpMethodName = '_mutex_try_op';
|
||||
export const notifyLockMethodName = '_mutex_notify_lock';
|
||||
export const execOpsMethodName = '_mutex_execOps';
|
||||
export const saveExecOpResultMethodName = '_mutex_save_exec_op_result';
|
||||
export const preReadExecTakeOpsMethodName = '_mutex_pre_read_exec_take_ops';
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
import {
|
||||
constructContinueTx,
|
||||
constructContractRef,
|
||||
Context,
|
||||
extractContractArgs,
|
||||
extractRead,
|
||||
passCwebFrom,
|
||||
} from '@coinweb/contract-kit';
|
||||
import { getCallParameters, getContractArguments, getContractIssuer } from 'lib/onchain';
|
||||
|
||||
import { MutexPreReadTakeOpsArgs, MutexSaveExecOpResultArgs } from '../types';
|
||||
|
||||
import { saveExecOpResultMethodName } from './names';
|
||||
|
||||
export const preReadExecTakeOps = (context: Context) => {
|
||||
const { availableCweb } = getCallParameters(context);
|
||||
const issuer = getContractIssuer(context);
|
||||
|
||||
const [execId, unavailableIndexes, ops] = getContractArguments<MutexPreReadTakeOpsArgs>(context);
|
||||
|
||||
const storedCweb = extractContractArgs(context.tx)
|
||||
.map((op) => BigInt(extractRead(op)?.[0]?.content.fees_stored ?? 0))
|
||||
.reduce((total, op) => total + op, 0n);
|
||||
|
||||
const fee = 700n + BigInt(ops.length) * 100n;
|
||||
|
||||
return [
|
||||
constructContinueTx(
|
||||
context,
|
||||
[passCwebFrom(issuer, availableCweb)],
|
||||
[
|
||||
{
|
||||
callInfo: {
|
||||
ref: constructContractRef(issuer, []),
|
||||
methodInfo: {
|
||||
methodName: saveExecOpResultMethodName,
|
||||
methodArgs: [execId, unavailableIndexes] satisfies MutexSaveExecOpResultArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
providedCweb: availableCweb + storedCweb - fee,
|
||||
authenticated: null,
|
||||
},
|
||||
contractArgs: ops,
|
||||
},
|
||||
},
|
||||
]
|
||||
),
|
||||
];
|
||||
};
|
||||
33
packages/cwait/src/onchain/mutex/methods/saveExecOpResult.ts
Normal file
33
packages/cwait/src/onchain/mutex/methods/saveExecOpResult.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { constructContinueTx, Context, extractContractArgs } from '@coinweb/contract-kit';
|
||||
import { getCallParameters, getContractArguments } from 'lib/onchain';
|
||||
|
||||
import { constructMutexExecOpsClaimStore } from '../claims';
|
||||
import { MutexExecOpsResult, MutexSaveExecOpResultArgs } from '../types';
|
||||
|
||||
export const saveExecOpResult = (context: Context) => {
|
||||
const { availableCweb } = getCallParameters(context);
|
||||
|
||||
const [execId, unavailableIndexes] = getContractArguments<MutexSaveExecOpResultArgs>(context);
|
||||
const resolvedOps = extractContractArgs(context.tx);
|
||||
|
||||
const result = new Array(resolvedOps.length + unavailableIndexes.length)
|
||||
.fill({ ok: false, error: 'Resource is busy' })
|
||||
.map((value: MutexExecOpsResult[number], i) => {
|
||||
if (unavailableIndexes.includes(i)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const resolvedOp = resolvedOps.shift();
|
||||
|
||||
if (!resolvedOp) {
|
||||
throw new Error('An error occurred while saving the exec op result');
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true as const,
|
||||
resolved: resolvedOp,
|
||||
};
|
||||
});
|
||||
|
||||
return [constructContinueTx(context, [constructMutexExecOpsClaimStore(execId, result, availableCweb - 200n)])];
|
||||
};
|
||||
@ -1,30 +0,0 @@
|
||||
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,5 @@
|
||||
import { Claim, ClaimKey, GStore, GTake } from '@coinweb/contract-kit';
|
||||
import { ClaimKey, CwebStore, GStore, GTake, PreparedOperation, ResolvedOperation } from '@coinweb/contract-kit';
|
||||
import { CwebTake } from '@coinweb/contract-kit/dist/types/operations/take';
|
||||
|
||||
export type LockedKey = Omit<ClaimKey, 'second_part'> & Partial<Pick<ClaimKey, 'second_part'>>;
|
||||
|
||||
@ -8,19 +9,23 @@ export type MutexLockState = {
|
||||
processId: string;
|
||||
};
|
||||
|
||||
export enum MutexAccessStatus {
|
||||
GRANTED = 'granted',
|
||||
DENIED = 'denied',
|
||||
export type MutexExecOpsResult = (
|
||||
| {
|
||||
ok: true;
|
||||
resolved: ResolvedOperation;
|
||||
}
|
||||
|
||||
export type MutexAccessResult = {
|
||||
status: MutexAccessStatus;
|
||||
};
|
||||
|
||||
export type MutexGetAccessArgs = [claimKey: ClaimKey, processId: string, uniqueId: string];
|
||||
| {
|
||||
ok: false;
|
||||
error: string;
|
||||
}
|
||||
)[];
|
||||
|
||||
export type MutexUnlockArgs = [lockId: string, timestamp: number, notify?: boolean];
|
||||
|
||||
export type MutexTryOpArgs = [op: GTake<Claim> | GStore<Claim>, processId: string];
|
||||
export type MutexExecOpArgs = [ops: (GTake<CwebTake> | GStore<CwebStore>)[], processId: string, execId?: string];
|
||||
|
||||
export type MutexNotifyLockArgs = [lockId: string];
|
||||
|
||||
export type MutexPreReadTakeOpsArgs = [execId: string, unavailableIndexes: number[], ops: PreparedOperation[]];
|
||||
|
||||
export type MutexSaveExecOpResultArgs = [execId: string, unavailableIndexes: number[]];
|
||||
|
||||
@ -6,7 +6,7 @@ import { isResolvedSlotOp, isResolvedStoreOp } from '../../utils';
|
||||
import { pushAwaitedTask } from '../awaited';
|
||||
import { shiftResolvedOp } from '../resolved';
|
||||
|
||||
export const storeOp = (claim: Claim) => {
|
||||
export const storeOp = (claim: Claim, storeCweb?: bigint) => {
|
||||
console.log('storeOp');
|
||||
let opMarkerValue = false;
|
||||
|
||||
@ -15,7 +15,7 @@ export const storeOp = (claim: Claim) => {
|
||||
const { op, isOp } = shiftResolvedOp();
|
||||
|
||||
if (!isOp) {
|
||||
pushAwaitedTask(constructStore(claim));
|
||||
pushAwaitedTask({ ...constructStore(claim), providedCweb: storeCweb });
|
||||
opMarkerValue = true;
|
||||
} else {
|
||||
if (isResolvedSlotOp(op)) {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { prepareTx } from './prepareTxs';
|
||||
|
||||
export const constructTx = (isFullyExecuted: boolean) => {
|
||||
const { calls } = prepareTx(isFullyExecuted);
|
||||
const { calls, txFee } = prepareTx(isFullyExecuted, 0n);
|
||||
|
||||
const { txs } = prepareTx(isFullyExecuted, calls);
|
||||
const { txs } = prepareTx(isFullyExecuted, txFee, calls);
|
||||
|
||||
return txs;
|
||||
};
|
||||
|
||||
@ -3,42 +3,52 @@ import {
|
||||
constructContinueTx,
|
||||
constructContractRef,
|
||||
FullCallInfo,
|
||||
GTake,
|
||||
NewTx,
|
||||
passCwebFrom,
|
||||
PreparedOperation,
|
||||
sendCwebInterface,
|
||||
} from '@coinweb/contract-kit';
|
||||
import { CwebBlock } from '@coinweb/contract-kit/dist/esm/operations/block';
|
||||
import { GBlock } from '@coinweb/contract-kit/dist/types/operations/generics';
|
||||
import { CwebTake } from '@coinweb/contract-kit/dist/types/operations/take';
|
||||
|
||||
import { ExecutorMethodArgs, ResolvedOp, ResolvedSlotOp, Task } from '../../../types';
|
||||
import { ExecutorMethodArgs, PreparedExtendedStoreOp, PreparedOp, ResolvedOp, ResolvedSlotOp } from '../../../types';
|
||||
import { constructFundsClaimRangRead, constructFundsClaimStore } from '../../claims/funds';
|
||||
import { constructResultBlockFilter, constructResultClaimTake, resultKey } from '../../claims/result';
|
||||
import { context, getRawContext } from '../../context';
|
||||
import { isPreparedBlockOp, isPreparedExecOp } from '../typeGuards';
|
||||
import { constructExecOpsCall, constructLockCall, constructUnlockCall } from '../../mutex';
|
||||
import {
|
||||
isPreparedExecOp,
|
||||
isPreparedLockOp,
|
||||
isPreparedStoreOp,
|
||||
isPreparedTakeOp,
|
||||
isPreparedUnlockOp,
|
||||
} from '../typeGuards';
|
||||
import { uuid } from '../uuid';
|
||||
|
||||
export const prepareInThreadTxs = ({
|
||||
cwebPerCall,
|
||||
outThreadTasksCount,
|
||||
outThreadFee,
|
||||
tasks,
|
||||
ops,
|
||||
}: {
|
||||
tasks: Task[];
|
||||
ops: PreparedOp[];
|
||||
cwebPerCall: bigint;
|
||||
outThreadTasksCount: number;
|
||||
outThreadFee: bigint;
|
||||
}): {
|
||||
txs: NewTx[];
|
||||
calls: number;
|
||||
txFee: bigint;
|
||||
} => {
|
||||
if (!tasks.length) {
|
||||
if (!ops.length) {
|
||||
const { constructSendCweb } = sendCwebInterface();
|
||||
const { availableCweb, takeOps, storedCweb } = context.funds;
|
||||
const { user } = context;
|
||||
|
||||
const restOfAvailableCweb = availableCweb - outThreadFee;
|
||||
|
||||
const restOfCweb = restOfAvailableCweb + storedCweb - BigInt(takeOps.length) * 100n - 3000n;
|
||||
const fee = BigInt(takeOps.length) * 100n - 3000n;
|
||||
const restOfCweb = restOfAvailableCweb + storedCweb - fee;
|
||||
|
||||
const txs =
|
||||
restOfCweb > 0n
|
||||
@ -51,12 +61,15 @@ export const prepareInThreadTxs = ({
|
||||
]
|
||||
: [];
|
||||
|
||||
return { txs, calls: 0 };
|
||||
return { txs, calls: 0, txFee: fee };
|
||||
}
|
||||
|
||||
let txFee = 0n;
|
||||
let callsPrepared = 0;
|
||||
const resolvedSlotOps = new Array(outThreadTasksCount).fill({ SlotOp: 0 }) satisfies ResolvedSlotOp[];
|
||||
const resolvedSlotOps = new Array(outThreadTasksCount).fill({ SlotOp: { ok: true } }) satisfies ResolvedSlotOp[];
|
||||
|
||||
const preparedExecOps: (PreparedExtendedStoreOp | GTake<CwebTake>)[] = [];
|
||||
const excOpsIndexes: number[] = [];
|
||||
|
||||
const resolvedChildOps: ResolvedOp[] = [...context.ops, ...resolvedSlotOps];
|
||||
|
||||
@ -66,15 +79,11 @@ export const prepareInThreadTxs = ({
|
||||
//Info for separate child call
|
||||
const childCalls: FullCallInfo[] = [];
|
||||
|
||||
//Block ops for separate child call
|
||||
const childBlocks = tasks
|
||||
.filter((task): task is { op: GBlock<CwebBlock>; batchId: number } => isPreparedBlockOp(task.op))
|
||||
.map(({ op }) => op);
|
||||
|
||||
tasks.forEach((task) => {
|
||||
if (isPreparedExecOp(task.op)) {
|
||||
ops.forEach((op, i) => {
|
||||
switch (true) {
|
||||
case isPreparedExecOp(op): {
|
||||
console.log('Child call info');
|
||||
const id = task.op.ExecOp.id;
|
||||
const id = op.ExecOp.id;
|
||||
|
||||
callArgs.push(constructBlock([constructResultBlockFilter(id)]), constructResultClaimTake(id));
|
||||
txFee += 200n;
|
||||
@ -94,7 +103,7 @@ export const prepareInThreadTxs = ({
|
||||
] satisfies ExecutorMethodArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
providedCweb: cwebPerCall - 700n,
|
||||
providedCweb: cwebPerCall,
|
||||
authenticated: null,
|
||||
},
|
||||
contractArgs: [],
|
||||
@ -102,12 +111,45 @@ export const prepareInThreadTxs = ({
|
||||
});
|
||||
|
||||
callsPrepared++;
|
||||
} else {
|
||||
callArgs.push(task.op);
|
||||
txFee += 700n;
|
||||
|
||||
break;
|
||||
}
|
||||
case isPreparedStoreOp(op):
|
||||
case isPreparedTakeOp(op): {
|
||||
preparedExecOps.push(op);
|
||||
excOpsIndexes.push(i);
|
||||
break;
|
||||
}
|
||||
case isPreparedLockOp(op): {
|
||||
const { callInfo, fee, ops } = constructLockCall(context.issuer, op.LockOp.lockId);
|
||||
|
||||
childCalls.push({ callInfo });
|
||||
callArgs.push(...ops);
|
||||
txFee += fee;
|
||||
|
||||
break;
|
||||
}
|
||||
case isPreparedUnlockOp(op): {
|
||||
const { callInfo, fee, ops } = constructUnlockCall(
|
||||
context.issuer,
|
||||
op.UnlockOp.lockId,
|
||||
op.UnlockOp.timestamp,
|
||||
false
|
||||
);
|
||||
|
||||
childCalls.push({ callInfo });
|
||||
callArgs.push(...ops);
|
||||
txFee += fee;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
callArgs.push(op);
|
||||
txFee += 100n;
|
||||
}
|
||||
|
||||
resolvedChildOps.push({ SlotOp: 0 });
|
||||
resolvedChildOps.push({ SlotOp: { ok: true } });
|
||||
});
|
||||
|
||||
const returnTxs: NewTx[] = [];
|
||||
@ -168,6 +210,7 @@ export const prepareInThreadTxs = ({
|
||||
context.parentId,
|
||||
context.needSaveResult,
|
||||
takeOps.map((op) => (op.TakeOp.key.second_part as [string])[0]),
|
||||
excOpsIndexes,
|
||||
] satisfies ExecutorMethodArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
@ -182,10 +225,26 @@ export const prepareInThreadTxs = ({
|
||||
);
|
||||
|
||||
if (childCalls.length) {
|
||||
returnTxs.push(constructContinueTx(getRawContext(), childBlocks, childCalls));
|
||||
returnTxs.push(constructContinueTx(getRawContext(), [], childCalls));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { txs: returnTxs, calls: callsPrepared };
|
||||
if (preparedExecOps.length > 0) {
|
||||
const execId = uuid();
|
||||
|
||||
const { callInfo, fee, ops } = constructExecOpsCall({
|
||||
issuer: context.issuer,
|
||||
ops: preparedExecOps,
|
||||
processId: context.thisId,
|
||||
execId,
|
||||
});
|
||||
|
||||
childCalls.push({ callInfo });
|
||||
txFee += fee;
|
||||
|
||||
callArgs.push(...ops);
|
||||
}
|
||||
|
||||
return { txs: returnTxs, calls: callsPrepared, txFee };
|
||||
};
|
||||
|
||||
@ -2,42 +2,50 @@ import {
|
||||
constructContinueTx,
|
||||
constructContractRef,
|
||||
FullCallInfo,
|
||||
GTake,
|
||||
NewTx,
|
||||
PreparedOperation,
|
||||
} from '@coinweb/contract-kit';
|
||||
import { CwebTake } from '@coinweb/contract-kit/dist/types/operations/take';
|
||||
|
||||
import { ExecutorMethodArgs, Task } from '../../../types';
|
||||
import { ExecutorMethodArgs, PreparedExtendedStoreOp, PreparedOp } from '../../../types';
|
||||
import { context, getRawContext } from '../../context';
|
||||
import { isPreparedExecOp } from '../typeGuards';
|
||||
import { constructLockCall, constructExecOpsCall, constructUnlockCall } from '../../mutex';
|
||||
import {
|
||||
isPreparedBlockOp,
|
||||
isPreparedExecOp,
|
||||
isPreparedLockOp,
|
||||
isPreparedStoreOp,
|
||||
isPreparedTakeOp,
|
||||
isPreparedUnlockOp,
|
||||
} from '../typeGuards';
|
||||
|
||||
export const prepareOutThreadTxs = ({
|
||||
tasks,
|
||||
ops,
|
||||
cwebPerCall,
|
||||
}: {
|
||||
tasks: Task[];
|
||||
ops: PreparedOp[];
|
||||
cwebPerCall: bigint;
|
||||
}): {
|
||||
txs: NewTx[];
|
||||
fee: bigint;
|
||||
txFee: bigint;
|
||||
calls: number;
|
||||
} => {
|
||||
const siblingCallResolvedOps = [...context.ops];
|
||||
|
||||
const siblingTxInfo: {
|
||||
[batchId: number]: {
|
||||
calls: FullCallInfo[];
|
||||
ops: PreparedOperation[];
|
||||
};
|
||||
} = {};
|
||||
const preparedCalls: FullCallInfo[] = [];
|
||||
const preparedOps: PreparedOperation[] = [];
|
||||
const preparedStoreAndTakes: (PreparedExtendedStoreOp | GTake<CwebTake>)[] = [];
|
||||
|
||||
let txFee = 0n;
|
||||
let callsPrepared = 0;
|
||||
|
||||
tasks.forEach((task) => {
|
||||
if (isPreparedExecOp(task.op)) {
|
||||
ops.forEach((op) => {
|
||||
switch (true) {
|
||||
case isPreparedExecOp(op): {
|
||||
console.log('Sibling call info');
|
||||
|
||||
const id = task.op.ExecOp.id;
|
||||
const id = op.ExecOp.id;
|
||||
|
||||
const callInfo = {
|
||||
callInfo: {
|
||||
@ -54,44 +62,65 @@ export const prepareOutThreadTxs = ({
|
||||
] satisfies ExecutorMethodArgs,
|
||||
},
|
||||
contractInfo: {
|
||||
providedCweb: cwebPerCall - 700n,
|
||||
providedCweb: cwebPerCall,
|
||||
authenticated: null,
|
||||
},
|
||||
contractArgs: [],
|
||||
},
|
||||
};
|
||||
|
||||
if (siblingTxInfo[task.batchId]) {
|
||||
siblingTxInfo[task.batchId].calls.push(callInfo);
|
||||
} else {
|
||||
siblingTxInfo[task.batchId] = {
|
||||
calls: [callInfo],
|
||||
ops: [],
|
||||
};
|
||||
}
|
||||
preparedCalls.push(callInfo);
|
||||
txFee += 700n;
|
||||
|
||||
callsPrepared++;
|
||||
} else {
|
||||
if (siblingTxInfo[task.batchId]) {
|
||||
siblingTxInfo[task.batchId].ops.push(task.op);
|
||||
} else {
|
||||
siblingTxInfo[task.batchId] = {
|
||||
calls: [],
|
||||
ops: [task.op],
|
||||
};
|
||||
break;
|
||||
}
|
||||
case isPreparedStoreOp(op):
|
||||
case isPreparedTakeOp(op): {
|
||||
preparedStoreAndTakes.push(op);
|
||||
break;
|
||||
}
|
||||
case isPreparedLockOp(op): {
|
||||
const { callInfo, fee } = constructLockCall(context.issuer, op.LockOp.lockId);
|
||||
|
||||
preparedCalls.push({ callInfo });
|
||||
txFee += fee;
|
||||
|
||||
break;
|
||||
}
|
||||
case isPreparedUnlockOp(op): {
|
||||
const { callInfo, fee } = constructUnlockCall(context.issuer, op.UnlockOp.lockId, op.UnlockOp.timestamp, false);
|
||||
|
||||
preparedCalls.push({ callInfo });
|
||||
txFee += fee;
|
||||
|
||||
break;
|
||||
}
|
||||
case isPreparedBlockOp(op): {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
preparedOps.push(op);
|
||||
txFee += 100n;
|
||||
}
|
||||
|
||||
siblingCallResolvedOps.push({ SlotOp: 0 });
|
||||
siblingCallResolvedOps.push({ SlotOp: { ok: true } });
|
||||
});
|
||||
|
||||
const siblingTxs = Object.values(siblingTxInfo).map(({ calls, ops }) =>
|
||||
constructContinueTx(getRawContext(), ops, calls)
|
||||
);
|
||||
if (preparedStoreAndTakes.length > 0) {
|
||||
const { callInfo, fee } = constructExecOpsCall({
|
||||
issuer: context.issuer,
|
||||
ops: preparedStoreAndTakes,
|
||||
processId: context.thisId,
|
||||
});
|
||||
|
||||
txFee += BigInt(siblingTxs.length) * 100n;
|
||||
preparedCalls.push({ callInfo });
|
||||
txFee += fee;
|
||||
}
|
||||
|
||||
return { txs: siblingTxs, fee: txFee, calls: callsPrepared };
|
||||
return {
|
||||
txs: [constructContinueTx(getRawContext(), preparedOps, preparedCalls)],
|
||||
txFee,
|
||||
calls: callsPrepared,
|
||||
};
|
||||
};
|
||||
|
||||
@ -7,7 +7,11 @@ import { prepareInThreadTxs } from './prepareInThreadTxs';
|
||||
import { prepareOutThreadTxs } from './prepareOutThreadTxs';
|
||||
import { splitTasks } from './splitTasks';
|
||||
|
||||
export const prepareTx = (isFullyExecuted: boolean, callsCount?: number): { txs: NewTx[]; calls: number } => {
|
||||
export const prepareTx = (
|
||||
isFullyExecuted: boolean,
|
||||
txFee: bigint,
|
||||
callsCount?: number
|
||||
): { txs: NewTx[]; calls: number; txFee: bigint } => {
|
||||
console.log('Calls Count: ', callsCount);
|
||||
|
||||
const awaitedTasks = getAwaitedTasks();
|
||||
@ -16,14 +20,15 @@ export const prepareTx = (isFullyExecuted: boolean, callsCount?: number): { txs:
|
||||
|
||||
if (!awaitedTasks.length) {
|
||||
if (context.isChild) {
|
||||
return { txs: [], calls: 0 };
|
||||
return { txs: [], calls: 0, txFee: 0n };
|
||||
}
|
||||
|
||||
const { constructSendCweb } = sendCwebInterface();
|
||||
const { availableCweb, takeOps, storedCweb } = context.funds;
|
||||
const { user } = context;
|
||||
|
||||
const restOfCweb = availableCweb + storedCweb - BigInt(takeOps.length) * 100n - 3000n;
|
||||
const fee = BigInt(takeOps.length) * 100n - 3000n;
|
||||
const restOfCweb = availableCweb + storedCweb - fee;
|
||||
|
||||
const txs =
|
||||
restOfCweb > 0n
|
||||
@ -36,26 +41,35 @@ export const prepareTx = (isFullyExecuted: boolean, callsCount?: number): { txs:
|
||||
]
|
||||
: [];
|
||||
|
||||
return { txs, calls: 0 };
|
||||
return { txs, calls: 0, txFee: fee };
|
||||
}
|
||||
|
||||
const { inThreadTasks, outThreadTasks } = splitTasks(awaitedTasks, isFullyExecuted);
|
||||
const { inThreadOps, outThreadOps } = splitTasks(awaitedTasks, isFullyExecuted);
|
||||
|
||||
const { availableCweb } = context.funds;
|
||||
|
||||
const cwebPerCall = availableCweb / BigInt(callsCount || 1);
|
||||
const cwebPerCall = (availableCweb - txFee) / BigInt(callsCount || 1);
|
||||
|
||||
const {
|
||||
txs: outThreadTxs,
|
||||
fee: outThreadFee,
|
||||
calls: outThreadCallsPrepared,
|
||||
} = prepareOutThreadTxs({ tasks: outThreadTasks, cwebPerCall });
|
||||
txFee: outThreadFee,
|
||||
} = prepareOutThreadTxs({ ops: outThreadOps, cwebPerCall });
|
||||
|
||||
const { txs: inThreadTxs, calls: inThreadCallsPrepared } = prepareInThreadTxs({
|
||||
tasks: inThreadTasks,
|
||||
const {
|
||||
txs: inThreadTxs,
|
||||
calls: inThreadCallsPrepared,
|
||||
txFee: inThreadFee,
|
||||
} = prepareInThreadTxs({
|
||||
ops: inThreadOps,
|
||||
cwebPerCall,
|
||||
outThreadTasksCount: outThreadTasks.length,
|
||||
outThreadTasksCount: outThreadOps.length,
|
||||
outThreadFee,
|
||||
});
|
||||
|
||||
return { txs: [...inThreadTxs, ...outThreadTxs], calls: inThreadCallsPrepared + outThreadCallsPrepared };
|
||||
return {
|
||||
txs: [...inThreadTxs, ...outThreadTxs],
|
||||
calls: inThreadCallsPrepared + outThreadCallsPrepared,
|
||||
txFee: inThreadFee + outThreadFee,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,48 +1,26 @@
|
||||
import { Task } from '../../../types';
|
||||
import { isPreparedBlockOp } from '../typeGuards';
|
||||
import { PreparedOp, Task } from '../../../types';
|
||||
|
||||
export const splitTasks = (awaitedTasks: Task[], isFullyExecuted: boolean) => {
|
||||
const awaitedTasksBatched: (Task | Task[])[] = [];
|
||||
const preparedTasks: (Task | Task[])[] = [];
|
||||
|
||||
awaitedTasks.forEach((task) => {
|
||||
if (task.batchId === -1) {
|
||||
awaitedTasksBatched.push(task);
|
||||
return;
|
||||
if (awaitedTasks.length === 0) {
|
||||
return { inThreadOps: [], outThreadOps: [] };
|
||||
}
|
||||
|
||||
const latestTask = awaitedTasksBatched.at(-1);
|
||||
|
||||
if (Array.isArray(latestTask) && latestTask.at(-1)?.batchId === task.batchId) {
|
||||
latestTask.push(task);
|
||||
return;
|
||||
}
|
||||
|
||||
awaitedTasksBatched.push([task]);
|
||||
});
|
||||
|
||||
awaitedTasksBatched.forEach((task, i) => {
|
||||
if (
|
||||
i === awaitedTasksBatched.length - 1 ||
|
||||
!Array.isArray(task) ||
|
||||
(task.length > 1 && task.some(({ op }) => isPreparedBlockOp(op)))
|
||||
) {
|
||||
preparedTasks.push(task);
|
||||
} else {
|
||||
preparedTasks.push(...task.map((task) => ({ ...task, batchId: -1 })));
|
||||
}
|
||||
});
|
||||
|
||||
let inThreadTasks: Task[] = [];
|
||||
let outThreadTasks: Task[] = [];
|
||||
const inThreadOps: PreparedOp[] = [];
|
||||
let outThreadOps: PreparedOp[] = [];
|
||||
|
||||
if (!isFullyExecuted) {
|
||||
const preparedCallTasks = preparedTasks.at(-1)!;
|
||||
inThreadTasks = [...(Array.isArray(preparedCallTasks) ? preparedCallTasks : [preparedCallTasks])];
|
||||
outThreadTasks = preparedTasks.slice(0, -1).flat();
|
||||
const latestTaskBatchId = awaitedTasks.at(-1)!.batchId ?? -1;
|
||||
|
||||
awaitedTasks.forEach((task) => {
|
||||
if (task.batchId === latestTaskBatchId) {
|
||||
inThreadOps.push(task.op);
|
||||
} else {
|
||||
outThreadTasks = preparedTasks.flat();
|
||||
outThreadOps.push(task.op);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
outThreadOps = awaitedTasks.map((task) => task.op);
|
||||
}
|
||||
|
||||
return { inThreadTasks, outThreadTasks };
|
||||
return { inThreadOps, outThreadOps };
|
||||
};
|
||||
|
||||
@ -12,10 +12,14 @@ import { CwebBlock } from '@coinweb/contract-kit/dist/esm/operations/block';
|
||||
import { CwebCallRefResolved, isResolvedCall } from '@coinweb/contract-kit/dist/esm/operations/call';
|
||||
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 { CwebTake } from '@coinweb/contract-kit/dist/types/operations/take';
|
||||
|
||||
import {
|
||||
PreparedExecOp,
|
||||
PreparedExtendedStoreOp,
|
||||
PreparedLockOp,
|
||||
PreparedOp,
|
||||
PreparedUnlockOp,
|
||||
ResolvedChildOp,
|
||||
ResolvedExecOp,
|
||||
ResolvedLockOp,
|
||||
@ -119,3 +123,43 @@ export const isPreparedBlockOp = (op?: PreparedOp | null): op is GBlock<CwebBloc
|
||||
|
||||
return !!(op && 'BlockOp' in op);
|
||||
};
|
||||
|
||||
export const isPreparedLockOp = (op?: PreparedOp | null): op is PreparedLockOp => {
|
||||
if (op && 'LockOp' in op) {
|
||||
console.log('isPreparedLockOp >>> ', JSON.stringify(op));
|
||||
}
|
||||
|
||||
return !!(op && 'LockOp' in op);
|
||||
};
|
||||
|
||||
export const isPreparedUnlockOp = (op?: PreparedOp | null): op is PreparedUnlockOp => {
|
||||
if (op && 'UnlockOp' in op) {
|
||||
console.log('isPreparedUnlockOp >>> ', JSON.stringify(op));
|
||||
}
|
||||
|
||||
return !!(op && 'UnlockOp' in op);
|
||||
};
|
||||
|
||||
export const isPreparedStoreOp = (op?: PreparedOp | null): op is GStore<CwebStore> => {
|
||||
if (op && 'StoreOp' in op) {
|
||||
console.log('isPreparedStoreOp >>> ', JSON.stringify(op));
|
||||
}
|
||||
|
||||
return !!(op && 'StoreOp' in op);
|
||||
};
|
||||
|
||||
export const isPreparedExtendedStoreOp = (op?: PreparedOp | null): op is PreparedExtendedStoreOp => {
|
||||
if (op && 'StoreOp' in op) {
|
||||
console.log('isPreparedExtendedStoreOp >>> ', JSON.stringify(op));
|
||||
}
|
||||
|
||||
return !!(op && 'StoreOp' in op);
|
||||
};
|
||||
|
||||
export const isPreparedTakeOp = (op?: PreparedOp | null): op is GTake<CwebTake> => {
|
||||
if (op && 'TakeOp' in op) {
|
||||
console.log('isPreparedTakeOp >>> ', JSON.stringify(op));
|
||||
}
|
||||
|
||||
return !!(op && 'TakeOp' in op);
|
||||
};
|
||||
|
||||
@ -1,4 +1,13 @@
|
||||
import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation, User } from '@coinweb/contract-kit';
|
||||
import {
|
||||
Claim,
|
||||
ClaimKey,
|
||||
CwebStore,
|
||||
GStore,
|
||||
OrdJson,
|
||||
PreparedOperation,
|
||||
ResolvedOperation,
|
||||
User,
|
||||
} from '@coinweb/contract-kit';
|
||||
|
||||
import { LockedKey } from './onchain/mutex';
|
||||
|
||||
@ -11,7 +20,14 @@ export type TypedClaim<TBody extends OrdJson = OrdJson, TKey extends ClaimKey =
|
||||
};
|
||||
|
||||
export type ResolvedSlotOp = {
|
||||
SlotOp: 0;
|
||||
SlotOp:
|
||||
| {
|
||||
ok: false;
|
||||
error: string;
|
||||
}
|
||||
| {
|
||||
ok: true;
|
||||
};
|
||||
};
|
||||
|
||||
export type ResolvedExecOp = {
|
||||
@ -27,6 +43,7 @@ export type ResolvedChildOp = {
|
||||
export type ResolvedLockOp = {
|
||||
LockOp: {
|
||||
lockId: string;
|
||||
timestamp: number;
|
||||
};
|
||||
};
|
||||
|
||||
@ -52,16 +69,25 @@ export type PreparedLockOp = {
|
||||
LockOp: {
|
||||
lockId: string;
|
||||
keys: LockedKey[];
|
||||
timestamp: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type PreparedUnlockOp = {
|
||||
UnlockOp: {
|
||||
lockId: string;
|
||||
timestamp: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type PreparedOp = PreparedOperation | PreparedExecOp | PreparedLockOp | PreparedUnlockOp;
|
||||
export type PreparedExtendedStoreOp = GStore<CwebStore> & { providedCweb?: bigint };
|
||||
|
||||
export type PreparedOp =
|
||||
| PreparedOperation
|
||||
| PreparedExecOp
|
||||
| PreparedLockOp
|
||||
| PreparedUnlockOp
|
||||
| PreparedExtendedStoreOp;
|
||||
|
||||
export type Task = {
|
||||
op: PreparedOp;
|
||||
@ -76,4 +102,5 @@ export type ExecutorMethodArgs = [
|
||||
parentId?: string,
|
||||
saveResult?: boolean,
|
||||
takenFundsIds?: string[],
|
||||
execOpsIndexes?: number[],
|
||||
];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user