wallet: create non-templated transaction.

This commit is contained in:
Nodar Chkuaselidze 2018-08-05 22:23:52 +04:00
parent 9472833011
commit c0fb984da6
No known key found for this signature in database
GPG Key ID: 8E1B4DC29040BD90
5 changed files with 116 additions and 2 deletions

View File

@ -9,8 +9,13 @@
- `PUT /wallet/:id` Creating a watch-only wallet now requires an `accountKey`
argument. This is to prevent bcoin from generating keys and addresses the
user can not spend from.
- `POST /wallet/:id/create` Now has a `sign` argument for optional signing
of transactions.
- `POST /wallet/:id/create`
- Now has a `sign` argument for optional signing of transactions.
- Now has a `template` option, that will skip templating inputs when
`sign = false`, but you can enable it if necessary. It does not have an
effect when `sign = true`.
- Exposes `blocks`, which can will be used if there is no `rate` option.
- Exposes `sort` (Default `true`), that can be used to disable BIP69 sorting.
#### RPC

View File

@ -468,13 +468,16 @@ class HTTP extends Server {
const options = {
rate: valid.u64('rate'),
blocks: valid.u32('blocks'),
maxFee: valid.u64('maxFee'),
selection: valid.str('selection'),
smart: valid.bool('smart'),
account: valid.str('account'),
sort: valid.bool('sort'),
subtractFee: valid.bool('subtractFee'),
subtractIndex: valid.i32('subtractIndex'),
depth: valid.u32(['confirmations', 'depth']),
template: valid.bool('template', sign),
outputs: []
};

View File

@ -1236,6 +1236,9 @@ class Wallet extends EventEmitter {
* to avoid sorting), set locktime, and template it.
* @param {Object} options - See {@link Wallet#fund options}.
* @param {Object[]} options.outputs - See {@link MTX#addOutput}.
* @param {Boolean} options.sort - Sort inputs and outputs (BIP69).
* @param {Boolean} options.template - Build scripts for inputs.
* @param {Number} options.locktime - TX locktime
* @returns {Promise} - Returns {@link MTX}.
*/
@ -1281,6 +1284,9 @@ class Wallet extends EventEmitter {
assert(mtx.verifyInputs(this.wdb.state.height + 1),
'TX failed context check.');
if (options.template === false)
return mtx;
const total = await this.template(mtx);
if (total === 0)

View File

@ -264,6 +264,72 @@ describe('HTTP', function() {
});
});
for (const template of [true, false]) {
const suffix = template ? 'with template' : 'without template';
it(`should create and sign transaction ${suffix}`, async () => {
const change = await wallet.createChange('default');
const tx = await wallet.createTX({
template: template, // should not matter, sign = true
sign: true,
outputs: [{
address: change.address,
value: 50000
}]
});
const mtx = MTX.fromJSON(tx);
for (const input of tx.inputs) {
const script = input.script;
assert.notStrictEqual(script, '',
'Input must be signed.');
}
assert.strictEqual(mtx.verify(), true,
'Transaction must be signed.');
});
}
it('should create transaction without template', async () => {
const change = await wallet.createChange('default');
const tx = await wallet.createTX({
sign: false,
outputs: [{
address: change.address,
value: 50000
}]
});
for (const input of tx.inputs) {
const script = input.script;
assert.strictEqual(script.length, 0,
'Input must not be templated.');
}
});
it('should create transaction with template', async () => {
const change = await wallet.createChange('default');
const tx = await wallet.createTX({
sign: false,
template: true,
outputs: [{
address: change.address,
value: 20000
}]
});
for (const input of tx.inputs) {
const script = Buffer.from(input.script, 'hex');
// p2pkh
// 1 (OP_0 placeholder) + 1 (length) + 33 (pubkey)
assert.strictEqual(script.length, 35);
assert.strictEqual(script[0], 0x00,
'First item in stack must be a placeholder OP_0');
}
});
it('should cleanup', async () => {
consensus.COINBASE_MATURITY = 100;
await wallet.close();

View File

@ -1220,6 +1220,40 @@ describe('Wallet', function() {
assert(t3.verify());
});
for (const witness of [true, false]) {
it(`should create non-templated tx (witness=${witness})`, async () => {
const wallet = await wdb.create({ witness });
// Fund wallet
const t1 = new MTX();
t1.addInput(dummyInput());
t1.addOutput(await wallet.receiveAddress(), 500000);
await wdb.addTX(t1.toTX());
const options = {
rate: 10000,
round: true,
outputs: [{
address: await wallet.receiveAddress(),
value: 7000
}],
template: false
};
const t2 = await wallet.createTX(options);
assert(t2, 'Could not create tx.');
for (const input of t2.inputs) {
const {script, witness} = input;
assert.strictEqual(script.length, 0, 'Input is templated.');
assert.strictEqual(witness.length, 0, 'Input is templated.');
}
});
}
it('should get range of txs', async () => {
const wallet = currentWallet;
const txs = await wallet.getRange(null, {