Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref! only support getPrivateKey(), drop keys array #57

Merged
merged 2 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions bin/create-memo.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ let DashTx = require("../");
let DashKeys = require("dashkeys");
let Secp256k1 = require("@dashincubator/secp256k1");

/** @type {import('../dashtx.js').TxSign} */
async function signTx(privKeyBytes, hashBytes) {
let sigOpts = { canonical: true };
let sigBuf = await Secp256k1.sign(hashBytes, privKeyBytes, sigOpts);
return sigBuf;
}

async function main() {
let args = process.argv.slice(2);

Expand Down Expand Up @@ -77,7 +70,6 @@ async function main() {
let dash = toDash(coreUtxo.satoshis);
console.info(`Coin Value: ${dash} (${duffs})`);

let keys = [privKeyBytes];
let inputs = [coreUtxo];
let outputs = [{ memo: memo, satoshis: 0 }];

Expand Down Expand Up @@ -106,11 +98,29 @@ async function main() {
//change.satoshis = sats;

let dashTx = DashTx.create({
sign: signTx,
/** @type {import('../dashtx.js').TxSign} */
sign: async function (privKeyBytes, hashBytes) {
let sigOpts = { canonical: true };
let sigBuf = await Secp256k1.sign(hashBytes, privKeyBytes, sigOpts);
return sigBuf;
},
getPrivateKey: async function () {
return privKeyBytes;
},
toPublicKey:
/**
* @param {Uint8Array} privBytes
* @returns {Promise<Uint8Array>}
*/
async function (privBytes) {
let isCompressed = true;
let pubBytes = Secp256k1.getPublicKey(privBytes, isCompressed);
return pubBytes;
},
});

//@ts-ignore
let txInfoSigned = await dashTx.hashAndSignAll(txInfo, keys);
let txInfoSigned = await dashTx.hashAndSignAll(txInfo);
let txHex = txInfoSigned.transaction.toString();

console.info();
Expand Down
42 changes: 11 additions & 31 deletions dashtx.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,9 @@ var DashTx = ("object" === typeof module && exports) || {};
let txInst = {};

/** @type {TxHashAndSignAll} */
txInst.hashAndSignAll = async function (txInfo, keys) {
txInst.hashAndSignAll = async function (txInfo) {
let privUtils = keyUtils;
if (keys) {
if (keys.length !== txInfo.inputs.length) {
let msg = `the number and order of 'keys' must match number of 'inputs' - each 'utxo' of the provided private key must be matched to that private key`;
throw new Error(msg);
}
privUtils = Object.assign({}, keyUtils);
}
void Tx._addPrivKeyUtils(privUtils, keys);
void Tx._addPrivKeyUtils(privUtils);

return await Tx._hashAndSignAll(txInfo, privUtils);
};
Expand Down Expand Up @@ -333,19 +326,18 @@ var DashTx = ("object" === typeof module && exports) || {};

/**
* @param {TxDraft} txDraft
* @param {Array<TxPrivateKey>} keys
* @returns {Promise<TxSummary>}
*/
txInst.legacy.finalizePresorted = async function (txDraft, keys) {
txInst.legacy.finalizePresorted = async function (txDraft) {
/** @type {TxInfoSigned} */
let txSigned = await txInst.legacy
._signToTarget(txDraft, keys)
._signToTarget(txDraft)
.catch(async function (e) {
if ("E_NO_ENTROPY" !== e.code) {
throw e;
}

let _txSigned = await txInst.legacy._signFeeWalk(txDraft, keys);
let _txSigned = await txInst.legacy._signFeeWalk(txDraft);
return _txSigned;
});

Expand All @@ -355,10 +347,9 @@ var DashTx = ("object" === typeof module && exports) || {};

/**
* @param {TxDraft} txDraft
* @param {Array<Uint8Array>} keys
* @returns {Promise<TxInfoSigned>}
*/
txInst.legacy._signToTarget = async function (txDraft, keys) {
txInst.legacy._signToTarget = async function (txDraft) {
let limit = 128;
let lastTx = "";
let hasEntropy = true;
Expand All @@ -368,7 +359,7 @@ var DashTx = ("object" === typeof module && exports) || {};
let fee;

for (let n = 0; true; n += 1) {
txSigned = await txInst.hashAndSignAll(txDraft, keys);
txSigned = await txInst.hashAndSignAll(txDraft);

fee = txSigned.transaction.length / 2;
if (fee <= txDraft.feeTarget) {
Expand Down Expand Up @@ -401,10 +392,9 @@ var DashTx = ("object" === typeof module && exports) || {};
* Strategy for signing transactions when a non-entropy signing method is used -
* exhaustively walk each possible signature until one that works is found.
* @param {TxDraft} txDraft
* @param {Array<Uint8Array>} keys
* @returns {Promise<TxInfoSigned>}
*/
txInst.legacy._signFeeWalk = async function (txDraft, keys) {
txInst.legacy._signFeeWalk = async function (txDraft) {
//@ts-ignore - TODO should have satoshis by now
let totalIn = DashTx.sum(txDraft.inputs);
let totalOut = DashTx.sum(txDraft.outputs);
Expand Down Expand Up @@ -434,7 +424,7 @@ var DashTx = ("object" === typeof module && exports) || {};
txDraft.outputs[outIndex].satoshis -= 1;
totalFee += 1;

txSigned = await txInst.hashAndSignAll(txDraft, keys);
txSigned = await txInst.hashAndSignAll(txDraft);

let byteFee = txSigned.transaction.length / 2;
if (byteFee <= totalFee) {
Expand Down Expand Up @@ -745,19 +735,10 @@ var DashTx = ("object" === typeof module && exports) || {};

/**
* @param {TxDeps} privUtils
* @param {Array<TxPrivateKey>} keys
*/
Tx._addPrivKeyUtils = function (privUtils, keys) {
Tx._addPrivKeyUtils = function (privUtils) {
if (!privUtils.getPrivateKey) {
if (!keys) {
throw new Error(`you must create with 'getPrivateKey()'`);
}
/** @type {TxGetPrivateKey} */
privUtils.getPrivateKey = async function (_, i) {
//@ts-ignore - keys *is* defined, see above
let privKey = keys[i];
return privKey;
};
throw new Error(`you must create with 'opts.getPrivateKey()'`);
}

if (!privUtils.getPublicKey) {
Expand Down Expand Up @@ -2113,7 +2094,6 @@ if ("object" === typeof module) {
/**
* @callback TxHashAndSignAll
* @param {TxInfo} txInfo
* @param {Array<TxPrivateKey>} [keys]
*/

/**
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dashtx",
"version": "0.15.3",
"version": "0.16.0",
"description": "Create DASH Transactions with Vanilla JS (0 deps, cross-platform)",
"main": "dashtx.js",
"module": "dashtx.mjs",
Expand Down
27 changes: 26 additions & 1 deletion tests/legacy-draft.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

let DashTx = require("../");

let Secp256k1 = require("@dashincubator/secp256k1");

// generated with https://webinstall.dev/dashmsg
// dashmsg gen --cointype '4c' ./test-1.wif
// dashmsg inspect --cointype '4c' "$(cat ./test-1.wif)"
Expand Down Expand Up @@ -43,7 +45,30 @@ let tests = [
];

async function test() {
let dashTx = DashTx.create();
let keyUtils = {
getPrivateKey: async function (txInput, i) {
let pkhBytes = DashKeys.utils.hexToBytes(txInput.pubKeyHash);
let address = await DashKeys.pkhToAddr(txInput.pubKeyHash);

let yourKeyData = yourWalletKeyMapGoesHere[address];

let privKeyBytes = DashKeys.wifToPrivKey(yourKeyData.wif);
return privKeyBytes;
},
sign: async function (privKeyBytes, txHashBytes) {
let sigOpts = { canonical: true, extraEntropy: true };
let sigBytes = await Secp256k1.sign(txHashBytes, privKeyBytes, sigOpts);

return sigBytes;
},
toPublicKey: async function (privKeyBytes) {
let isCompressed = true;
let pubKeyBytes = Secp256k1.getPublicKey(privKeyBytes, isCompressed);

return pubKeyBytes;
},
};
let dashTx = DashTx.create(keyUtils);

for (let t of tests) {
let exp = t.expected;
Expand Down
53 changes: 27 additions & 26 deletions tests/legacy-finalize-presorted.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,6 @@ let DashTx = require("../");
let DashKeys = require("dashkeys");
let Secp256k1 = require("@dashincubator/secp256k1");

let keyUtils = {
sign: async function (privKeyBytes, hashBytes) {
let sigOpts = {
canonical: true,
extraEntropy: true,
};
let sigBuf = await Secp256k1.sign(hashBytes, privKeyBytes, sigOpts);
return sigBuf;
},
toPublicKey: async function (privKeyBytes) {
return DashKeys.utils.toPublicKey(privKeyBytes);
},
};

// generated with https://webinstall.dev/dashmsg
// dashmsg gen --cointype '4c' ./test-1.wif
// dashmsg inspect --cointype '4c' "$(cat ./test-1.wif)"
Expand Down Expand Up @@ -90,7 +76,31 @@ function genTestVals(name, sats, deterministic) {

async function testAll() {
async function setupAndRunOne(original) {
let keyUtils = {
sign: async function (privKeyBytes, hashBytes) {
let sigOpts = {
canonical: true,
extraEntropy: true,
};
let sigBuf = await Secp256k1.sign(hashBytes, privKeyBytes, sigOpts);
return sigBuf;
},
toPublicKey: async function (privKeyBytes) {
return DashKeys.utils.toPublicKey(privKeyBytes);
},
getPrivateKey: async function (txInput) {
let wif = original.wifs[txInput.address];
if (!wif) {
let msg = `no WIF found for pubKeyAddr '${txInput.address}' (${txInput.satoshis})`;
throw new Error(msg);
}

let privKeyBytes = await DashKeys.wifToPrivKey(wif);
return privKeyBytes;
},
};
let dashTx = DashTx.create(keyUtils);

let t1 = JSON.parse(JSON.stringify(original));
let t2 = JSON.parse(JSON.stringify(original));
let txDraft = dashTx.legacy.draftSingleOutput({
Expand All @@ -101,18 +111,9 @@ async function testAll() {
txDraft.inputs.sort(DashTx.sortInputs);
txDraft.outputs.sort(DashTx.sortOutputs);

let keys = [];
for (let input of txDraft.inputs) {
let pkhBytes = await DashKeys.addrToPkh(input.address);
input.pubKeyHash = DashKeys.utils.bytesToHex(pkhBytes);

let wif = t1.wifs[input.address];
let key = await DashKeys.wifToPrivKey(wif);
if (!key) {
let msg = `no WIF found for pubKeyAddr '${input.address}' (${input.satoshis})`;
throw new Error(msg);
}
keys.push(key);
}

for (let output of txDraft.outputs) {
Expand All @@ -128,7 +129,7 @@ async function testAll() {
}
let myDashTx = DashTx.create(_keyUtils);

await testOne(myDashTx, t2, txDraft, keys, rndIters).catch(function (err) {
await testOne(myDashTx, t2, txDraft, rndIters).catch(function (err) {
console.info(`# failed ${t1.name}`);
console.info(`# txDraft`, txDraft);
if (err.txSummary) {
Expand Down Expand Up @@ -162,12 +163,12 @@ function createNonRndSigner() {
return nonRndSign;
}

async function testOne(myDashTx, original, txDraft, keys, rndIters) {
async function testOne(myDashTx, original, txDraft, rndIters) {
for (let seedIterations = 0; seedIterations < rndIters; seedIterations += 1) {
let t = JSON.parse(JSON.stringify(original));
let exp = t.expected;

let txSummary = await myDashTx.legacy.finalizePresorted(txDraft, keys);
let txSummary = await myDashTx.legacy.finalizePresorted(txDraft);
let txByteSize = txSummary.transaction.length / 2;
// console.log("[DEBUG] txSummary");
// console.log(txByteSize, txSummary.fee);
Expand Down
23 changes: 11 additions & 12 deletions tests/memo.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
let Zora = require("zora");

let Secp256k1 = require("@dashincubator/secp256k1");
let DashKeys = require("dashkeys");

let DashTx = require("../dashtx.js");
let dashTx = DashTx.create({
Expand All @@ -17,7 +16,15 @@ let dashTx = DashTx.create({
return sigBuf;
},
toPublicKey: async function (privKeyBytes) {
return DashKeys.utils.toPublicKey(privKeyBytes);
let isCompressed = true;
let pubKeyBuf = Secp256k1.getPublicKey(privKeyBytes, isCompressed);
return pubKeyBuf;
},
getPrivateKey: async function (txInput) {
let privKeyHex =
"ba0863ae0c162d67ae68a7f1e9dfdb7e3c47a71d397e19d7442f1afef3928511";
let privKeyBytes = DashTx.utils.hexToBytes(privKeyHex);
return privKeyBytes;
},
});

Expand Down Expand Up @@ -78,8 +85,6 @@ Zora.test("memo lengths", function (t) {
});

Zora.test("can create memo tx", async function (t) {
let privKeyHex =
"ba0863ae0c162d67ae68a7f1e9dfdb7e3c47a71d397e19d7442f1afef3928511";
let pkh = "82754a9c935fbfcdda5995a32006a68a8156ee2b";

let txId = "77".repeat(32);
Expand All @@ -98,9 +103,7 @@ Zora.test("can create memo tx", async function (t) {
let changeOutput = { pubKeyHash: pkh };
let txInfo = await DashTx.legacyCreateTx(coins, outputs, changeOutput);

let privKey = DashTx.utils.hexToBytes(privKeyHex);
let keys = [privKey];
let txInfoSigned = await dashTx.hashAndSignAll(txInfo, keys);
let txInfoSigned = await dashTx.hashAndSignAll(txInfo);

let rawtx =
"03000000017777777777777777777777777777777777777777777777777777777777777777000000006b483045022100888db2ea9388e2c29d2480fd3374250cb2242a7dfa0e4bc6d82ac01b58f99dfb02200fe878c74f58eebf234f31a43a17bc6ea1535de6f7f2329ac007107888a39199012103f808bdec4293bf12441ec9a9e61bc3b264c78fcc5ad499ce5f0799f2874e6856ffffffff0200000000000000000e6a0c48656c6c6f2c204461736821484d0000000000001976a91482754a9c935fbfcdda5995a32006a68a8156ee2b88ac00000000";
Expand All @@ -109,8 +112,6 @@ Zora.test("can create memo tx", async function (t) {
});

Zora.test("can create donation tx via memo", async function (t) {
let privKeyHex =
"ba0863ae0c162d67ae68a7f1e9dfdb7e3c47a71d397e19d7442f1afef3928511";
let pkh = "82754a9c935fbfcdda5995a32006a68a8156ee2b";

let txId = "77".repeat(32);
Expand All @@ -127,9 +128,7 @@ Zora.test("can create donation tx via memo", async function (t) {
outputs: outputs,
};

let privKey = DashTx.utils.hexToBytes(privKeyHex);
let keys = [privKey];
let txInfoSigned = await dashTx.hashAndSignAll(txInfo, keys);
let txInfoSigned = await dashTx.hashAndSignAll(txInfo);
let txHex = txInfoSigned.transaction;

let rawtx =
Expand Down
Loading