diff --git a/package-lock.json b/package-lock.json index e90b972..c7038f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@dataswapcore/contracts": "^0.9.2", + "@dataswapcore/contracts": "^0.9.5", "@glif/filecoin-address": "^2.0.43", "@unipackage/datastore": "^2.0.0", "@unipackage/filecoin": "^2.3.0", @@ -417,13 +417,14 @@ "integrity": "sha512-9Cxtizc2J8mUUCoupqSsOeMle6Ey19XnSDXvO//WVeUy/TP6mNZ2TWkQ6ycI5yeOWxPv5KhIvENj1JPMF1xztw==" }, "node_modules/@dataswapcore/contracts": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@dataswapcore/contracts/-/contracts-0.9.2.tgz", - "integrity": "sha512-wSmELs+/dAGNU8Vg158MAupYS+kj0bn2Bb+bn6EV2/urfiqU0Yrn57g4pPMu7sD9fjQpI2PvOCJMEGUZPxaREQ==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@dataswapcore/contracts/-/contracts-0.9.5.tgz", + "integrity": "sha512-v26LFE+xgKzp2AOUmfXsuoUTq/DpNjO2+19nYBIcoihaysbz6MkHwUMamm8cKU4AcIOUp1ZJAfB+aajrQrt5FQ==", "dependencies": { "@openzeppelin/contracts": "^4.9.3", "@openzeppelin/contracts-upgradeable": "^4.9.3", "@release-it/conventional-changelog": "^8.0.1", + "filecoin-solidity-api": "^1.1.2", "git-cz": "^4.9.0", "global": "^4.4.0", "hardhat-abi-exporter": "2.10.1", @@ -8616,6 +8617,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/filecoin-solidity-api": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/filecoin-solidity-api/-/filecoin-solidity-api-1.1.2.tgz", + "integrity": "sha512-0HeCZnRaHQosbz2khbj4mjB9d5U0V4vNf0TJW/gE9JFiR20HaDYEcYv7chA7cEY5alb0eKDx0OUWGxX/qL0wNg==", + "dependencies": { + "solidity-cborutils": "^2.0.0" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", diff --git a/package.json b/package.json index 053e09b..3e7f2e9 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "homepage": "https://github.com/dataswap/dataswapjs#readme", "dependencies": { - "@dataswapcore/contracts": "^0.9.2", + "@dataswapcore/contracts": "^0.9.5", "@glif/filecoin-address": "^2.0.43", "@unipackage/datastore": "^2.0.0", "@unipackage/filecoin": "^2.3.0", diff --git a/src/core/carstore/repo/evm/index.ts b/src/core/carstore/repo/evm/index.ts index e2b55df..e4bb44b 100644 --- a/src/core/carstore/repo/evm/index.ts +++ b/src/core/carstore/repo/evm/index.ts @@ -49,6 +49,20 @@ interface CarstoreCallEvm { */ getCarsSize(carIds: bigint[]): Promise> + /** + * Retrieves the piece size for a given car ID. + * @param carId The ID of the car. + * @returns A promise that resolves to the piece size of the car. + */ + getPieceSize(carId: bigint): Promise> + + /** + * Retrieves the total piece size for an array of car IDs. + * @param carIds An array containing the IDs of cars. + * @returns A promise that resolves to the total piece size of the cars. + */ + + getPiecesSize(carIds: bigint[]): Promise> /** * @notice Get the dataset ID associated with a car. * @param carId Car ID to check. diff --git a/src/core/filplus/repo/evm/index.ts b/src/core/filplus/repo/evm/index.ts index 098e0db..cfa26dd 100644 --- a/src/core/filplus/repo/evm/index.ts +++ b/src/core/filplus/repo/evm/index.ts @@ -116,13 +116,10 @@ interface FilplusCallEvm { financeRuleChallengeProofsPricePrePoint(): Promise> /** - * Retrieves the count of challenge proofs submitter. - * - * @returns A promise with the EVM output containing the count of challenge proofs submitter. + * Retrieves the challenge points per auditor for dataset rules. + * @returns A promise that resolves to the challenge points per auditor. */ - datasetRuleMaxChallengeProofsSubmitersPerDataset(): Promise< - EvmOutput - > + datasetRuleChallengePointsPerAuditor(): Promise> /** * Retrieves the price per byte for datacap chunks of land. @@ -358,12 +355,11 @@ interface FilplusSendEvm { ): Promise> /** - * Sets the count of challenge proofs submitter. - * - * @param newValue - The new value for the count of challenge proofs submitter. - * @returns A promise with the EVM output indicating the success of the operation. + * Sets the challenge points per auditor for dataset rules. + * @param newValue The new value for the challenge points per auditor. + * @returns A promise that resolves to void. */ - setDatasetRuleMaxChallengeProofsSubmitersPerDataset( + setDatasetRuleChallengePointsPerAuditor( newValue: number ): Promise> @@ -565,7 +561,7 @@ export interface FilplusOriginEvm extends FilplusCallEvm, FilplusSendEvm {} "finaceRuleDatasetProofCollateral", "financeRuleDisputeAuditCollateral", "financeRuleChallengeProofsPricePrePoint", - "datasetRuleMaxChallengeProofsSubmitersPerDataset", + "datasetRuleChallengePointsPerAuditor", "financeRuleDatacapChunkLandPricePreByte", "financeRuleDatacapPricePreByte", "datasetRuleMinProofTimeout", @@ -595,7 +591,7 @@ export interface FilplusOriginEvm extends FilplusCallEvm, FilplusSendEvm {} "setEscrowReleaseRule", "setFinanceRuleDatacapPricePreByte", "setFinanceRuleDatacapChunkLandPricePreByte", - "setDatasetRuleMaxChallengeProofsSubmitersPerDataset", + "setDatasetRuleChallengePointsPerAuditor", "setFinanceRuleDatacapDatasetApprovedLockDays", "setFinanceRuleDatacapCollateralMaxLockDays", "setDatasetRuleAuditorsElectionTime", @@ -644,7 +640,7 @@ export class FilplusEvm extends FilplusOriginEvm { case "setEscrowReleaseRule": case "setFinanceRuleDatacapPricePreByte": case "setFinanceRuleDatacapChunkLandPricePreByte": - case "setDatasetRuleMaxChallengeProofsSubmitersPerDataset": + case "setDatasetRuleChallengePointsPerAuditor": case "setFinanceRuleDatacapDatasetApprovedLockDays": case "setFinanceRuleDatacapCollateralMaxLockDays": case "setDatasetRuleAuditorsElectionTime": diff --git a/src/module/dataset/challenge/repo/evm/index.ts b/src/module/dataset/challenge/repo/evm/index.ts index 18b8f2b..c9a89f4 100644 --- a/src/module/dataset/challenge/repo/evm/index.ts +++ b/src/module/dataset/challenge/repo/evm/index.ts @@ -57,22 +57,31 @@ interface DatasetChallengeCallEvm { ): Promise> /** - * Get the count of proofs for a dataset challenge. - * - * @param datasetId - ID of the dataset. - * @returns EvmOutput containing the number of proofs. + * Retrieves the number of auditors who have submitted challenges for a given dataset ID. + * @param datasetId The ID of the dataset. + * @returns A promise that resolves to the number of auditors who have submitted challenges. */ - getDatasetChallengeProofsCount( + getChallengeAuditorsCountSubmitted( datasetId: number - ): Promise> + ): Promise> /** - * Get the count of challenges for a dataset. - * - * @param datasetId - ID of the dataset. - * @returns EvmOutput containing the number of challenges. + * Retrieves the required number of auditors for challenging a given dataset ID. + * @param datasetId The ID of the dataset. + * @returns A promise that resolves to the required number of auditors for challenging. */ - getChallengeSubmissionCount(datasetId: number): Promise> + getChallengeAuditorsCountRequirement( + datasetId: number + ): Promise> + + /** + * Retrieves the required number of challenge points for a given dataset ID. + * @param datasetId The ID of the dataset. + * @returns A promise that resolves to the required number of challenge points. + */ + getChallengePointsCountRequirement( + datasetId: number + ): Promise> /** * @dev Retrieves the auditor candidates for a specific dataset. @@ -171,8 +180,9 @@ export interface DatasetChallengeOriginEvm @withCallMethod([ "getDatasetChallengeProofsSubmitters", "getDatasetChallengeProofs", - "getDatasetChallengeProofsCount", - "getChallengeSubmissionCount", + "getChallengeAuditorsCountSubmitted", + "getChallengeAuditorsCountRequirement", + "getChallengePointsCountRequirement", "getDatasetAuditorCandidates", "getAuditorElectionEndHeight", "isWinner", diff --git a/src/module/dataset/metadata/repo/datastore/index.ts b/src/module/dataset/metadata/repo/datastore/index.ts index cee7f85..c746d5f 100644 --- a/src/module/dataset/metadata/repo/datastore/index.ts +++ b/src/module/dataset/metadata/repo/datastore/index.ts @@ -198,7 +198,7 @@ export class DatasetMetadataMongoDatastore extends DataStore< } const challengeCount = - await options.datasetChallengeEvm.getChallengeSubmissionCount( + await options.datasetChallengeEvm.getChallengePointsCountRequirement( options.datasetId ) if (!challengeCount.ok) { diff --git a/src/module/dataset/proof/repo/evm/index.ts b/src/module/dataset/proof/repo/evm/index.ts index 9a2bbc9..19c82aa 100644 --- a/src/module/dataset/proof/repo/evm/index.ts +++ b/src/module/dataset/proof/repo/evm/index.ts @@ -81,6 +81,17 @@ interface DatasetProofCallEvm { dataType: DataType ): Promise> + /** + * Retrieves the unpadded size of the dataset for a given dataset ID and data type. + * @param datasetId The ID of the dataset. + * @param dataType The data type for which to retrieve the unpadded size. + * @returns A promise that resolves to the unpadded size of the dataset. + */ + getDatasetUnpadSize( + datasetId: number, + dataType: DataType + ): Promise> + /** * Retrieves the complete height of the dataset proof. * @param datasetId The ID of the dataset. @@ -259,6 +270,7 @@ export interface DatasetProofOriginEvm "getDatasetProofCount", "getDatasetProofSubmitter", "getDatasetSize", + "getDatasetUnpadSize", "getDatasetProofCompleteHeight", "getDatasetProofRootHash", "isDatasetProofallCompleted", diff --git a/test/assertions/core/filplusAssertion.ts b/test/assertions/core/filplusAssertion.ts index cb54564..bcd7204 100644 --- a/test/assertions/core/filplusAssertion.ts +++ b/test/assertions/core/filplusAssertion.ts @@ -191,16 +191,15 @@ export class FilplusAssertion implements IFilplusAssertion { } /** - * Asserts that the challenge proofs submitter count matches the expected count. - * - * @param exceptCount - The expected challenge proofs submitter count. - * @returns A promise indicating whether the assertion passed or not. + * Asserts the dataset rule challenge points per auditor. + * @param exceptCount The expected count of dataset rule challenge points per auditor. + * @returns A promise that resolves to void. */ - async getChallengeProofsSubmiterCountAssertion( + async datasetRuleChallengePointsPerAuditorAssertion( exceptCount: number ): Promise { let count = await handleEvmError( - this.filplus.datasetRuleMaxChallengeProofsSubmitersPerDataset() + this.filplus.datasetRuleChallengePointsPerAuditor() ) assert.isTrue(equal(exceptCount, count), "count should be expect") } @@ -738,20 +737,17 @@ export class FilplusAssertion implements IFilplusAssertion { } /** - * Sets the count of challenge proofs submitter. - * - * @param newValue - The new value for the challenge proofs submitter count. - * @returns A promise indicating the success of the operation. + * Sets the dataset rule challenge points per auditor assertion. + * @param newValue The new value for the dataset rule challenge points per auditor. + * @returns A promise that resolves to void. */ - async setChallengeProofsSubmiterCountAssertion( + async setDatasetRuleChallengePointsPerAuditorAssertion( newValue: number ): Promise { await handleEvmError( - this.filplus.setDatasetRuleMaxChallengeProofsSubmitersPerDataset( - newValue - ) + this.filplus.setDatasetRuleChallengePointsPerAuditor(newValue) ) - this.getChallengeProofsSubmiterCountAssertion(newValue) + this.datasetRuleChallengePointsPerAuditorAssertion(newValue) } /** diff --git a/test/assertions/module/datasetsAssertion.ts b/test/assertions/module/datasetsAssertion.ts index 696e7d9..60bc60b 100644 --- a/test/assertions/module/datasetsAssertion.ts +++ b/test/assertions/module/datasetsAssertion.ts @@ -742,7 +742,12 @@ export class DatasetsAssertion implements IDatasetsAssertion { dataType, Number(proofCount) + expectLeafHashes.length ) - const sum = expectLeafSizes.reduce((acc, curr) => acc + curr, 0) + + let sum: number = 0 + for (let i = 0; i < expectLeafSizes.length; i++) { + sum += utils.carSizeToPieceSize(expectLeafSizes[i]) + } + //const sum = expectLeafSizes.reduce((acc, curr) => acc + curr, 0) await this.getDatasetSizeAssertion( datasetId, dataType, @@ -837,14 +842,14 @@ export class DatasetsAssertion implements IDatasetsAssertion { * @param expectCount - The expected count of challenge proofs. * @returns A Promise resolving if the assertion is successful. */ - async getDatasetChallengeProofsCountAssertion( + async getChallengeAuditorsCountSubmittedAssertion( datasetId: number, - expectCount: number + expectCount: bigint ): Promise { const challengeProofsCount = await handleEvmError( this.contractsManager .DatasetChallengeEvm() - .getDatasetChallengeProofsCount(datasetId) + .getChallengeAuditorsCountSubmitted(datasetId) ) expect(expectCount).to.be.equal(Number(challengeProofsCount)) } @@ -855,18 +860,35 @@ export class DatasetsAssertion implements IDatasetsAssertion { * @param expectCount - The expected count of challenge submissions. * @returns A Promise resolving if the assertion is successful. */ - async getChallengeSubmissionCountAssertion( + async getChallengePointsCountRequirementAssertion( datasetId: number, - expectCount: number + expectCount: bigint ): Promise { const challengeSubmissionCount = await handleEvmError( this.contractsManager .DatasetChallengeEvm() - .getChallengeSubmissionCount(datasetId) + .getChallengePointsCountRequirement(datasetId) ) - expect(expectCount).to.be.equal(Number(challengeSubmissionCount)) + expect(expectCount).to.be.equal(challengeSubmissionCount) } + /** + * Asserts the required number of auditors for challenging a dataset. + * @param datasetId The ID of the dataset. + * @param expectCount The expected number of auditors required for challenging. + * @returns A promise that resolves to void. + */ + async getChallengeAuditorsCountRequirementAssertion( + datasetId: number, + expectCount: bigint + ): Promise { + const challengeSubmissionCount = await handleEvmError( + this.contractsManager + .DatasetChallengeEvm() + .getChallengeAuditorsCountRequirement(datasetId) + ) + expect(expectCount).to.be.equal(Number(challengeSubmissionCount)) + } /** * Asserts whether a dataset's challenge proof is duplicate based on the provided parameters. * @param datasetId - The ID of the dataset. @@ -978,7 +1000,7 @@ export class DatasetsAssertion implements IDatasetsAssertion { const count = await handleEvmError( this.contractsManager .DatasetChallengeEvm() - .getDatasetChallengeProofsCount(datasetId) + .getChallengeAuditorsCountSubmitted(datasetId) ) this.contractsManager .DatasetChallengeEvm() @@ -1010,9 +1032,9 @@ export class DatasetsAssertion implements IDatasetsAssertion { ) await this.getDatasetStateAssertion(datasetId, DatasetState.Approved) - await this.getDatasetChallengeProofsCountAssertion( + await this.getChallengeAuditorsCountSubmittedAssertion( datasetId, - Number(count) + 1 + count + BigInt(1) ) await this.isDatasetChallengeProofDuplicateAssertion( @@ -1022,20 +1044,31 @@ export class DatasetsAssertion implements IDatasetsAssertion { true ) - let expectSubmissionCount: number - const carsCount = await handleEvmError( + let pointsRequirement: bigint + const unpadSize = await handleEvmError( this.contractsManager .DatasetProofEvm() - .getDatasetProofCount(datasetId, DataType.Source) + .getDatasetUnpadSize(datasetId, DataType.Source) ) - if (Number(carsCount) < 1000) { - expectSubmissionCount = 1 - } else { - expectSubmissionCount = carsCount / 1000 + 1 - } - await this.getChallengeSubmissionCountAssertion( + const smallDataSet = BigInt(1099511627776) //1 point per 1TB + const securePoints = + (unpadSize + smallDataSet - BigInt(1)) / smallDataSet + const pointsPerAuditor = await handleEvmError( + this.contractsManager + .FilplusEvm() + .datasetRuleChallengePointsPerAuditor() + ) + const auditorsRequirement = + (securePoints + pointsPerAuditor - BigInt(1)) / pointsPerAuditor + + pointsRequirement = auditorsRequirement * pointsPerAuditor + await this.getChallengePointsCountRequirementAssertion( + datasetId, + pointsRequirement + ) + await this.getChallengeAuditorsCountRequirementAssertion( datasetId, - expectSubmissionCount + auditorsRequirement ) } } diff --git a/test/interfaces/assertions/core/IFilplusAssertion.ts b/test/interfaces/assertions/core/IFilplusAssertion.ts index 7a18199..ef8b729 100644 --- a/test/interfaces/assertions/core/IFilplusAssertion.ts +++ b/test/interfaces/assertions/core/IFilplusAssertion.ts @@ -120,13 +120,13 @@ export interface IFilplusAssertion { getChallengeProofsPricePrePointAssertion(exceptPrice: bigint): Promise /** - * Asserts that the challenge proofs submitter count matches the expected count. - * - * @param exceptCount - The expected challenge proofs submitter count. - * @returns A promise indicating whether the assertion passed or not. + * Asserts the dataset rule challenge points per auditor. + * @param exceptCount The expected count of dataset rule challenge points per auditor. + * @returns A promise that resolves to void. */ - getChallengeProofsSubmiterCountAssertion(exceptCount: number): Promise - + datasetRuleChallengePointsPerAuditorAssertion( + exceptCount: number + ): Promise /** * Asserts that the datacap chunk land price per byte matches the expected price. * @@ -381,12 +381,13 @@ export interface IFilplusAssertion { setDatacapChunkLandPricePreByteAssertion(newValue: bigint): Promise /** - * Sets the count of challenge proofs submitter. - * - * @param newValue - The new value for the challenge proofs submitter count. - * @returns A promise indicating the success of the operation. + * Sets the dataset rule challenge points per auditor assertion. + * @param newValue The new value for the dataset rule challenge points per auditor. + * @returns A promise that resolves to void. */ - setChallengeProofsSubmiterCountAssertion(newValue: number): Promise + setDatasetRuleChallengePointsPerAuditorAssertion( + newValue: number + ): Promise /** * Sets the lock duration in days for approved datasets in datacap. diff --git a/test/interfaces/assertions/module/IDatasetsAssertion.ts b/test/interfaces/assertions/module/IDatasetsAssertion.ts index 5f95ed9..4d6bd27 100644 --- a/test/interfaces/assertions/module/IDatasetsAssertion.ts +++ b/test/interfaces/assertions/module/IDatasetsAssertion.ts @@ -398,9 +398,9 @@ export interface IDatasetsAssertion { * @param expectCount - The expected count of challenge proofs. * @returns A Promise resolving if the assertion is successful. */ - getDatasetChallengeProofsCountAssertion( + getChallengeAuditorsCountSubmittedAssertion( datasetId: number, - expectCount: number + expectCount: bigint ): Promise /** @@ -409,9 +409,20 @@ export interface IDatasetsAssertion { * @param expectCount - The expected count of challenge submissions. * @returns A Promise resolving if the assertion is successful. */ - getChallengeSubmissionCountAssertion( + getChallengePointsCountRequirementAssertion( datasetId: number, - expectCount: number + expectCount: bigint + ): Promise + + /** + * Asserts the required number of auditors for challenging a dataset. + * @param datasetId The ID of the dataset. + * @param expectCount The expected number of auditors required for challenging. + * @returns A promise that resolves to void. + */ + getChallengeAuditorsCountRequirementAssertion( + datasetId: number, + expectCount: bigint ): Promise /** diff --git a/test/shared/utils.ts b/test/shared/utils.ts index 8ef0ac8..f8dce79 100644 --- a/test/shared/utils.ts +++ b/test/shared/utils.ts @@ -231,3 +231,61 @@ export function createTargetMessage(options: { }, }) } + +/** + * Counts the number of ones in the binary representation of a 64-bit number. + * @param _x The input number. + * @returns The number of ones. + */ +function onesCount64(_x: number): bigint { + let count = BigInt(0) + for (let i = 0; i < 64; i++) { + if ((_x & (1 << i)) != 0) { + count++ + } + } + return count +} + +/** + * Counts the number of leading zeros in the binary representation of a 64-bit number. + * @param _x The input number. + * @returns The number of leading zeros. + */ +function leadingZeros64(_x: number): bigint { + let count = BigInt(0) + for (let i = 63; i >= 0; i--) { + if ((_x & (1 << i)) == 0) { + count++ + } else { + break + } + } + return count +} + +/** + * Calculates the padded piece size based on the input size. + * @param _size The input size. + * @returns The padded piece size. + */ +function calculatePaddedPieceSize(_size: number): number { + if (onesCount64(_size) != BigInt(1)) { + let lz = leadingZeros64(_size) + return Number(1 << (64 - Number(lz))) + } else { + return _size + } +} + +/** + * Converts car size to padded piece size. + * @param _size The car size. + * @returns The padded piece size. + */ +export function carSizeToPieceSize(_size: number): number { + const sourceChunkSize: number = 127 + const mod = _size % sourceChunkSize + const size = mod != 0 ? _size + sourceChunkSize - mod : _size + return calculatePaddedPieceSize(size) +} diff --git a/test/unittests/core/filplus.test.ts b/test/unittests/core/filplus.test.ts index 9f86f74..dca7637 100644 --- a/test/unittests/core/filplus.test.ts +++ b/test/unittests/core/filplus.test.ts @@ -138,9 +138,13 @@ describe("filplus", () => { /** * Test case for setting the challenge proofs submiter count. */ - it("setDatasetRuleMaxChallengeProofsSubmitersPerDataset", async function () { - await filplusAssertion.setChallengeProofsSubmiterCountAssertion(1) - await filplusAssertion.setChallengeProofsSubmiterCountAssertion(10) + it("setDatasetRuleChallengePointsPerAuditor", async function () { + await filplusAssertion.setDatasetRuleChallengePointsPerAuditorAssertion( + 2 + ) + await filplusAssertion.setDatasetRuleChallengePointsPerAuditorAssertion( + 5 + ) }) /**