Skip to content

Commit 3dc47a2

Browse files
authored
Merge pull request #84 from ardriveapp/PE-701_merge_down_master
PE-707: Adjust estimator for byteCountForWinston and export chunk estimator
2 parents da4a1e4 + 21fa3d8 commit 3dc47a2

File tree

5 files changed

+67
-25
lines changed

5 files changed

+67
-25
lines changed

README.md

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
1-
# Version 1.0 Is Coming!
2-
3-
Version 0.x will be retired in favor of a major version update whose enhacements include:
4-
5-
- Improved type safety
6-
- More user-friendly ArDrive and ArFS APIs
7-
- Excision of database-related code
8-
- Excision of file-sync-related code
9-
10-
We believe these improvements will promote extensibility and decouple key building blocks from unnecessary dependencies. Engage with the community in [Discord](https://discord.gg/7RuTBckX) for more information.
11-
121
# ardrive-core-js
132

143
ArDrive Core is a TypeScript library that 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.
154

5+
Engage with the community in [Discord](https://discord.gg/7RuTBckX) for more information.
6+
167
## Development Environment Setup
178

189
We use nvm to manage our Node engine version and, if necessary, to install an npm version that we can then use to install Yarn.

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.1",
3+
"version": "1.0.2",
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/exports.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export * from './community/verto_contract_oracle';
4040
// Pricing
4141
export * from './pricing/ar_data_price';
4242
export * from './pricing/ar_data_price_estimator';
43+
export * from './pricing/ar_data_price_chunk_estimator';
4344
export * from './pricing/ar_data_price_oracle_estimator';
4445
export * from './pricing/arweave_oracle';
4546
export * from './pricing/data_price_regression';

src/pricing/ar_data_price_chunk_estimator.test.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { GatewayOracle } from './gateway_oracle';
22
import type { ArweaveOracle } from './arweave_oracle';
33
import { expect } from 'chai';
44
import { SinonStubbedInstance, stub } from 'sinon';
5-
import { ArDriveCommunityTip, W, AR, ByteCount } from '../types';
5+
import { W, AR, ByteCount, ArDriveCommunityTip } from '../types';
66
import { ARDataPriceChunkEstimator } from './ar_data_price_chunk_estimator';
77

88
describe('ARDataPriceChunkEstimator class', () => {
@@ -60,12 +60,18 @@ describe('ARDataPriceChunkEstimator class', () => {
6060
• 1 chunk of bytes: base fee + marginal chunk fee
6161
• 1 chunk of bytes plus 1 byte: base fee + (marginal chunk fee * 2)
6262
• 2 chunks of bytes: base fee + (marginal chunk fee * 2)
63+
• 5 chunks of bytes: base fee + (marginal chunk fee * 2) + 1
64+
• 10 chunks of bytes: base fee + (marginal chunk fee * 2) + 2
6365
*/
6466
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(0))}`).to.equal('102');
6567
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(1))}`).to.equal('1102');
6668
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(chunkSize))}`).to.equal('1102');
6769
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(chunkSize + 1))}`).to.equal('2102');
6870
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(chunkSize * 2))}`).to.equal('2102');
71+
// Extra winston for 5th chunk
72+
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(chunkSize * 5))}`).to.equal('5103');
73+
// Two extra winston for 10th chunk
74+
expect(`${await calculator.getBaseWinstonPriceForByteCount(new ByteCount(chunkSize * 10))}`).to.equal('10104');
6975
});
7076

7177
describe('getByteCountForWinston function', () => {
@@ -78,6 +84,11 @@ describe('ARDataPriceChunkEstimator class', () => {
7884
• Base fee + marginal chunk price Winston: chunksize bytes
7985
• Base fee + marginal chunk price + 1 Winston: chunksize bytes
8086
• Base fee + (2 * marginal chunk price) Winston: 2 * chunksize bytes
87+
• Base fee + (5 * marginal chunk price) + 1 Winston: 5 * chunksize bytes
88+
• Base fee + (10 * marginal chunk price) + 2 Winston: 10 * chunksize bytes
89+
• Base fee + (10 * marginal chunk price) + 1 Winston: 9 * chunksize bytes
90+
• Base fee + (8000 * marginal chunk price) + 1599 Winston: 7999 * chunksize bytes
91+
• Base fee + (8000 * marginal chunk price) + 1600 Winston: 8000 * chunksize bytes
8192
*/
8293
expect((await calculator.getByteCountForWinston(W(0))).equals(new ByteCount(0))).to.be.true;
8394
expect((await calculator.getByteCountForWinston(W(1))).equals(new ByteCount(0))).to.be.true;
@@ -98,6 +109,40 @@ describe('ARDataPriceChunkEstimator class', () => {
98109
new ByteCount(2 * chunkSize)
99110
)
100111
).to.be.true;
112+
expect(
113+
// Add one extra winston for the 5th chunk
114+
(await calculator.getByteCountForWinston(W(baseFee + 2 + 5 * marginalFeePerChunk + 1))).equals(
115+
new ByteCount(5 * chunkSize)
116+
)
117+
).to.be.true;
118+
119+
expect(
120+
// Add two extra winston for the 10th chunk
121+
(await calculator.getByteCountForWinston(W(baseFee + 2 + 10 * marginalFeePerChunk + 2))).equals(
122+
new ByteCount(10 * chunkSize)
123+
)
124+
).to.be.true;
125+
126+
expect(
127+
// But expect 9 chunks when only 1 extra winston is added
128+
(await calculator.getByteCountForWinston(W(baseFee + 2 + 10 * marginalFeePerChunk + 1))).equals(
129+
new ByteCount(9 * chunkSize)
130+
)
131+
).to.be.true;
132+
133+
expect(
134+
// Expect winston for 8000 chunks but only 1599 extra winston to equal 7999 chunks
135+
(await calculator.getByteCountForWinston(W(baseFee + 2 + 8000 * marginalFeePerChunk + 1599))).equals(
136+
new ByteCount(7999 * chunkSize)
137+
)
138+
).to.be.true;
139+
140+
expect(
141+
// But 1600 extra winston will return 8000 chunks
142+
(await calculator.getByteCountForWinston(W(baseFee + 2 + 8000 * marginalFeePerChunk + 1600))).equals(
143+
new ByteCount(8000 * chunkSize)
144+
)
145+
).to.be.true;
101146
});
102147

103148
it('makes two oracle calls after the first price estimation request', async () => {

src/pricing/ar_data_price_chunk_estimator.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { GatewayOracle } from './gateway_oracle';
22
import type { ArweaveOracle } from './arweave_oracle';
33
import { AbstractARDataPriceAndCapacityEstimator } from './ar_data_price_estimator';
4-
import { ArDriveCommunityTip, AR, ByteCount, Winston, W } from '../types';
4+
import { AR, ByteCount, Winston, W, ArDriveCommunityTip } from '../types';
55

66
const byteCountOfChunk = new ByteCount(Math.pow(2, 10) * 256); // 256 KiB
77

@@ -91,13 +91,14 @@ export class ARDataPriceChunkEstimator extends AbstractARDataPriceAndCapacityEst
9191

9292
const numberOfChunksToUpload = Math.ceil(byteCount.valueOf() / byteCountOfChunk.valueOf());
9393

94-
// Every 5th chunk, arweave.net pricing adds 1 winston
95-
const mysteriousExtraWinston = W(Math.floor(numberOfChunksToUpload / 5));
94+
// Every 5th chunk, arweave.net pricing adds 1 Winston, which they define as a
95+
// mining reward as a proportion of the estimated transaction storage costs
96+
const minerFeeShareResidual = W(Math.floor(numberOfChunksToUpload / 5));
9697

9798
const predictedPrice = this.pricingInfo.perChunkWinstonPrice
9899
.times(numberOfChunksToUpload)
99100
.plus(this.pricingInfo.baseWinstonPrice)
100-
.plus(mysteriousExtraWinston);
101+
.plus(minerFeeShareResidual);
101102

102103
return predictedPrice;
103104
}
@@ -118,17 +119,22 @@ export class ARDataPriceChunkEstimator extends AbstractARDataPriceAndCapacityEst
118119
throw Error('Failed to generate pricing model!');
119120
}
120121
}
122+
const { oneChunkWinstonPrice, baseWinstonPrice, perChunkWinstonPrice } = this.pricingInfo;
121123

122-
if (winston.isGreaterThanOrEqualTo(this.pricingInfo.oneChunkWinstonPrice)) {
123-
// TODO: TEST THIS UPDATED ALGO!
124-
const numberOfChunks = +winston
125-
.minus(this.pricingInfo.baseWinstonPrice)
126-
.dividedBy(+this.pricingInfo.perChunkWinstonPrice, 'ROUND_DOWN');
124+
if (winston.isGreaterThanOrEqualTo(oneChunkWinstonPrice)) {
125+
const winstonToSpend = winston.minus(baseWinstonPrice);
127126

128-
return new ByteCount(+byteCountOfChunk * numberOfChunks);
127+
const fifthChunks = winstonToSpend
128+
.dividedBy(perChunkWinstonPrice.toString(), 'ROUND_DOWN')
129+
.dividedBy(5, 'ROUND_DOWN');
130+
const actualWinstonToSpend = winstonToSpend.minus(fifthChunks);
131+
132+
const numChunks = actualWinstonToSpend.dividedBy(perChunkWinstonPrice.toString(), 'ROUND_DOWN');
133+
134+
return new ByteCount(+numChunks.times(byteCountOfChunk.toString()));
129135
}
130136

131-
// Return 0 if winston price given does not cover the base winston price for a 1 byte transaction
137+
// Return 0 if winston price given does not cover the base winston price for a 1 chunk transaction
132138
return new ByteCount(0);
133139
}
134140

@@ -150,7 +156,6 @@ export class ARDataPriceChunkEstimator extends AbstractARDataPriceAndCapacityEst
150156
}
151157
}
152158

153-
// TODO: CHANGE AND/OR TEST THIS ALGO
154159
return super.getByteCountForAR(arPrice, { minWinstonFee, tipPercentage });
155160
}
156161
}

0 commit comments

Comments
 (0)