Skip to content

Commit

Permalink
Merge PR #845 from 'nodech/http-races'
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Aug 31, 2023
2 parents 61ae19c + e49a8fc commit 7aeb668
Show file tree
Hide file tree
Showing 4 changed files with 585 additions and 56 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# HSD Release Notes & Changelog

## Unreleased

### Wallet API:

- HTTP Changes:
- All transaction creating endpoints now accept `hardFee` for specifying the
exact fee.
- All transaction sending endpoints now fundlock/queue tx creation. (no more
conflicting transactions)

## v6.0.0

### Node and Wallet HTTP API
Expand Down
148 changes: 95 additions & 53 deletions lib/wallet/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,9 @@ class HTTP extends Server {
// Send TX
this.post('/wallet/:id/send', async (req, res) => {
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');

const options = TransactionOptions.fromValidator(valid);
const tx = await req.wallet.send(options, passphrase);
const tx = await req.wallet.send(options);

const details = await req.wallet.getDetails(tx.hash());

Expand All @@ -470,14 +469,15 @@ class HTTP extends Server {
// Create TX
this.post('/wallet/:id/create', async (req, res) => {
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const sign = valid.bool('sign', true);

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const options = TransactionOptions.fromValidator(valid);
const tx = await req.wallet.createTX(options);

if (sign)
await req.wallet.sign(tx, passphrase);
await req.wallet.sign(tx, options.passphrase);

const json = tx.getJSON(this.network);

Expand Down Expand Up @@ -1068,23 +1068,26 @@ class HTTP extends Server {
this.post('/wallet/:id/open', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(name, 'Name is required.');
enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createOpen(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendOpen(name, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createOpen(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1100,7 +1103,6 @@ class HTTP extends Server {
const name = valid.str('name');
const bid = valid.u64('bid');
const lockup = valid.u64('lockup');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

Expand All @@ -1110,15 +1112,19 @@ class HTTP extends Server {
enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createBid(name, bid, lockup, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendBid(name, bid, lockup, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createBid(name, bid, lockup, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand Down Expand Up @@ -1180,29 +1186,39 @@ class HTTP extends Server {
this.post('/wallet/:id/reveal', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);

let mtx;
if (broadcast) {
let tx;

if (!name) {
mtx = await req.wallet.createRevealAll(options);
} else {
mtx = await req.wallet.createReveal(name, options);
}
if (name) {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendReveal(name, options);
} else {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendRevealAll(options);
}

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
return res.json(200, tx.getJSON(this.network));
}

let mtx;

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
if (name) {
mtx = await req.wallet.createReveal(name, options);
} else {
mtx = await req.wallet.createRevealAll(options);
}

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1216,29 +1232,39 @@ class HTTP extends Server {
this.post('/wallet/:id/redeem', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);

if (broadcast) {
let tx;

if (name) {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendRedeem(name, options);
} else {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendRedeemAll(options);
}

return res.json(200, tx.getJSON(this.network));
}

let mtx;

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
if (!name) {
mtx = await req.wallet.createRedeemAll(options);
} else {
mtx = await req.wallet.createRedeem(name, options);
}

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
return res.json(200, tx.getJSON(this.network));
}

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1253,7 +1279,6 @@ class HTTP extends Server {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const data = valid.obj('data');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

Expand All @@ -1269,15 +1294,19 @@ class HTTP extends Server {
}

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createUpdate(name, resource, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendUpdate(name, resource, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createUpdate(name, resource, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1291,23 +1320,24 @@ class HTTP extends Server {
this.post('/wallet/:id/renewal', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createRenewal(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendRenewal(name, options);
return res.json(200, tx.getJSON(this.network));
}

const mtx = await req.wallet.createRenewal(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1322,7 +1352,6 @@ class HTTP extends Server {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const address = valid.str('address');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

Expand All @@ -1332,15 +1361,19 @@ class HTTP extends Server {

const addr = Address.fromString(address, this.network);
const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createTransfer(name, addr, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendTransfer(name, addr, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createTransfer(name, addr, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1354,23 +1387,26 @@ class HTTP extends Server {
this.post('/wallet/:id/cancel', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createCancel(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendCancel(name, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createCancel(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1384,23 +1420,24 @@ class HTTP extends Server {
this.post('/wallet/:id/finalize', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createFinalize(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendFinalize(name, options);
return res.json(200, tx.getJSON(this.network));
}

const mtx = await req.wallet.createFinalize(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1414,23 +1451,26 @@ class HTTP extends Server {
this.post('/wallet/:id/revoke', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createRevoke(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendRevoke(name, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createRevoke(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand Down Expand Up @@ -1814,6 +1854,8 @@ class TransactionOptions {
this.subtractIndex = valid.i32('subtractIndex');
this.depth = valid.u32(['confirmations', 'depth']);
this.paths = valid.bool('paths');
this.passphrase = valid.str('passphrase');
this.hardFee = valid.u64('hardFee'),
this.outputs = [];

if (valid.has('outputs')) {
Expand Down
Loading

0 comments on commit 7aeb668

Please sign in to comment.