Skip to content

Commit 4c8fb56

Browse files
committed
ref!(dashp2p): allow shared and reusable buffers
1 parent b87ecba commit 4c8fb56

File tree

2 files changed

+253
-109
lines changed

2 files changed

+253
-109
lines changed

public/dashjoin.js

Lines changed: 154 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ var DashJoin = ('object' === typeof module && exports) || {};
33
'use strict';
44

55
let DashP2P = window.DashP2P || require('dashp2p');
6+
let DashTx = window.DashTx || require('dashtx');
67

78
const DV_LITTLE_ENDIAN = true;
89

910
const DENOM_LOWEST = 100001;
1011
const PREDENOM_MIN = DENOM_LOWEST + 193;
1112
const COLLATERAL = 10000; // DENOM_LOWEST / 10
12-
const PAYLOAD_SIZE_MAX = 4 * 1024 * 1024;
1313

1414
let STANDARD_DENOMINATIONS_MAP = {
1515
// 0.00100001
@@ -24,11 +24,25 @@ var DashJoin = ('object' === typeof module && exports) || {};
2424
0b00000001: 1000010000,
2525
};
2626

27+
// Note: "mask" may be a misnomer. The spec seems to be more of an ID,
28+
// but the implementation makes it look more like a mask...
29+
let STANDARD_DENOMINATION_MASKS = {
30+
// 0.00100001
31+
100001: 0b00010000,
32+
// 0.01000010
33+
1000010: 0b00001000,
34+
// 0.10000100
35+
10000100: 0b00000100,
36+
// 1.00001000
37+
100001000: 0b00000010,
38+
// 10.00010000
39+
1000010000: 0b00000001,
40+
};
41+
2742
// https://github.com/dashpay/dash/blob/v19.x/src/coinjoin/coinjoin.h#L39
2843
// const COINJOIN_ENTRY_MAX_SIZE = 9; // real
2944
// const COINJOIN_ENTRY_MAX_SIZE = 2; // just for testing right now
3045

31-
DashJoin.PAYLOAD_SIZE_MAX = PAYLOAD_SIZE_MAX;
3246
DashJoin.DENOM_LOWEST = DENOM_LOWEST;
3347
DashJoin.COLLATERAL = COLLATERAL;
3448
DashJoin.PREDENOM_MIN = PREDENOM_MIN;
@@ -59,6 +73,17 @@ var DashJoin = ('object' === typeof module && exports) || {};
5973
return 0;
6074
};
6175

76+
Sizes.DSQ = 142;
77+
Sizes.SENDDSQ = 1; // 1-byte bool
78+
Sizes.DENOM = 4; // 32-bit uint
79+
Sizes.PROTX = 32;
80+
Sizes.TIME = 8; // 64-bit uint
81+
Sizes.READY = 1; // 1-byte bool
82+
Sizes.SIG = 97;
83+
84+
// Sizes.DSSU = 16;
85+
// Sizes.SESSION_ID = 4;
86+
6287
/**
6388
* Turns on or off DSQ messages (necessary for CoinJoin, but off by default)
6489
* @param {Object} opts
@@ -72,43 +97,144 @@ var DashJoin = ('object' === typeof module && exports) || {};
7297
send = true,
7398
}) {
7499
const command = 'senddsq';
75-
const SENDDSQ_SIZE = 1; // 1-byte bool
100+
let [bytes, payload] = DashP2P.packers._alloc(message, Sizes.SENDDSQ);
76101

77-
if (!message) {
78-
let dsqSize = DashP2P.sizes.HEADER_SIZE + SENDDSQ_SIZE;
79-
message = new Uint8Array(dsqSize);
102+
let sendByte = [0x01];
103+
if (!send) {
104+
sendByte = [0x00];
80105
}
106+
payload.set(sendByte, 0);
107+
108+
void DashP2P.packers.message({ network, command, bytes });
109+
return bytes;
110+
};
81111

82-
let payload = message.subarray(DashP2P.sizes.HEADER_SIZE);
83-
if (send) {
84-
payload.set([0x01], 0);
85-
} else {
86-
payload.set([0x00], 0);
112+
/**
113+
* @param {Object} opts
114+
* @param {NetworkName} opts.network - "mainnet", "testnet", etc
115+
* @param {Uint8Array?} [opts.message]
116+
* @param {Uint32} opts.denomination
117+
* @param {Uint8Array} opts.collateralTx
118+
*/
119+
Packers.dsa = function ({ network, message, denomination, collateralTx }) {
120+
const command = 'dsa';
121+
let dsaSize = Sizes.DENOM + collateralTx.length;
122+
let [bytes, payload] = DashP2P.packers._alloc(message, dsaSize);
123+
124+
//@ts-ignore - numbers can be used as map keys
125+
let denomMask = STANDARD_DENOMINATION_MASKS[denomination];
126+
if (!denomMask) {
127+
throw new Error(
128+
`contact your local Dash representative to vote for denominations of '${denomination}'`,
129+
);
87130
}
88131

89-
void DashP2P.packers.message({ network, command, bytes: message });
90-
return message;
91-
// return { message, payload };
132+
let dv = new DataView(payload.buffer);
133+
let offset = 0;
134+
135+
dv.setUint32(offset, denomMask, DV_LITTLE_ENDIAN);
136+
offset += Sizes.DENOM;
137+
138+
payload.set(collateralTx, offset);
139+
140+
void DashP2P.packers.message({ network, command, bytes });
141+
return bytes;
92142
};
93143

94-
Sizes.DSQ_SIZE = 142;
95-
// DSQ stuff??
96-
Sizes.DENOM = 4;
97-
Sizes.PROTX = 32;
98-
Sizes.TIME = 8;
99-
Sizes.READY = 1;
100-
Sizes.SIG = 97;
101-
//
144+
/**
145+
* @param {Object} opts
146+
* @param {NetworkName} opts.network - "mainnet", "testnet", etc
147+
* @param {Uint8Array?} [opts.message]
148+
* @param {Array<import('dashtx').TxInput>} opts.inputs
149+
* @param {Array<import('dashtx').TxOutput>} opts.outputs
150+
* @param {Uint8Array} opts.collateralTx
151+
*/
152+
Packers.dsi = function ({ network, message, inputs, collateralTx, outputs }) {
153+
const command = 'dsi';
154+
155+
let neutered = [];
156+
for (let input of inputs) {
157+
let _input = {
158+
txId: input.txId || input.txid,
159+
txid: input.txid || input.txId,
160+
outputIndex: input.outputIndex,
161+
};
162+
neutered.push(_input);
163+
}
164+
165+
let inputsHex = DashTx.serializeInputs(inputs);
166+
let inputHex = inputsHex.join('');
167+
let outputsHex = DashTx.serializeOutputs(outputs);
168+
let outputHex = outputsHex.join('');
169+
170+
let dsiSize = collateralTx.length;
171+
dsiSize += inputHex.length / 2;
172+
dsiSize += outputHex.length / 2;
173+
174+
let [bytes, payload] = DashP2P.packers._alloc(message, dsiSize);
102175

103-
// Sizes.DSSU_SIZE = 16;
104-
// Sizes.SESSION_ID_SIZE = 4;
176+
let offset = 0;
177+
{
178+
let j = 0;
179+
for (let i = 0; i < inputHex.length; i += 2) {
180+
let end = i + 2;
181+
let hex = inputHex.slice(i, end);
182+
payload[j] = parseInt(hex, 16);
183+
j += 1;
184+
}
185+
offset += inputHex.length / 2;
186+
}
187+
188+
payload.set(collateralTx, offset);
189+
offset += collateralTx.length;
190+
191+
{
192+
let outputsPayload = payload.subarray(offset);
193+
let j = 0;
194+
for (let i = 0; i < outputHex.length; i += 2) {
195+
let end = i + 2;
196+
let hex = outputHex.slice(i, end);
197+
outputsPayload[j] = parseInt(hex, 16);
198+
j += 1;
199+
}
200+
offset += outputHex.length / 2;
201+
}
202+
203+
void DashP2P.packers.message({ network, command, bytes });
204+
return bytes;
205+
};
206+
207+
/**
208+
* @param {Object} opts
209+
* @param {Uint8Array?} [opts.message]
210+
* @param {NetworkName} opts.network - "mainnet", "testnet", etc
211+
* @param {Array<import('dashtx').CoreUtxo>} [opts.inputs]
212+
*/
213+
Packers.dss = function ({ network, message, inputs }) {
214+
const command = 'dss';
215+
216+
if (!inputs?.length) {
217+
// TODO make better
218+
throw new Error('you must provide some inputs');
219+
}
220+
221+
let txInputsHex = DashTx.serializeInputs(inputs);
222+
let txInputHex = txInputsHex.join('');
223+
224+
let dssSize = txInputHex.length / 2;
225+
let [bytes, payload] = DashP2P.packers._alloc(message, dssSize);
226+
void DashP2P.utils.hexToPayload(txInputHex, payload);
227+
228+
void DashP2P.packers.message({ network, command, bytes });
229+
return bytes;
230+
};
105231

106232
/**
107233
* @param {Uint8Array} bytes
108234
*/
109235
Parsers.dsq = function (bytes) {
110-
if (bytes.length !== Sizes.DSQ_SIZE) {
111-
let msg = `developer error: 'dsq' must be ${Sizes.DSQ_SIZE} bytes, but received ${bytes.length}`;
236+
if (bytes.length !== Sizes.DSQ) {
237+
let msg = `developer error: 'dsq' must be ${Sizes.DSQ} bytes, but received ${bytes.length}`;
112238
throw new Error(msg);
113239
}
114240
let dv = new DataView(bytes.buffer);
@@ -160,40 +286,8 @@ var DashJoin = ('object' === typeof module && exports) || {};
160286
return dsqMessage;
161287
};
162288

163-
Utils.hexToBytes = function (hex) {
164-
let bufLen = hex.length / 2;
165-
let u8 = new Uint8Array(bufLen);
166-
167-
let i = 0;
168-
let index = 0;
169-
let lastIndex = hex.length - 2;
170-
for (;;) {
171-
if (i > lastIndex) {
172-
break;
173-
}
174-
175-
let h = hex.slice(i, i + 2);
176-
let b = parseInt(h, 16);
177-
u8[index] = b;
178-
179-
i += 2;
180-
index += 1;
181-
}
182-
183-
return u8;
184-
};
185-
186-
Utils.bytesToHex = function (u8) {
187-
/** @type {Array<String>} */
188-
let hex = [];
189-
190-
u8.forEach(function (b) {
191-
let h = b.toString(16).padStart(2, '0');
192-
hex.push(h);
193-
});
194-
195-
return hex.join('');
196-
};
289+
// Utils.hexToBytes = DashTx.utils.hexToBytes;
290+
// Utils.bytesToHex = DashTx.utils.bytesToHex;
197291

198292
Utils._evonodeMapToList = function (evonodesMap) {
199293
console.log('[debug] get evonode list...');

0 commit comments

Comments
 (0)