mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
Reject truncated DATUM PPLNS coinbases
This commit is contained in:
+2
-2
@@ -113,11 +113,11 @@ PAYOUT_BOOTSTRAP_WINDOW=true
|
|||||||
# solo preserves current one-address coinbase payouts. Set to snapshot to pay
|
# solo preserves current one-address coinbase payouts. Set to snapshot to pay
|
||||||
# the latest payout snapshot directly in coinbase outputs.
|
# the latest payout snapshot directly in coinbase outputs.
|
||||||
PAYOUT_COINBASE_MODE=solo
|
PAYOUT_COINBASE_MODE=solo
|
||||||
PAYOUT_MAX_COINBASE_OUTPUTS=10
|
PAYOUT_MAX_COINBASE_OUTPUTS=200
|
||||||
PAYOUT_MIN_OUTPUT_SATS=546
|
PAYOUT_MIN_OUTPUT_SATS=546
|
||||||
PAYOUT_FEE_ADDRESS=
|
PAYOUT_FEE_ADDRESS=
|
||||||
PAYOUT_FEE_PERCENT=0
|
PAYOUT_FEE_PERCENT=0
|
||||||
PAYOUT_COINBASE_WEIGHT_BUDGET=50000
|
PAYOUT_COINBASE_WEIGHT_BUDGET=26000
|
||||||
|
|
||||||
#redis
|
#redis
|
||||||
REDIS_URL=redis://redis:6379
|
REDIS_URL=redis://redis:6379
|
||||||
|
|||||||
@@ -108,11 +108,11 @@ services:
|
|||||||
PAYOUT_METHOD: ${PAYOUT_METHOD:-pplns}
|
PAYOUT_METHOD: ${PAYOUT_METHOD:-pplns}
|
||||||
PAYOUT_WINDOW_FACTOR: ${PAYOUT_WINDOW_FACTOR:-4}
|
PAYOUT_WINDOW_FACTOR: ${PAYOUT_WINDOW_FACTOR:-4}
|
||||||
PAYOUT_BOOTSTRAP_WINDOW: ${PAYOUT_BOOTSTRAP_WINDOW:-true}
|
PAYOUT_BOOTSTRAP_WINDOW: ${PAYOUT_BOOTSTRAP_WINDOW:-true}
|
||||||
PAYOUT_MAX_COINBASE_OUTPUTS: ${PAYOUT_MAX_COINBASE_OUTPUTS:-10}
|
PAYOUT_MAX_COINBASE_OUTPUTS: ${PAYOUT_MAX_COINBASE_OUTPUTS:-200}
|
||||||
PAYOUT_MIN_OUTPUT_SATS: ${PAYOUT_MIN_OUTPUT_SATS:-546}
|
PAYOUT_MIN_OUTPUT_SATS: ${PAYOUT_MIN_OUTPUT_SATS:-546}
|
||||||
PAYOUT_FEE_ADDRESS: ${PAYOUT_FEE_ADDRESS:-}
|
PAYOUT_FEE_ADDRESS: ${PAYOUT_FEE_ADDRESS:-}
|
||||||
PAYOUT_FEE_PERCENT: ${PAYOUT_FEE_PERCENT:-0}
|
PAYOUT_FEE_PERCENT: ${PAYOUT_FEE_PERCENT:-0}
|
||||||
PAYOUT_COINBASE_WEIGHT_BUDGET: ${PAYOUT_COINBASE_WEIGHT_BUDGET:-50000}
|
PAYOUT_COINBASE_WEIGHT_BUDGET: ${PAYOUT_COINBASE_WEIGHT_BUDGET:-26000}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "node -e \"const http=require('http'); const https=require('https'); const secure=process.env.API_SECURE==='true'; const client=secure?https:http; const req=client.get({hostname:'127.0.0.1',port:process.env.API_PORT||3334,path:'/api/network',rejectUnauthorized:false},res=>process.exit(res.statusCode<500?0:1)); req.on('error',()=>process.exit(1)); req.setTimeout(5000,()=>{req.destroy(); process.exit(1);});\""]
|
test: ["CMD-SHELL", "node -e \"const http=require('http'); const https=require('https'); const secure=process.env.API_SECURE==='true'; const client=secure?https:http; const req=client.get({hostname:'127.0.0.1',port:process.env.API_PORT||3334,path:'/api/network',rejectUnauthorized:false},res=>process.exit(res.statusCode<500?0:1)); req.on('error',()=>process.exit(1)); req.setTimeout(5000,()=>{req.destroy(); process.exit(1);});\""]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
|
|||||||
@@ -122,11 +122,11 @@ services:
|
|||||||
PAYOUT_WINDOW_FACTOR: ${PAYOUT_WINDOW_FACTOR:-4}
|
PAYOUT_WINDOW_FACTOR: ${PAYOUT_WINDOW_FACTOR:-4}
|
||||||
PAYOUT_BOOTSTRAP_WINDOW: ${PAYOUT_BOOTSTRAP_WINDOW:-true}
|
PAYOUT_BOOTSTRAP_WINDOW: ${PAYOUT_BOOTSTRAP_WINDOW:-true}
|
||||||
PAYOUT_COINBASE_MODE: ${PAYOUT_COINBASE_MODE:-solo}
|
PAYOUT_COINBASE_MODE: ${PAYOUT_COINBASE_MODE:-solo}
|
||||||
PAYOUT_MAX_COINBASE_OUTPUTS: ${PAYOUT_MAX_COINBASE_OUTPUTS:-10}
|
PAYOUT_MAX_COINBASE_OUTPUTS: ${PAYOUT_MAX_COINBASE_OUTPUTS:-200}
|
||||||
PAYOUT_MIN_OUTPUT_SATS: ${PAYOUT_MIN_OUTPUT_SATS:-546}
|
PAYOUT_MIN_OUTPUT_SATS: ${PAYOUT_MIN_OUTPUT_SATS:-546}
|
||||||
PAYOUT_FEE_ADDRESS: ${PAYOUT_FEE_ADDRESS:-}
|
PAYOUT_FEE_ADDRESS: ${PAYOUT_FEE_ADDRESS:-}
|
||||||
PAYOUT_FEE_PERCENT: ${PAYOUT_FEE_PERCENT:-0}
|
PAYOUT_FEE_PERCENT: ${PAYOUT_FEE_PERCENT:-0}
|
||||||
PAYOUT_COINBASE_WEIGHT_BUDGET: ${PAYOUT_COINBASE_WEIGHT_BUDGET:-50000}
|
PAYOUT_COINBASE_WEIGHT_BUDGET: ${PAYOUT_COINBASE_WEIGHT_BUDGET:-26000}
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
bitcoin:
|
bitcoin:
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ export interface ExpectedPayout {
|
|||||||
percent: number;
|
percent: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_MAX_COINBASE_OUTPUTS = 10;
|
const DEFAULT_MAX_COINBASE_OUTPUTS = 200;
|
||||||
const DEFAULT_MIN_OUTPUT_SATS = 546;
|
const DEFAULT_MIN_OUTPUT_SATS = 546;
|
||||||
const DEFAULT_PAYOUT_METHOD = 'pplns';
|
const DEFAULT_PAYOUT_METHOD = 'pplns';
|
||||||
const DEFAULT_PAYOUT_WINDOW_FACTOR = 4;
|
const DEFAULT_PAYOUT_WINDOW_FACTOR = 4;
|
||||||
const DEFAULT_COINBASE_WEIGHT_BUDGET = 50_000;
|
const DEFAULT_COINBASE_WEIGHT_BUDGET = 26_000;
|
||||||
const DEFAULT_PAYOUT_BOOTSTRAP_WINDOW = true;
|
const DEFAULT_PAYOUT_BOOTSTRAP_WINDOW = true;
|
||||||
const PPLNS_PAYOUT_MODE: PayoutMode = 'pplns';
|
const PPLNS_PAYOUT_MODE: PayoutMode = 'pplns';
|
||||||
|
|
||||||
|
|||||||
@@ -329,6 +329,49 @@ describe('DatumService job validation', () => {
|
|||||||
expect(validation.error).toBe('output-count-mismatch');
|
expect(validation.error).toBe('output-count-mismatch');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects DATUM PPLNS coinbases that only fit a smaller profile and add a pool remainder', () => {
|
||||||
|
const configService = {
|
||||||
|
get: jest.fn((key: string) => {
|
||||||
|
if (key === 'NETWORK') {
|
||||||
|
return 'testnet';
|
||||||
|
}
|
||||||
|
if (key === 'DATUM_POOL_PAYOUT_ADDRESS') {
|
||||||
|
return 'tb1qdyjakeepue4trak9d3hvyelrd0aw7mwju2d0c2';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const service = createService({ configService }) as any;
|
||||||
|
const extranonce = Buffer.alloc(12, 1);
|
||||||
|
const expectedOutputs = [
|
||||||
|
{ address: 'tb1q42vtlphyjjcun9wcv9f0d9pkhup9dcf5z9k4gh', amountSats: 421 },
|
||||||
|
{ address: 'tb1q9r8gvnx3j4d6jvl0fqjrmy3dar4k4l3052af7q', amountSats: 133 },
|
||||||
|
{ address: 'tb1qdyjakeepue4trak9d3hvyelrd0aw7mwju2d0c2', amountSats: 42 },
|
||||||
|
];
|
||||||
|
const coinbase = createDatumCoinbaseSplit([
|
||||||
|
{ address: 'tb1q42vtlphyjjcun9wcv9f0d9pkhup9dcf5z9k4gh', amountSats: 421 },
|
||||||
|
{ address: 'tb1qdyjakeepue4trak9d3hvyelrd0aw7mwju2d0c2', amountSats: 175 },
|
||||||
|
], extranonce);
|
||||||
|
const latestTemplate = {
|
||||||
|
blockData: {
|
||||||
|
coinbasevalue: 596,
|
||||||
|
payoutOutputs: expectedOutputs,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const validation = service.validateDatumCoinbasePayouts(
|
||||||
|
coinbase,
|
||||||
|
{ extranonce, targetByte: 0 },
|
||||||
|
latestTemplate,
|
||||||
|
596n,
|
||||||
|
undefined,
|
||||||
|
'pplns',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(validation.valid).toBe(false);
|
||||||
|
expect(validation.error).toBe('output-count-mismatch');
|
||||||
|
});
|
||||||
|
|
||||||
it('rejects DATUM coinbases that do not pay the pool snapshot outputs', () => {
|
it('rejects DATUM coinbases that do not pay the pool snapshot outputs', () => {
|
||||||
const service = createService() as any;
|
const service = createService() as any;
|
||||||
const extranonce = Buffer.alloc(12, 1);
|
const extranonce = Buffer.alloc(12, 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user