Skip to content

Commit 6a22ded

Browse files
authored
Merge pull request #89 from ardriveapp/PE-726_excise_arfs_tag_from_data_tx
PE-726: Excise ArFS tag from data transactions
2 parents 0c5a504 + 58e1c9f commit 6a22ded

File tree

3 files changed

+140
-20
lines changed

3 files changed

+140
-20
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ardrive-core-js",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "ArDrive Core contains the essential back end application features to support the ArDrive CLI and Desktop apps, such as file management, Permaweb upload/download, wallet management and other common functions.",
55
"main": "./lib/exports.js",
66
"types": "./lib/exports.d.ts",

src/arfs/arfsdao.test.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import Arweave from 'arweave';
2+
import { stubEntityID } from '../../tests/stubs';
3+
import { ByteCount, FeeMultiple, stubTransactionID, UnixTime, W } from '../types';
4+
import { readJWKFile } from '../utils/common';
5+
import { ArFSDAO } from './arfsdao';
6+
import { ArFSPublicFileMetaDataPrototype } from './arfs_prototypes';
7+
import { ArFSPublicFileMetadataTransactionData } from './arfs_trx_data_types';
8+
import { expect } from 'chai';
9+
import { Tag } from 'arweave/node/lib/transaction';
10+
11+
describe('The ArFSDAO class', () => {
12+
const wallet = readJWKFile('./test_wallet.json');
13+
const fakeArweave = Arweave.init({
14+
host: 'localhost',
15+
port: 443,
16+
protocol: 'https',
17+
timeout: 600000
18+
});
19+
20+
const arfsDao = new ArFSDAO(wallet, fakeArweave, true, 'ArFSDAO-Test', '1.0');
21+
22+
const stubFileMetaDataTrx = new ArFSPublicFileMetaDataPrototype(
23+
new ArFSPublicFileMetadataTransactionData(
24+
'Test Metadata',
25+
new ByteCount(10),
26+
new UnixTime(123456789),
27+
stubTransactionID,
28+
'text/plain'
29+
),
30+
stubEntityID,
31+
stubEntityID,
32+
stubEntityID
33+
);
34+
35+
describe('prepareObjectTransaction function', () => {
36+
// Helper function to grab the decoded gql tags off of a Transaction
37+
const getDecodedTagName = (tag: Tag) => tag.get('name', { decode: true, string: true });
38+
39+
it('includes the base ArFS tags by default', async () => {
40+
const transaction = await arfsDao.prepareArFSObjectTransaction({
41+
objectMetaData: stubFileMetaDataTrx,
42+
rewardSettings: { reward: W(10) }
43+
});
44+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'ArFS')).to.exist;
45+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'App-Name')).to.exist;
46+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'App-Version')).to.exist;
47+
expect(transaction.tags.length).to.equal(9);
48+
});
49+
50+
it('includes the boost tag when boosted', async () => {
51+
const transaction = await arfsDao.prepareArFSObjectTransaction({
52+
objectMetaData: stubFileMetaDataTrx,
53+
rewardSettings: { reward: W(10), feeMultiple: new FeeMultiple(1.5) }
54+
});
55+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'Boost')).to.exist;
56+
expect(transaction.tags.length).to.equal(10);
57+
});
58+
59+
it('excludes the boost tag when boosted and boost tag is excluded', async () => {
60+
const transaction = await arfsDao.prepareArFSObjectTransaction({
61+
objectMetaData: stubFileMetaDataTrx,
62+
rewardSettings: { reward: W(10), feeMultiple: new FeeMultiple(1.5) },
63+
excludedTagNames: ['Boost']
64+
});
65+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'Boost')).to.be.undefined;
66+
expect(transaction.tags.length).to.equal(9);
67+
});
68+
69+
it('excludes ArFS tag if its within the exclusion array', async () => {
70+
const transaction = await arfsDao.prepareArFSObjectTransaction({
71+
objectMetaData: stubFileMetaDataTrx,
72+
rewardSettings: { reward: W(10) },
73+
excludedTagNames: ['ArFS']
74+
});
75+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'ArFS')).to.be.undefined;
76+
expect(transaction.tags.length).to.equal(8);
77+
});
78+
79+
it('can exclude multiple tags if provided within the exclusion array', async () => {
80+
const transaction = await arfsDao.prepareArFSObjectTransaction({
81+
objectMetaData: stubFileMetaDataTrx,
82+
rewardSettings: { reward: W(10) },
83+
excludedTagNames: ['ArFS', 'App-Version', 'App-Name']
84+
});
85+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'ArFS')).to.be.undefined;
86+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'App-Name')).to.be.undefined;
87+
expect(transaction.tags.find((tag) => getDecodedTagName(tag) === 'App-Version')).to.be.undefined;
88+
expect(transaction.tags.length).to.equal(6);
89+
});
90+
});
91+
});

src/arfs/arfsdao.ts

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ export class PrivateDriveKeyData {
108108
}
109109
}
110110

111+
export interface PrepareObjectTransactionParams {
112+
objectMetaData: ArFSObjectMetadataPrototype;
113+
rewardSettings?: RewardSettings;
114+
excludedTagNames?: string[];
115+
otherTags?: GQLTagInterface[];
116+
}
117+
111118
export interface ArFSMoveParams<O extends ArFSFileOrFolderEntity, T extends ArFSObjectTransactionData> {
112119
originalMetaData: O;
113120
newParentFolderId: FolderID;
@@ -208,7 +215,7 @@ export class ArFSDAO extends ArFSDAOAnonymous {
208215

209216
// Create a root folder metadata transaction
210217
const folderMetadata = folderPrototypeFactory(folderId, parentFolderId);
211-
const folderTrx = await this.prepareArFSObjectTransaction(folderMetadata, rewardSettings);
218+
const folderTrx = await this.prepareArFSObjectTransaction({ objectMetaData: folderMetadata, rewardSettings });
212219

213220
// Execute the upload
214221
if (!this.dryRun) {
@@ -275,7 +282,10 @@ export class ArFSDAO extends ArFSDAOAnonymous {
275282

276283
// Create a drive metadata transaction
277284
const driveMetaData = await createMetadataFn(driveId, rootFolderId);
278-
const driveTrx = await this.prepareArFSObjectTransaction(driveMetaData, driveRewardSettings);
285+
const driveTrx = await this.prepareArFSObjectTransaction({
286+
objectMetaData: driveMetaData,
287+
rewardSettings: driveRewardSettings
288+
});
279289

280290
// Execute the upload
281291
if (!this.dryRun) {
@@ -369,7 +379,10 @@ export class ArFSDAO extends ArFSDAOAnonymous {
369379
const metadataPrototype = metaDataFactory();
370380

371381
// Prepare meta data transaction
372-
const metaDataTrx = await this.prepareArFSObjectTransaction(metadataPrototype, metaDataBaseReward);
382+
const metaDataTrx = await this.prepareArFSObjectTransaction({
383+
objectMetaData: metadataPrototype,
384+
rewardSettings: metaDataBaseReward
385+
});
373386

374387
// Upload meta data
375388
if (!this.dryRun) {
@@ -493,7 +506,11 @@ export class ArFSDAO extends ArFSDAOAnonymous {
493506

494507
// Build file data transaction
495508
const fileDataPrototype = await dataPrototypeFactoryFn(fileData, dataContentType, fileId);
496-
const dataTrx = await this.prepareArFSObjectTransaction(fileDataPrototype, fileDataRewardSettings);
509+
const dataTrx = await this.prepareArFSObjectTransaction({
510+
objectMetaData: fileDataPrototype,
511+
rewardSettings: fileDataRewardSettings,
512+
excludedTagNames: ['ArFS']
513+
});
497514

498515
// Upload file data
499516
if (!this.dryRun) {
@@ -513,7 +530,10 @@ export class ArFSDAO extends ArFSDAOAnonymous {
513530
fileId
514531
);
515532
const fileMetadata = metadataFactoryFn(metadataTrxData, fileId);
516-
const metaDataTrx = await this.prepareArFSObjectTransaction(fileMetadata, metadataRewardSettings);
533+
const metaDataTrx = await this.prepareArFSObjectTransaction({
534+
objectMetaData: fileMetadata,
535+
rewardSettings: metadataRewardSettings
536+
});
517537

518538
// Upload meta data
519539
if (!this.dryRun) {
@@ -612,11 +632,12 @@ export class ArFSDAO extends ArFSDAOAnonymous {
612632
);
613633
}
614634

615-
async prepareArFSObjectTransaction(
616-
objectMetaData: ArFSObjectMetadataPrototype,
617-
rewardSettings: RewardSettings = {},
618-
otherTags: GQLTagInterface[] = []
619-
): Promise<Transaction> {
635+
async prepareArFSObjectTransaction({
636+
objectMetaData,
637+
rewardSettings = {},
638+
excludedTagNames = [],
639+
otherTags = []
640+
}: PrepareObjectTransactionParams): Promise<Transaction> {
620641
const wallet = this.wallet as JWKWallet;
621642

622643
// Create transaction
@@ -641,23 +662,31 @@ export class ArFSDAO extends ArFSDAOAnonymous {
641662
transaction.reward = rewardSettings.feeMultiple.boostReward(transaction.reward);
642663
}
643664

644-
// Add baseline ArFS Tags
645-
transaction.addTag('App-Name', this.appName);
646-
transaction.addTag('App-Version', this.appVersion);
647-
transaction.addTag('ArFS', CURRENT_ARFS_VERSION);
665+
let tagsToAdd: GQLTagInterface[] = [
666+
// Add baseline App Name and App Version Tags
667+
{ name: 'App-Name', value: this.appName },
668+
{ name: 'App-Version', value: this.appVersion },
669+
{ name: 'ArFS', value: CURRENT_ARFS_VERSION }
670+
];
671+
648672
if (rewardSettings.feeMultiple?.wouldBoostReward()) {
649-
transaction.addTag('Boost', rewardSettings.feeMultiple.toString());
673+
tagsToAdd.push({ name: 'Boost', value: rewardSettings.feeMultiple.toString() });
650674
}
651675

652-
// Add object-specific tags
653-
objectMetaData.addTagsToTransaction(transaction);
654-
655676
// Enforce that other tags are not protected
656677
objectMetaData.assertProtectedTags(otherTags);
657-
otherTags.forEach((tag) => {
678+
tagsToAdd.push(...otherTags);
679+
680+
// Remove any excluded tags
681+
tagsToAdd = tagsToAdd.filter((tag) => !excludedTagNames.includes(tag.name));
682+
683+
tagsToAdd.forEach((tag) => {
658684
transaction.addTag(tag.name, tag.value);
659685
});
660686

687+
// Add object-specific tags
688+
objectMetaData.addTagsToTransaction(transaction);
689+
661690
// Sign the transaction
662691
await this.arweave.transactions.sign(transaction, wallet.getPrivateKey());
663692
return transaction;

0 commit comments

Comments
 (0)