From 6ad621cace241d55daf9e79ac834dac1a56b355f Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 1 Feb 2016 11:39:38 -0800 Subject: [PATCH] api: rename methods, properties. add legacy support. --- README.md | 140 ++++++++++++----------- lib/bcoin/block.js | 13 ++- lib/bcoin/chain.js | 2 +- lib/bcoin/input.js | 77 +++++++++---- lib/bcoin/miner.js | 6 +- lib/bcoin/output.js | 6 +- lib/bcoin/pool.js | 6 +- lib/bcoin/protocol/framer.js | 8 +- lib/bcoin/protocol/parser.js | 6 +- lib/bcoin/script.js | 28 ++--- lib/bcoin/tx-pool.js | 48 ++++---- lib/bcoin/tx.js | 215 ++++++++++++++++++++--------------- lib/bcoin/wallet.js | 81 +++++++------ 13 files changed, 362 insertions(+), 274 deletions(-) diff --git a/README.md b/README.md index f9a26763..003dde46 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ pool.on('watched', function(tx, peer) { // Look for balance changes wallet.on('balance', function() { - utils.print('Wallet balance updated: %s', utils.btc(wallet.balance())); + utils.print('Wallet balance updated: %s', utils.btc(wallet.getBalance())); }); // Start the getheaders sync @@ -135,7 +135,7 @@ fs.writeFileSync(process.env.HOME + '/my-new-wallet.json', var tx = bcoin.tx(); // Add an output, send some money to our new wallet -tx.output({ +tx.addOutput({ address: receiver.getAddress(), // Every satoshi value in bcoin is // a big number, so we can convert @@ -148,8 +148,8 @@ tx.output({ // Fill the transaction inputs with the // necessary unspents (hopefully we have them!). -tx.fillUnspent( - wallet.unspent(), // Our unspents to choose from +tx.fill( + wallet.getUnspent(), // Our unspents to choose from wallet.getAddress(), // Our change address (warning: address re-use) null // We could put a hard fee here, but lets let bcoin figure it out ); @@ -252,7 +252,7 @@ utils.assert(buyer.getScriptAddress() === mediator.getScriptAddress()); utils.print('Created 2-of-3 wallet with address: %s', buyer.getScriptAddress()); // Create a fake coinbase for buyer to use as his funds -var coinbase = bcoin.tx().output(buyer.getKeyAddress(), utils.satoshi('50.0')); +var coinbase = bcoin.tx().addOutput(buyer.getKeyAddress(), utils.satoshi('50.0')); buyer.addTX(coinbase); // Now let's create a tx as the buyer. @@ -261,13 +261,14 @@ var btx = bcoin.tx(); // Send 25 BTC to the shared wallet // to buy something from seller. -btx.output({ +btx.addOutput({ address: buyer.getScriptAddress(), value: utils.satoshi('25.0') }); // Fill the unspents and sign -buyer.fillUnspent(btx); +if (!buyer.fill(btx)) + throw new Error('Not enough funds'); buyer.sign(btx); // Buyer sends his funds to the 2-of-3 wallet @@ -280,7 +281,7 @@ seller.addTX(btx); var stx = bcoin.tx(); // Seller wants to send the BTC to himself -stx.output({ +stx.addOutput({ address: seller.getKeyAddress(), value: utils.satoshi('25.0') // Subtract the fee @@ -291,13 +292,13 @@ stx.output({ // Give the mediator a little something, // since he's such a cool guy. -stx.output({ +stx.addOutput({ address: mediator.getKeyAddress(), value: utils.satoshi('1.0') }); // Add the buyer's utxo as the input -stx.input(btx, 0); +stx.addInput(btx, 0); // Add _one_ signature to the tx seller.sign(stx); @@ -329,7 +330,7 @@ and human-writable. For example, a standard pay-to-pubkey script would look like: ``` js -tx.output({ +tx.addOutput({ value: new bn(100000), script: [ 'dup', @@ -347,9 +348,9 @@ prefixes removed. Pushdata ops are represented with Arrays. The above script could be redeemed with: ``` js -tx2.input({ - out: { tx: tx, hash: tx.hash('hex'), index: 0 }, - seq: 0xffffffff, +tx2.addInput({ + prevout: { tx: tx, hash: tx.hash('hex'), index: 0 }, + sequence: 0xffffffff, script: [ signature, // Byte Array publicKey // Byte Array @@ -408,14 +409,14 @@ var wallet = bcoin.wallet({ ] }); console.log(wallet.getScriptAddress()); -var tx1 = bcoin.tx().output(wallet.getScriptAddress(), new bn(100000)); +var tx1 = bcoin.tx().addOutput(wallet.getScriptAddress(), new bn(100000)); ``` Which would be redeemed with: ``` js -tx2.input({ - out: { tx: tx1, hash: tx1.hash('hex'), index: 0 }, +tx2.addInput({ + prevout: { tx: tx1, hash: tx1.hash('hex'), index: 0 }, script: [ 2, // Redeem script: @@ -437,7 +438,7 @@ var bn = bcoin.bn; ... // Add an output with 100,000 satoshis as a value. -tx.output(wallet.getKeyAddress(), new bn(100000)); +tx.addOutput(wallet.getKeyAddress(), new bn(100000)); ``` To make this easier to deal with, bcoin has two helper functions: `utils.btc()` @@ -642,6 +643,7 @@ Subtype can be `block`, `merkleblock`, or `header`. validation will fail. - __isGenesis()__ - Returns true if block is the genesis block of the network. before the reference node. +- __getSize()__ - Return block size in bytes. - __getHeight()__ - Returns height in the blockchain. Returns `-1` if block is not present in the chain. node. @@ -933,7 +935,7 @@ Usage: `bcoin.input([options])` - __out.hash__ - Previous output's txid as a hex string. - __out.index__ - Previous output's index. - __script__ - Array of opcodes. -- __seq__ - Input's nSequence, `0xffffffff` by default. +- __sequence__ - Input's nSequence, `0xffffffff` by default. ##### Properties: @@ -968,8 +970,8 @@ which parse the script and grab the previous output data and cache it as - __scriptaddress__ - The p2sh address. - __m__ - `m` value (required signatures). - __n__ - `n` value (number of keys). -- __lock__ - The OP_CHECKLOCKTIMEVERIFY locktime if present (NOTE: This will only - grab the first value and not deal with OP_IF statements, etc). +- __lockTime__ - The OP_CHECKLOCKTIMEVERIFY locktime if present (NOTE: This + will only grab the first value and not deal with OP_IF statements, etc). - __flags__ - Coinbase flags if present. - __text__ - Coinbase flags converted to UTF-8, if present. - __output__ - Previous Output object. @@ -1034,8 +1036,8 @@ script and cache it as `_data`. - __scriptaddress__ - The p2sh address. - __m__ - `m` value (required signatures). - __n__ - `n` value (number of keys). -- __lock__ - The OP_CHECKLOCKTIMEVERIFY locktime if present (NOTE: This will only - grab the first value and not deal with OP_IF statements, etc). +- __lockTime__ - The OP_CHECKLOCKTIMEVERIFY locktime if present (NOTE: This + will only grab the first value and not deal with OP_IF statements, etc). - __flags__ - `nulldata` data. - __text__ - `nulldata` data converted to UTF-8. @@ -1406,10 +1408,10 @@ Usage: `bcoin.txPool(wallet)` - Inherits all from EventEmitter. - __add(tx)__ - Add TX to the pool. -- __all()__ - Return all TXes in the pool owned by wallet. -- __unspent()__ - Return all TXes with unspent outputs, owned by wallet. -- __pending()__ - Return all 0-confirmation transactions. -- __balance()__ - Return total balance of TX pool. +- __getAll()__ - Return all TXes in the pool owned by wallet. +- __getUnspent()__ - Return all TXes with unspent outputs, owned by wallet. +- __getPending()__ - Return all 0-confirmation transactions. +- __getBalance()__ - Return total balance of TX pool. - __toJSON()__ - Return TX pool in serialized JSON format. - __fromJSON()__ - Load TX pool from serialized JSON format. @@ -1427,9 +1429,9 @@ Usage: `bcoin.tx([options], [block])` ##### Options: - __version__ - Transaction version (default: 1). -- __inputs__ - Array of input objects with `tx.input()` options. -- __outputs__ - Array of output objects with `tx.output()` options. -- __lock__ - nLockTime value. +- __inputs__ - Array of input objects with `tx.addInput()` options. +- __outputs__ - Array of output objects with `tx.addOutput()` options. +- __lockTime__ - nLockTime value. - __ts__ - Timestamp (set by `block` if passed in arguments - spv-mode). - __block__ - Block hash (Set by `block` if passed in arguments - spv-mode). - __network__ - Should be `true` if TX came in from the network. @@ -1468,34 +1470,35 @@ Usage: `bcoin.tx([options], [block])` - __render([force])__ - Serialize transaction. Returns raw byte array. Will return raw data passed in from the network if available. Set `force=true` to force serialization. -- __size()__ - Return serializzed transaction size in bytes. -- __input(options)__ - Add an input to the transaction. Options can be an Input - object (see above), in the form of an Input object (containing properties - `out.tx`, `out.hash`, `out.index`, `script`, and `seq`). - - `input()` can handle many different arguments in the forms of: - - `tx.input(tx, index)` - - `tx.input(txHash, index)` - - `tx.input(input)` - - `tx.input({ hash: hash, index: index })` - - `tx.input({ tx: tx, index: index })` +- __getSize()__ - Return serializzed transaction size in bytes. +- __addInput(options)__ - Add an input to the transaction. Options can be an + Input object (see above), in the form of an Input object (containing + properties `prevout.tx`, `prevout.hash`, `prevout.index`, `script`, and + `sequence`). + - `addInput()` can handle many different arguments in the forms of: + - `tx.addInput(tx, index)` + - `tx.addInput(txHash, index)` + - `tx.addInput(input)` + - `tx.addInput({ hash: hash, index: index })` + - `tx.addInput({ tx: tx, index: index })` - __scriptInput(index/input, pub, redeem)__ - Initialize the input scripts based on previous output script type. `n` signatures will be added. Signatures will be null dummies (empty signature slots) until `signInput()` is called. `pub` (the public key) and `redeem` (raw redeem script) should always be passed in if there is a pubkeyhash or scripthash output being redeemed. Will not overwrite existing input scripts. -- __signature(index/input, key, [type])__ - Create a signature for the desired - input using `key` as the private key and `type` as the sighash type. Sighash - type can be a number or a string (`all`, `single`, or `none`). Returns a DER - signature byte array. +- __createSignature(index/input, key, [type])__ - Create a signature for the + desired input using `key` as the private key and `type` as the sighash type. + Sighash type can be a number or a string (`all`, `single`, or `none`). + Returns a DER signature byte array. - __signInput(index/input, key, [type])__ - Sign the desired input and place the signature in an empty signature slot. Finalize the input script and reduce signature slots to `m` once the minimum amount of signatures has been reached. - __scriptSig(index/input, key, pub, redeem, type)__ - Execute `scriptInput` _and_ `signInput`. -- __output(options), output(output), output(address, value)__ - Add an output to the - transaction. +- __addOutput(options), addOutput(output), addOutput(address, value)__ - Add an + output to the transaction. - `options` can be in the form of: { @@ -1507,11 +1510,11 @@ Usage: `bcoin.tx([options], [block])` n: [n value], flags: [nulldata], scripthash: [true or false], - lock: [locktime for checklocktimeverify] + lockTime: [locktime for checklocktimeverify] } - __scriptOutput(index/output, options)__ - Compile an output script for the - output based on the same options `output()` handles. + output based on the same options `addOutput()` handles. - __signatureHash(index/input, s, type)__ - Return the to-be-signed hash of the transaction for the desired input. Must pass in previous output subscript as `s`, as well as the sighash type (number or string of `all`, `none`, or @@ -1525,9 +1528,9 @@ Usage: `bcoin.tx([options], [block])` - __isCoinbase()__ - Returns true if TX is a coinbase. - __maxSize()__ - Estimate the size of the transaction in bytes (works before input scripts are compiled and signed). Useful for fee calculation. -- __getUnspent(unspent, changeAddress, [fee])__ - Determine which unspents to +- __getInputs(unspent, changeAddress, [fee])__ - Determine which unspents to use from `unspent` (an array of possible unspents, usually returned by - `wallet.unspent()`). Calculates the fee and chooses unspents based on the + `wallet.getUnspent()`). Calculates the fee and chooses unspents based on the total value required for the transaction. A hard `fee` can be passed in (satoshis/big number) which will skip the fee calculation. Calculates the necessary change. Returns an object in the form of: @@ -1542,22 +1545,22 @@ Usage: `bcoin.tx([options], [block])` } `inputs` will be `null` if not enough funds were available. - __NOTE:__ `getUnspent()` should only be called once all outputs have been added. -- __fillUnspent(unspent, [changeAddress], [fee])__ - Calls `getUnspent()` and + __NOTE:__ `getInputs()` should only be called once all outputs have been added. +- __fill(unspent, [changeAddress], [fee])__ - Calls `getInputs()` and adds the created inputs to the transaction. Adds a change output if - necessary. Returns the same result value as `getUnspent()`. __NOTE:__ Should + necessary. Returns the same result value as `getInputs()`. __NOTE:__ Should only be called once all outputs have been added. - __getFee()__ - Returns the fee for transaction. -- __funds(side)__ - Returns the total funds for a side of the transaction - `'in'` or `'out'`. -- __setLockTime(lock)__ - Sets a locktime for the transaction. Will set the +- __getFunds(side)__ - Returns the total funds for a side of the transaction + `'input'` or `'output'`. +- __setLockTime(lockTime)__ - Sets a locktime for the transaction. Will set the nSequences accordingly. - __increaseFee(fee)__ - Increase fee to a hard fee. Opts transaction in for replace-by-fee. __NOTE:__ Transaction must be rescripted and resigned before broadcasting. -- __fill(wallet/txpool/object)__ - Fills all the transaction's inputs with the - appropriate previous outputs using the available transactions in a wallet, - txpool, or an object with txids as its keys and txs as its values. +- __fillPrevout(wallet/txpool/object)__ - Fills all the transaction's inputs + with the appropriate previous outputs using the available transactions in a + wallet, txpool, or an object with txids as its keys and txs as its values. - __isFull()__ - Returns true if the TX has all previous output references. - __isFinal(height, ts)__ - Mimics the bitcoind `IsFinalTx()` function. Checks the locktime and input sequences. Returns true or false. @@ -1616,7 +1619,7 @@ Usage: `bcoin.wallet(options)` ##### Events: -- __balance(balance)__ - Emitted when balance is updated. `balance` is in +- __getBalance(balance)__ - Emitted when balance is updated. `balance` is in satoshis (big number). - __tx(tx)__ - Emitted when a TX is added to the wallet's TXPool. - __load(ts)__ - Emitted when the TXPool is finished loading. `ts` is the @@ -1646,9 +1649,10 @@ Usage: `bcoin.wallet(options)` this wallet. If `index` is not present, all outputs will be tested. - __ownInput(tx, [index])__ - Check to see if input at `index` pertains to this wallet. If `index` is not present, all inputs will be tested. -- __fillUnspent(tx, [changeAddress], [fee])__ - Fill tx with inputs necessary - for total output value. Uses `wallet.unspent()` as the unspent list. -- __fillTX(tx)__ - "Fill" a transactions' inputs with references to its +- __fill(tx, [changeAddress], [fee])__ - Fill tx with inputs necessary for + total output value. Uses `wallet.getUnspent()` as the unspent list. Returns true + if successfully filled necessary funds. +- __fillPrevout(tx)__ - "Fill" a transactions' inputs with references to its previous outputs if available. - __scriptInputs(tx)__ - Compile necessary scripts for inputs (with OP_0 where the signatures should be). Will not overwrite existing input scripts. @@ -1657,13 +1661,11 @@ Usage: `bcoin.wallet(options)` - __sign(tx)__ - Equivalent to calling both `scriptInputs(tx)` and `signInputs(tx)` in one go. - __addTX(tx)__ - Add a transaction to the wallet's TXPool. -- __all()__ - Returns all transactions from the TXPool. -- __unspent()__ - Returns all TXes with unspent outputs from the TXPool. -- __pending()__ - Returns all TXes in the TXPool that have yet to be included +- __getAll()__ - Returns all transactions from the TXPool. +- __getUnspent()__ - Returns all TXes with unspent outputs from the TXPool. +- __getPending()__ - Returns all TXes in the TXPool that have yet to be included in a block. -- __balance()__ - Returns total balance of the TXPool. -- __fill(tx)__ - Attempt to `fillUnspent(tx)`. Return `null` if failed to reach - total output value. Return `tx` if successful. +- __getBalance()__ - Returns total balance of the TXPool. - __toAddress()__ - Return blockchain-explorer-like data in the format of: { diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 6ef5c35f..e9c97c4e 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -128,10 +128,13 @@ Block.prototype.render = function render() { return bcoin.protocol.framer.block(this, this.subtype); }; -Block.prototype.size = function size() { +Block.prototype.getSize = function getSize() { return this._size || this.render().length; }; +// Legacy +Block.prototype.size = Block.prototype.getSize; + Block.prototype.hasTX = function hasTX(hash) { return this.tx.indexOf(hash) !== -1; }; @@ -255,7 +258,7 @@ Block.prototype._verify = function _verify() { // Size can't be bigger than MAX_BLOCK_SIZE if (this.txs.length > constants.block.maxSize - || this.size() > constants.block.maxSize) { + || this.getSize() > constants.block.maxSize) { utils.debug('Block is too large: %s', this.rhash); return false; } @@ -456,10 +459,10 @@ Block.prototype.verifyContext = function verifyContext() { // We need the previous output in order // to verify the script. - if (!input.out.tx) + if (!input.prevout.tx) continue; - assert(input.out.tx); + assert(input.prevout.tx); // Verify the script if (!tx.verify(j, true, flags)) { @@ -468,7 +471,7 @@ Block.prototype.verifyContext = function verifyContext() { } // Ensure tx is not double spending an output - // if (this.chain.isSpent(input.out.hash, input.out.index)) { + // if (this.chain.isSpent(input.prevout.hash, input.prevout.index)) { // utils.debug('Block is using spent inputs: %s', this.rhash); // return false; // } diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 78cd3dbc..7a70533a 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -519,7 +519,7 @@ Chain.prototype.hashRange = function hashRange(start, end) { return hashes; }; -Chain.prototype.locatorHashes = function locatorHashes(start) { +Chain.prototype.getLocator = function getLocator(start) { var hashes = []; var top = this.height(); var step = 1; diff --git a/lib/bcoin/input.js b/lib/bcoin/input.js index 1c5c3e32..105da862 100644 --- a/lib/bcoin/input.js +++ b/lib/bcoin/input.js @@ -14,25 +14,50 @@ var constants = bcoin.protocol.constants; */ function Input(options) { + var prevout; + if (!(this instanceof Input)) return new Input(options); - this.out = { - tx: options.out.tx || null, - hash: options.out.hash, - index: options.out.index + prevout = options.prevout || options.out; + + this.prevout = { + tx: prevout.tx || null, + hash: prevout.hash, + index: prevout.index }; - if (typeof this.out.hash !== 'string') - this.out.hash = utils.toHex(this.out.hash); + if (utils.isBuffer(this.prevout.hash)) + this.prevout.hash = utils.toHex(this.prevout.hash); this.script = options.script ? options.script.slice() : []; - this.seq = options.seq === undefined ? 0xffffffff : options.seq; + this.sequence = options.sequence == null ? 0xffffffff : options.sequence; + + // Legacy + if (options.seq != null) + this.sequence = options.seq; if (options.script && options.script._raw) utils.hidden(this.script, '_raw', options.script._raw); } +// Legacy +Input.prototype.__defineSetter__('seq', function(sequence) { + return this.sequence = sequence; +}); + +Input.prototype.__defineGetter__('seq', function() { + return this.sequence; +}); + +Input.prototype.__defineSetter__('out', function(prevout) { + return this.prevout = prevout; +}); + +Input.prototype.__defineGetter__('out', function() { + return this.prevout; +}); + Input.prototype.__defineGetter__('data', function() { var data; @@ -41,7 +66,7 @@ Input.prototype.__defineGetter__('data', function() { data = Input.getData(this); - if (this.script.length && this.out.tx) + if (this.script.length && this.prevout.tx) utils.hidden(this, '_data', data); return data; @@ -107,10 +132,10 @@ Input.prototype.__defineGetter__('n', function() { return this.data.n || this.m; }); -Input.prototype.__defineGetter__('lock', function() { +Input.prototype.__defineGetter__('lockTime', function() { if (!this.output) return 0; - return this.output.lock; + return this.output.lockTime; }); Input.prototype.__defineGetter__('flags', function() { @@ -122,9 +147,9 @@ Input.prototype.__defineGetter__('text', function() { }); Input.prototype.__defineGetter__('output', function() { - if (!this.out.tx) + if (!this.prevout.tx) return; - return this.out.tx.outputs[this.out.index]; + return this.prevout.tx.outputs[this.prevout.index]; }); Input.prototype.__defineGetter__('value', function() { @@ -134,7 +159,7 @@ Input.prototype.__defineGetter__('value', function() { }); Input.prototype.__defineGetter__('tx', function() { - return this.out.tx; + return this.prevout.tx; }); Input.prototype.__defineGetter__('addr', function() { @@ -182,7 +207,7 @@ Input.prototype.__defineGetter__('scriptaddr', function() { // height: Number, // flags: Array, // text: String, -// lock: Number, +// lockTime: Number, // value: bn, // script: Array, // seq: Number, @@ -204,12 +229,12 @@ Input.getData = function getData(input) { seq: input.seq }; - if (input.out) { - def.prev = input.out.hash; - def.index = input.out.index; + if (input.prevout) { + def.prev = input.prevout.hash; + def.index = input.prevout.index; } - if (input.out && +input.out.hash === 0) { + if (input.prevout && +input.prevout.hash === 0) { data = bcoin.script.getCoinbaseData(input.script); return utils.merge(def, data, { type: 'coinbase', @@ -217,8 +242,8 @@ Input.getData = function getData(input) { }); } - if (input.out && input.out.tx) { - output = input.out.tx.outputs[input.out.index]; + if (input.prevout && input.prevout.tx) { + output = input.prevout.tx.outputs[input.prevout.index]; if (output) { data = bcoin.script.getInputData(input.script, output.script); data.value = output.value; @@ -229,6 +254,10 @@ Input.getData = function getData(input) { return utils.merge(def, bcoin.script.getInputData(input.script)); }; +Input.prototype.isFinal = function isFinal() { + return this.sequence === 0xffffffff; +}; + Input.prototype.getID = function getID() { var data = bcoin.script.encode(this.script); var hash = utils.toHex(utils.ripesha(data)); @@ -240,9 +269,9 @@ Input.prototype.inspect = function inspect() { ? this.output.inspect() : { type: 'unknown', value: '0.0' }; - output.hash = this.out.hash; - output.rhash = utils.revHex(this.out.hash); - output.index = this.out.index; + output.hash = this.prevout.hash; + output.rhash = utils.revHex(this.prevout.hash); + output.index = this.prevout.index; return { type: this.type, @@ -254,7 +283,7 @@ Input.prototype.inspect = function inspect() { scriptaddress: this.scriptaddress, signatures: this.signatures.map(utils.toHex), text: this.text, - lock: this.lock, + lockTime: this.lockTime, value: utils.btc(output.value), script: bcoin.script.format(this.script)[0], redeem: this.redeem ? bcoin.script.format(this.redeem)[0] : null, diff --git a/lib/bcoin/miner.js b/lib/bcoin/miner.js index ff720a5d..e0168c34 100644 --- a/lib/bcoin/miner.js +++ b/lib/bcoin/miner.js @@ -142,7 +142,7 @@ Miner.prototype.addTX = function addTX(tx) { var full, ts; full = this.index.inputs.every(function(input) { - return !!input.out.tx; + return !!input.prevout.tx; }); // Cannot calculate fee if we don't have the prev_out. @@ -200,7 +200,7 @@ Miner.prototype.createBlock = function createBlock(tx) { coinbase = bcoin.tx(); coinbase.input({ - out: { + prevout: { hash: utils.toHex(constants.zeroHash), index: 0xffffffff }, @@ -226,7 +226,7 @@ Miner.prototype.createBlock = function createBlock(tx) { if (script.size(coinbase.inputs[0].script) > 100) throw new Error('Coinbase script is too large'); - coinbase.output({ + coinbase.addOutput({ address: this.address, value: new bn(0) }); diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index c0d9ac4e..bd18eb30 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -105,7 +105,7 @@ Output.prototype.__defineGetter__('n', function() { return this.data.n || this.m; }); -Output.prototype.__defineGetter__('lock', function() { +Output.prototype.__defineGetter__('lockTime', function() { return bcoin.script.getLockTime(this.script); }); @@ -162,7 +162,7 @@ Output.prototype.__defineGetter__('scriptaddr', function() { // height: Number, // flags: Array, // text: String, -// lock: Number, +// lockTime: Number, // value: bn, // script: Array, // seq: Number, @@ -203,7 +203,7 @@ Output.prototype.inspect = function inspect() { m: this.m, n: this.n, text: this.text, - lock: this.lock, + lockTime: this.lockTime, value: utils.btc(this.value), script: bcoin.script.format(this.script)[0] }; diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 4d8af57c..a1aaeced 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -1008,7 +1008,7 @@ Pool.prototype.isWatched = function(tx, bloom) { // 4. Test data elements in input scripts for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; - prev = input.out.hash; + prev = input.prevout.hash; if (typeof prev === 'string') prev = utils.toArray(prev, 'hex'); @@ -1018,8 +1018,8 @@ Pool.prototype.isWatched = function(tx, bloom) { return true; // Test the prev_out script - if (input.out.tx) { - prev = input.out.tx.outputs[input.out.index]; + if (input.prevout.tx) { + prev = input.prevout.tx.outputs[input.prevout.index]; if (testScript(prev.script)) return true; } diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index d6a0d63a..9e7c0e3f 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -280,14 +280,14 @@ Framer.tx = function tx(tx) { for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; - off += utils.copy(utils.toArray(input.out.hash, 'hex'), p, off, true); - off += utils.writeU32(p, input.out.index, off); + off += utils.copy(utils.toArray(input.prevout.hash, 'hex'), p, off, true); + off += utils.writeU32(p, input.prevout.index, off); s = bcoin.script.encode(input.script); off += utils.writeIntv(p, s.length, off); off += utils.copy(s, p, off, true); - off += utils.writeU32(p, input.seq, off); + off += utils.writeU32(p, input.sequence, off); } off += utils.writeIntv(p, tx.outputs.length, off); @@ -301,7 +301,7 @@ Framer.tx = function tx(tx) { off += utils.writeIntv(p, s.length, off); off += utils.copy(s, p, off, true); } - off += utils.writeU32(p, tx.lock, off); + off += utils.writeU32(p, tx.lockTime, off); return p; }; diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index a8767d5b..644ac74b 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -373,12 +373,12 @@ Parser.prototype.parseTXIn = function parseTXIn(p) { return { size: off + scriptLen + 4, - out: { + prevout: { hash: utils.toArray(p.slice(0, 32)), index: utils.readU32(p, 32) }, script: bcoin.script.decode(utils.toArray(p.slice(off, off + scriptLen))), - seq: utils.readU32(p, off + scriptLen) + sequence: utils.readU32(p, off + scriptLen) }; }; @@ -461,7 +461,7 @@ Parser.prototype.parseTX = function parseTX(p) { version: utils.read32(p, 0), inputs: txIn, outputs: txOut, - lock: utils.readU32(p, off), + lockTime: utils.readU32(p, off), _off: off + 4, _size: p.length }; diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 8e41781e..ee529fba 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -386,7 +386,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) { var key, sig, type, subscript, hash; var keys, i, j, m; var succ; - var lock, threshold; + var lockTime, threshold; var evalScript; stack.alt = stack.alt || []; @@ -934,28 +934,28 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) { if (!tx || stack.length === 0) return false; - lock = stack[stack.length - 1]; + lockTime = stack[stack.length - 1]; - if (!Array.isArray(lock)) + if (!Array.isArray(lockTime)) return false; - if (lock.length > 6) + if (lockTime.length > 6) return false; - lock = script.num(lock, true); + lockTime = script.num(lockTime, true); - if (lock < 0) + if (lockTime < 0) return false; threshold = constants.locktimeThreshold; if (!( - (tx.lock < threshold && lock < threshold) - || (tx.lock >= threshold && lock >= threshold) + (tx.lockTime < threshold && lockTime < threshold) + || (tx.lockTime >= threshold && lockTime >= threshold) )) { return false; } - if (lock > tx.lock) + if (lockTime > tx.lockTime) return false; if (!tx.inputs[index] || tx.inputs[index].seq === 0xffffffff) @@ -1312,7 +1312,7 @@ script.getInputData = function getData(s, prev) { }; script._getInputData = function _getInputData(s, type) { - var sig, key, hash, raw, redeem, lock, hash, address, input, output; + var sig, key, hash, raw, redeem, lockTime, hash, address, input, output; assert(typeof type === 'string'); @@ -1355,7 +1355,7 @@ script._getInputData = function _getInputData(s, type) { if (type === 'scripthash') { raw = s[s.length - 1]; redeem = script.decode(raw); - lock = script.getLockTime(redeem); + lockTime = script.getLockTime(redeem); hash = bcoin.wallet.key2hash(raw); address = bcoin.wallet.hash2addr(hash, 'scripthash'); output = script.getOutputData(script.getSubscript(redeem)); @@ -1368,7 +1368,7 @@ script._getInputData = function _getInputData(s, type) { redeem: redeem, scripthash: hash, scriptaddress: address, - lock: lock + lockTime: lockTime }); } @@ -2063,8 +2063,8 @@ script.format = function format(input, output) { scripts.push(output); } else if (input) { scripts.push(input.script); - if (input.out.tx && input.out.tx.outputs[input.out.index]) { - prev = input.out.tx.outputs[input.out.index].script; + if (input.prevout.tx && input.prevout.tx.outputs[input.prevout.index]) { + prev = input.prevout.tx.outputs[input.prevout.index].script; scripts.push(prev); if (script.isScripthash(prev)) { redeem = script.decode(input.script[input.script.length - 1]); diff --git a/lib/bcoin/tx-pool.js b/lib/bcoin/tx-pool.js index 8a38fb22..1cb43d9d 100644 --- a/lib/bcoin/tx-pool.js +++ b/lib/bcoin/tx-pool.js @@ -93,20 +93,20 @@ TXPool.prototype.add = function add(tx, noWrite) { // Consume unspent money or add orphans for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; - key = input.out.hash + '/' + input.out.index; + key = input.prevout.hash + '/' + input.prevout.index; unspent = this._unspent[key]; - if (!input.out.tx && this._all[input.out.hash]) - input.out.tx = this._all[input.out.hash]; + if (!input.prevout.tx && this._all[input.prevout.hash]) + input.prevout.tx = this._all[input.prevout.hash]; if (unspent) { // Add TX to inputs and spend money index = tx._inputIndex(unspent.tx.hash('hex'), unspent.index); assert(index !== -1); assert(tx.inputs[index] === input); - assert(tx.inputs[index].out.hash === unspent.tx.hash('hex')); - assert(tx.inputs[index].out.index === unspent.index); - input.out.tx = unspent.tx; + assert(tx.inputs[index].prevout.hash === unspent.tx.hash('hex')); + assert(tx.inputs[index].prevout.index === unspent.index); + input.prevout.tx = unspent.tx; // Skip invalid transactions if (!tx.verify(index)) @@ -123,13 +123,13 @@ TXPool.prototype.add = function add(tx, noWrite) { // signature checking code to ownInput for p2sh and p2pk, // we could in theory use ownInput here (and down below) // instead. - if (input.out.tx) { - if (!this._wallet.ownOutput(input.out.tx, input.out.index)) + if (input.prevout.tx) { + if (!this._wallet.ownOutput(input.prevout.tx, input.prevout.index)) continue; } // Add orphan, if no parent transaction is yet known - orphan = { tx: tx, index: input.out.index }; + orphan = { tx: tx, index: input.prevout.index }; if (this._orphans[key]) this._orphans[key].push(orphan); else @@ -149,9 +149,9 @@ TXPool.prototype.add = function add(tx, noWrite) { function checkOrphan(orphan) { var index = orphan.tx._inputIndex(tx.hash('hex'), orphan.index); assert(index !== -1); - assert(orphan.tx.inputs[index].out.hash === tx.hash('hex')); - assert(orphan.tx.inputs[index].out.index === i); - orphan.tx.inputs[index].out.tx = tx; + assert(orphan.tx.inputs[index].prevout.hash === tx.hash('hex')); + assert(orphan.tx.inputs[index].prevout.index === i); + orphan.tx.inputs[index].prevout.tx = tx; // Verify that input script is correct, if not - add output to unspent // and remove orphan from storage @@ -225,7 +225,7 @@ TXPool.prototype._removeTX = function _removeTX(tx, noWrite) { }); }; -TXPool.prototype.all = function all() { +TXPool.prototype.getAll = function getAll() { return Object.keys(this._all).map(function(key) { return this._all[key]; }, this).filter(function(tx) { @@ -234,7 +234,7 @@ TXPool.prototype.all = function all() { }, this); }; -TXPool.prototype.unspent = function unspent() { +TXPool.prototype.getUnspent = function getUnspent() { return Object.keys(this._unspent).map(function(key) { return this._unspent[key]; }, this).filter(function(item) { @@ -246,7 +246,7 @@ TXPool.prototype.hasUnspent = function hasUnspent(hash, unspent) { var has; if (utils.isBuffer(hash) && hash.length && typeof hash[0] !== 'number') { - unspent = this.unspent(); + unspent = this.getUnspent(); has = hash.map(function(hash) { var h = this.hasUnspent(hash, unspent); if (!h) @@ -260,14 +260,14 @@ TXPool.prototype.hasUnspent = function hasUnspent(hash, unspent) { if (utils.isBuffer(hash)) hash = utils.toHex(hash); - else if (hash.out) - hash = hash.out.hash; + else if (hash.prevout) + hash = hash.prevout.hash; else if (hash.tx) hash = hash.tx.hash('hex'); else if (hash instanceof bcoin.tx) hash = hash.hash('hex'); - unspent = unspent || this.unspent(); + unspent = unspent || this.getUnspent(); has = unspent.filter(function(item) { return item.tx.hash('hex') === hash; @@ -279,7 +279,7 @@ TXPool.prototype.hasUnspent = function hasUnspent(hash, unspent) { return has; }; -TXPool.prototype.pending = function pending() { +TXPool.prototype.getPending = function getPending() { return Object.keys(this._all).map(function(key) { return this._all[key]; }, this).filter(function(tx) { @@ -287,9 +287,9 @@ TXPool.prototype.pending = function pending() { }); }; -TXPool.prototype.balance = function balance() { +TXPool.prototype.getBalance = function getBalance() { var acc = new bn(0); - var unspent = this.unspent(); + var unspent = this.getUnspent(); if (unspent.length === 0) return acc; @@ -298,6 +298,12 @@ TXPool.prototype.balance = function balance() { }, acc); }; +// Legacy +TXPool.prototype.all = TXPool.prototype.getAll; +TXPool.prototype.unspent = TXPool.prototype.getUnspent; +TXPool.prototype.pending = TXPool.prototype.getPending; +TXPool.prototype.balance = TXPool.prototype.getBalance; + TXPool.prototype.toJSON = function toJSON() { return { v: 1, diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index a9eab006..93464cb7 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -26,11 +26,15 @@ function TX(data, block) { this.version = data.version || 1; this.inputs = []; this.outputs = []; - this.lock = data.lock || 0; + this.lockTime = data.lockTime || 0; this.ts = data.ts || 0; this.block = data.block || null; this._hash = null; + // Legacy + if (data.lock != null) + this.lockTime = data.lock; + this._raw = data._raw || null; this._size = data._size || 0; @@ -42,14 +46,14 @@ function TX(data, block) { if (data.inputs) { assert(this.inputs.length === 0); data.inputs.forEach(function(input) { - this.input(input); + this.addInput(input); }, this); } if (data.outputs) { assert(this.outputs.length === 0); data.outputs.forEach(function(output) { - this.output(output); + this.addOutput(output); }, this); } @@ -65,15 +69,25 @@ function TX(data, block) { this.subtractFee = data.subtractFee || null; this.changeAddress = data.changeAddress || null; this.changeIndex = data.changeIndex != null ? data.changeIndex : -1; + this.total = data.total || null; // ps = Pending Since this.ps = this.ts === 0 ? utils.now() : 0; // Discourage fee snipping a la bitcoind - // if (data.lock == null) - // this._avoidFeeSnipping(); + // if (data.lockTime == null && data.lock == null) + // this.avoidFeeSnipping(); } +// Legacy +TX.prototype.__defineSetter__('lock', function(lockTime) { + return this.lockTime = lockTime; +}); + +TX.prototype.__defineGetter__('lock', function() { + return this.lockTime; +}); + TX.prototype.clone = function clone() { return new TX(this); }; @@ -89,22 +103,26 @@ TX.prototype.render = function render(force) { return bcoin.protocol.framer.tx(this); }; -TX.prototype.size = function size() { +TX.prototype.getSize = function getSize() { return this._size || this.render().length; }; -TX.prototype.input = function input(i, index) { - this._input(i, index); +TX.prototype.size = TX.prototype.getSize; + +TX.prototype.addInput = function addInput(i, index) { + this._addInput(i, index); return this; }; -// tx._input(tx, index) -// tx._input(hash, index) -// tx._input(input) -// tx._input({ hash: hash, index: index }) -// tx._input({ tx: tx, index: index }) -TX.prototype._input = function _input(obj, index) { - var options, hash, input, ex, i; +TX.prototype.input = TX.prototype.addInput; + +// tx._addInput(tx, index) +// tx._addInput(hash, index) +// tx._addInput(input) +// tx._addInput({ hash: hash, index: index }) +// tx._addInput({ tx: tx, index: index }) +TX.prototype._addInput = function _addInput(obj, index) { + var options, hash, input, ex, i, prevout; if (obj instanceof TX) options = { tx: obj, index: index }; @@ -113,10 +131,12 @@ TX.prototype._input = function _input(obj, index) { else options = obj; + prevout = options.prevout || options.out; + if (options.tx) hash = options.tx.hash('hex'); - else if (options.out) - hash = options.out.hash; + else if (prevout) + hash = prevout.hash; else hash = options.hash; @@ -125,21 +145,21 @@ TX.prototype._input = function _input(obj, index) { input = bcoin.input({ tx: this, - out: { - tx: options.out ? options.out.tx : options.tx, + prevout: { + tx: prevout ? prevout.tx : options.tx, hash: hash, - index: options.out ? options.out.index : options.index + index: prevout ? prevout.index : options.index }, script: options.script, - seq: options.seq + sequence: options.sequence || options.seq }); // Try modifying existing input first - i = this._inputIndex(input.out.hash, input.out.index); + i = this._inputIndex(input.prevout.hash, input.prevout.index); if (i !== -1) { ex = this.inputs[i]; - input.out.tx = input.out.tx || ex.out.tx; - input.seq = input.seq || ex.seq; + input.prevout.tx = input.prevout.tx || ex.prevout.tx; + input.sequence = input.sequence || ex.sequence; input.script = input.script.length ? input.script : ex.script; this.inputs[i] = input; } else { @@ -150,6 +170,8 @@ TX.prototype._input = function _input(obj, index) { return i; }; +TX.prototype._input = TX.prototype._addInput; + TX.prototype._inputIndex = function _inputIndex(hash, index) { var i, ex; @@ -158,7 +180,7 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) { for (i = 0; i < this.inputs.length; i++) { ex = this.inputs[i]; - if (ex.out.hash === hash && ex.out.index === index) + if (ex.prevout.hash === hash && ex.prevout.index === index) return i; } @@ -176,14 +198,14 @@ TX.prototype.scriptInput = function scriptInput(index, pub, redeem) { assert(input); // We should have previous outputs by now. - assert(input.out.tx); + assert(input.prevout.tx); // Already has a script template (at least) if (input.script.length) return; // Get the previous output's subscript - s = input.out.tx.getSubscript(input.out.index); + s = input.prevout.tx.getSubscript(input.prevout.index); // P2SH if (bcoin.script.isScripthash(s)) { @@ -236,7 +258,7 @@ TX.prototype.scriptInput = function scriptInput(index, pub, redeem) { } }; -TX.prototype.signature = function signature(index, key, type) { +TX.prototype.createSignature = function createSignature(index, key, type) { var input, s, hash, signature; if (typeof index !== 'number') @@ -253,10 +275,10 @@ TX.prototype.signature = function signature(index, key, type) { assert(input); // We should have previous outputs by now. - assert(input.out.tx); + assert(input.prevout.tx); // Get the previous output's subscript - s = input.out.tx.getSubscript(input.out.index); + s = input.prevout.tx.getSubscript(input.prevout.index); // We need to grab the redeem script when // signing p2sh transactions. @@ -278,6 +300,9 @@ TX.prototype.signature = function signature(index, key, type) { return signature; }; +// Legacy +TX.prototype.signature = TX.prototype.createSignature; + // Sign the now-built scriptSigs TX.prototype.signInput = function signInput(index, key, type) { var input, s, hash, signature; @@ -291,13 +316,13 @@ TX.prototype.signInput = function signInput(index, key, type) { assert(input); // We should have previous outputs by now. - assert(input.out.tx); + assert(input.prevout.tx); // Create our signature. - signature = this.signature(index, key, type); + signature = this.createSignature(index, key, type); // Get the previous output's subscript - s = input.out.tx.getSubscript(input.out.index); + s = input.prevout.tx.getSubscript(input.prevout.index); // Script length, needed for multisig len = input.script.length; @@ -484,7 +509,7 @@ TX.prototype.scriptSig = function scriptSig(index, key, pub, redeem, type) { return input.script; }; -TX.prototype.output = function output(obj, value) { +TX.prototype.addOutput = function addOutput(obj, value) { var options, output; if (obj instanceof bcoin.wallet) @@ -512,7 +537,8 @@ TX.prototype.output = function output(obj, value) { return this; }; -TX.prototype.out = TX.prototype.output; +TX.prototype.out = TX.prototype.addOutput; +TX.prototype.output = TX.prototype.addOutput; TX.prototype.scriptOutput = function scriptOutput(index, options) { var output, script, keys, m, n, hash, flags; @@ -618,9 +644,9 @@ TX.prototype.scriptOutput = function scriptOutput(index, options) { // P2SH Transaction // hash160 [hash] eq if (options.scripthash) { - if (options.lock != null) { + if (options.lockTime != null) { script = [ - bcoin.script.array(options.lock), + bcoin.script.array(options.lockTime), 'checklocktimeverify', 'drop', 'codeseparator' @@ -648,7 +674,7 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) { if (!Array.isArray(s)) { type = s; - s = this.inputs[index].out.tx.getSubscript(this.inputs[index].out.index); + s = this.inputs[index].prevout.tx.getSubscript(this.inputs[index].prevout.index); if (bcoin.script.isScripthash(s)) { s = this.inputs[index].script[this.inputs[index.script.length - 1]]; s = bcoin.script.getSubscript(bcoin.script.decode(s)); @@ -687,7 +713,7 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) { // Allow input sequence updates for other inputs. for (i = 0; i < copy.inputs.length; i++) { if (i !== index) - copy.inputs[i].seq = 0; + copy.inputs[i].sequence = 0; } } else if ((type & 0x1f) === constants.hashType.single) { // Bitcoind used to return 1 as an error code: @@ -709,7 +735,7 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) { // Allow input sequence updates for other inputs. for (i = 0; i < copy.inputs.length; i++) { if (i !== index) - copy.inputs[i].seq = 0; + copy.inputs[i].sequence = 0; } } @@ -761,15 +787,15 @@ TX.prototype.verify = function verify(index, force, flags) { if (index != null && index !== i) return true; - if (!input.out.tx) + if (!input.prevout.tx) return false; // Somethis is very wrong if this is // not the case. - assert.equal(input.out.tx.hash('hex'), input.out.hash); + assert.equal(input.prevout.tx.hash('hex'), input.prevout.hash); // Grab the previous output. - output = input.out.tx.outputs[input.out.index]; + output = input.prevout.tx.outputs[input.prevout.index]; // Transaction is referencing an output // that does not exist. @@ -777,7 +803,7 @@ TX.prototype.verify = function verify(index, force, flags) { return false; // Transaction cannot reference itself. - if (input.out.hash === this.hash('hex')) + if (input.prevout.hash === this.hash('hex')) return false; return bcoin.script.verify(input.script, output.script, this, i, flags); @@ -785,7 +811,7 @@ TX.prototype.verify = function verify(index, force, flags) { }; TX.prototype.isCoinbase = function isCoinbase() { - return this.inputs.length === 1 && +this.inputs[0].out.hash === 0; + return this.inputs.length === 1 && +this.inputs[0].prevout.hash === 0; }; TX.prototype.maxSize = function maxSize() { @@ -804,7 +830,7 @@ TX.prototype.maxSize = function maxSize() { size = 0; // Get the previous output's subscript - s = input.out.tx.getSubscript(input.out.index); + s = input.prevout.tx.getSubscript(input.prevout.index); // If we have access to the redeem script, // we can use it to calculate size much easier. @@ -888,9 +914,9 @@ TX.prototype.maxSize = function maxSize() { return total; }; -TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { +TX.prototype.getInputs = function getInputs(unspent, address, fee) { var tx = this.clone(); - var cost = tx.funds('out'); + var cost = tx.getFunds('output'); var totalkb = 1; var total = cost.addn(constants.tx.fee); var inputs = []; @@ -906,10 +932,10 @@ TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { // Add new inputs until TX will have enough // funds to cover both minimum post cost // and fee. - var index = tx._input(unspent); + var index = tx._addInput(unspent); inputs.push(tx.inputs[index]); lastAdded++; - return tx.funds('in').cmp(total) < 0; + return tx.getFunds('input').cmp(total) < 0; } // Transfer `total` funds maximum. @@ -918,7 +944,7 @@ TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { if (!fee) { // Add dummy output (for `change`) to // calculate maximum TX size. - tx.output({ + tx.addOutput({ address: address, value: new bn(0) }); @@ -931,7 +957,7 @@ TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { // break; // } // } - // total = tx.funds('out'); + // total = tx.getFunds('output'); // } // Change fee value if it is more than 1024 @@ -945,17 +971,17 @@ TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { totalkb += newkb; // Failed to get enough funds, add more inputs. - if (tx.funds('in').cmp(total) < 0) + if (tx.getFunds('input').cmp(total) < 0) unspent.slice(lastAdded).every(addInput); - } while (tx.funds('in').cmp(total) < 0 && lastAdded < unspent.length); + } while (tx.getFunds('input').cmp(total) < 0 && lastAdded < unspent.length); } - if (tx.funds('in').cmp(total) < 0) { + if (tx.getFunds('input').cmp(total) < 0) { // Still failing to get enough funds. inputs = null; } else { // How much money is left after filling outputs. - change = tx.funds('in').sub(total); + change = tx.getFunds('input').sub(total); } // Return necessary inputs and change. @@ -969,7 +995,7 @@ TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { }; }; -TX.prototype.fillUnspent = function fillUnspent(unspent, address, fee) { +TX.prototype.fill = function fill(unspent, address, fee) { var result; if (unspent) @@ -983,13 +1009,15 @@ TX.prototype.fillUnspent = function fillUnspent(unspent, address, fee) { assert(this.changeAddress); - result = this.getUnspent(this.unspent, this.changeAddress, this.hardFee); + result = this.getInputs(this.unspent, this.changeAddress, this.hardFee); + + this.total = result.total; if (!result.inputs) return result; result.inputs.forEach(function(input) { - this.input(input); + this.addInput(input); }, this); if (result.change.cmpn(constants.tx.dust) < 0) { @@ -1000,7 +1028,7 @@ TX.prototype.fillUnspent = function fillUnspent(unspent, address, fee) { ); this.changeIndex = -1; } else { - this.output({ + this.addOutput({ address: this.changeAddress, value: result.change }); @@ -1011,6 +1039,10 @@ TX.prototype.fillUnspent = function fillUnspent(unspent, address, fee) { return result; }; +// Legacy +TX.prototype.fillUnspent = TX.prototype.fill; +TX.prototype.fillInputs = TX.prototype.fill; + TX.prototype._recalculateFee = function recalculateFee() { var output = this.outputs[this.changeIndex]; var size, real, fee; @@ -1019,7 +1051,7 @@ TX.prototype._recalculateFee = function recalculateFee() { return; if (!output) { - this.output({ + this.addOutput({ address: this.changeAddress, value: new bn(0) }); @@ -1060,26 +1092,26 @@ TX.prototype._recalculateFee = function recalculateFee() { }; TX.prototype.getFee = function getFee() { - if (this.funds('in').cmp(this.funds('out')) < 0) + if (this.getFunds('input').cmp(this.getFunds('output')) < 0) return new bn(0); - return this.funds('in').sub(this.funds('out')); + return this.getFunds('input').sub(this.getFunds('output')); }; -TX.prototype.funds = function funds(side) { +TX.prototype.getFunds = function getFunds(side) { var acc = new bn(0); var inputs; - if (side === 'in') { + if (side === 'in' || side === 'input') { inputs = this.inputs.filter(function(input) { - return input.out.tx; + return input.prevout.tx; }); if (inputs.length === 0) return acc; inputs.reduce(function(acc, input) { - return acc.iadd(input.out.tx.outputs[input.out.index].value); + return acc.iadd(input.prevout.tx.outputs[input.prevout.index].value); }, acc); return acc; @@ -1096,25 +1128,28 @@ TX.prototype.funds = function funds(side) { return acc; }; -TX.prototype._avoidFeeSnipping = function _avoidFeeSnipping() { +// Legacy +TX.prototype.funds = TX.prototype.getFunds; + +TX.prototype.avoidFeeSnipping = function avoidFeeSnipping() { if (!this.chain) return; - this.lock = this.chain.height(); + this.lockTime = this.chain.height(); if ((Math.random() * 10 | 0) === 0) - this.lock = Math.max(0, this.lock - (Math.random() * 100 | 0)); + this.lockTime = Math.max(0, this.lockTime - (Math.random() * 100 | 0)); }; -TX.prototype.setLockTime = function setLockTime(lock) { +TX.prototype.setLockTime = function setLockTime(lockTime) { var i, input; - this.lock = lock; + this.lockTime = lockTime; for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; - if (input.seq === 0xffffffff) - input.seq = 0; + if (input.sequence === 0xffffffff) + input.sequence = 0; } }; @@ -1122,11 +1157,11 @@ TX.prototype.increaseFee = function increaseFee(fee) { var i, input; this.hardFee = fee || this.getFee().add(new bn(10000)); - this.fillUnspent(); + this.fill(); for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; - input.seq = 0xffffffff - 1; + input.sequence = 0xffffffff - 1; } }; @@ -1134,11 +1169,11 @@ TX.prototype.isFull = function isFull() { if (this.inputs.length === 0) return false; return this.inputs.every(function(input) { - return !!input.out.tx; + return !!input.prevout.tx; }); }; -TX.prototype.fill = function fill(txs) { +TX.prototype.fillPrevout = function fillPrevout(txs) { var inputs; if (txs instanceof bcoin.txPool) @@ -1154,9 +1189,9 @@ TX.prototype.fill = function fill(txs) { } inputs = this.inputs.filter(function(input) { - if (!input.out.tx && txs[input.out.hash]) - input.out.tx = txs[input.out.hash]; - return !!input.out.tx; + if (!input.prevout.tx && txs[input.prevout.hash]) + input.prevout.tx = txs[input.prevout.hash]; + return !!input.prevout.tx; }, this); return inputs.length === this.inputs.length; @@ -1206,14 +1241,14 @@ TX.prototype.isFinal = function isFinal(height, ts) { if (!this.chain) return true; - if (this.lock === 0) + if (this.lockTime === 0) return true; - if (this.lock < (this.lock < threshold ? height : ts)) + if (this.lockTime < (this.lockTime < threshold ? height : ts)) return true; for (i = 0; i < this.inputs.length; i++) { - if (this.inputs[i].seq !== 0xffffffff) + if (this.inputs[i].sequence !== 0xffffffff) return false; } @@ -1290,10 +1325,10 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) { for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; - if (!input.out.tx) + if (!input.prevout.tx) return false; - prev = input.out.tx.outputs[input.out.index]; + prev = input.prevout.tx.outputs[input.prevout.index]; if (!prev) return false; @@ -1347,11 +1382,11 @@ TX.prototype.getPriority = function getPriority() { for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; - if (!input.out.tx) + if (!input.prevout.tx) return constants.tx.freeThreshold.clone(); - output = input.out.tx.outputs[input.out.index]; - age = input.out.tx.getConfirmations(); + output = input.prevout.tx.outputs[input.prevout.index]; + age = input.prevout.tx.getConfirmations(); if (age === -1) age = 0; @@ -1399,7 +1434,7 @@ TX.prototype.getConfirmations = function getConfirmations() { }; TX.prototype.getValue = function getValue() { - return this.funds('out'); + return this.getFunds('output'); }; TX.prototype.__defineGetter__('chain', function() { diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 40f45577..6f0513bf 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -148,7 +148,7 @@ Wallet.prototype._init = function init() { // Notify owners about new accepted transactions this.tx.on('update', function(lastTs, tx) { - var b = this.balance(); + var b = this.getBalance(); if (prevBalance && prevBalance.cmp(b) !== 0) self.emit('balance', b); self.emit('update', tx); @@ -453,8 +453,8 @@ Wallet.prototype.ownInput = function ownInput(tx, index) { var inputs = tx.inputs.filter(function(input, i) { var s; - if (!input.out.tx && this.tx._all[input.out.hash]) - input.out.tx = this.tx._all[input.out.hash]; + if (!input.prevout.tx && this.tx._all[input.prevout.hash]) + input.prevout.tx = this.tx._all[input.prevout.hash]; if (index != null && index !== i) return false; @@ -473,10 +473,10 @@ Wallet.prototype.ownInput = function ownInput(tx, index) { return true; } - if (!input.out.tx) + if (!input.prevout.tx) return false; - s = input.out.tx.getSubscript(input.out.index); + s = input.prevout.tx.getSubscript(input.prevout.index); if (bcoin.script.isPubkey(s, key)) return true; @@ -501,27 +501,41 @@ Wallet.prototype.ownInput = function ownInput(tx, index) { return inputs; }; -Wallet.prototype.fillUnspent = function fillUnspent(tx, address, fee) { +Wallet.prototype.fill = function fill(tx, address, fee) { + var result; + if (!address) address = this.changeAddress || this.getAddress(); - return tx.fillUnspent(this.unspent(), address, fee); + result = tx.fill(this.getUnspent(), address, fee); + + if (!result.inputs) + return false; + + return true; }; -Wallet.prototype.fillTX = function fillTX(tx) { - return tx.fill(this); +// Legacy +Wallet.prototype.fillUnspent = Wallet.prototype.fill; +Wallet.prototype.fillInputs = Wallet.prototype.fill; + +Wallet.prototype.fillPrevout = function fillPrevout(tx) { + return tx.fillPrevout(this); }; +// Legacy +Wallet.prototype.fillTX = Wallet.prototype.fillPrevout; + Wallet.prototype.scriptInputs = function scriptInputs(tx) { var pub = this.getPublicKey(); var redeem = this.getScript(); var inputs = tx.inputs; inputs = inputs.filter(function(input, i) { - if (!input.out.tx && this.tx._all[input.out.hash]) - input.out.tx = this.tx._all[input.out.hash]; + if (!input.prevout.tx && this.tx._all[input.prevout.hash]) + input.prevout.tx = this.tx._all[input.prevout.hash]; - if (!input.out.tx || !this.ownOutput(input.out.tx)) + if (!input.prevout.tx || !this.ownOutput(input.prevout.tx)) return false; tx.scriptInput(i, pub, redeem); @@ -537,10 +551,10 @@ Wallet.prototype.signInputs = function signInputs(tx, type) { var inputs = tx.inputs; inputs = inputs.filter(function(input, i) { - if (!input.out.tx && this.tx._all[input.out.hash]) - input.out.tx = this.tx._all[input.out.hash]; + if (!input.prevout.tx && this.tx._all[input.prevout.hash]) + input.prevout.tx = this.tx._all[input.prevout.hash]; - if (!input.out.tx || !this.ownOutput(input.out.tx)) + if (!input.prevout.tx || !this.ownOutput(input.prevout.tx)) return false; tx.signInput(i, key, type); @@ -559,11 +573,11 @@ Wallet.prototype.sign = function sign(tx, type) { // Add signature script to each input inputs = inputs.filter(function(input, i) { - if (!input.out.tx && this.tx._all[input.out.hash]) - input.out.tx = this.tx._all[input.out.hash]; + if (!input.prevout.tx && this.tx._all[input.prevout.hash]) + input.prevout.tx = this.tx._all[input.prevout.hash]; // Filter inputs that this wallet own - if (!input.out.tx || !this.ownOutput(input.out.tx)) + if (!input.prevout.tx || !this.ownOutput(input.prevout.tx)) return false; tx.scriptSig(i, key, pub, redeem, type); @@ -578,28 +592,27 @@ Wallet.prototype.addTX = function addTX(tx, block) { return this.tx.add(tx); }; -Wallet.prototype.all = function all() { - return this.tx.all(); +Wallet.prototype.getAll = function getAll() { + return this.tx.getAll(); }; -Wallet.prototype.unspent = function unspent() { - return this.tx.unspent(); +Wallet.prototype.getUnspent = function getUnspent() { + return this.tx.getUnspent(); }; -Wallet.prototype.pending = function pending() { - return this.tx.pending(); +Wallet.prototype.getPending = function getPending() { + return this.tx.getPending(); }; -Wallet.prototype.balance = function balance() { - return this.tx.balance(); +Wallet.prototype.getBalance = function getBalance() { + return this.tx.getBalance(); }; -Wallet.prototype.fill = function fill(tx, changeAddress, fee) { - var result = this.fillUnspent(tx, changeAddress, fee); - if (!result.inputs) - return false; - return true; -}; +// Legacy +Wallet.prototype.all = Wallet.prototype.getAll; +Wallet.prototype.unspent = Wallet.prototype.getUnspent; +Wallet.prototype.pending = Wallet.prototype.getPending; +Wallet.prototype.balance = Wallet.prototype.getBalance; Wallet.prototype.toAddress = function toAddress() { var self = this; @@ -627,7 +640,7 @@ Wallet.prototype.toAddress = function toAddress() { hash: utils.toHex(this.getHash()), received: received, sent: sent, - balance: this.balance(), + balance: this.getBalance(), txs: txs }; }; @@ -641,7 +654,7 @@ Wallet.prototype.toJSON = function toJSON(encrypt) { label: this.label, address: this.getKeyAddress(), scriptaddress: this.getScriptAddress(), - balance: utils.toBTC(this.balance()), + balance: utils.toBTC(this.getBalance()), pub: this.getPublicKey('hex'), priv: encrypt ? encrypt(this.getPrivateKey('base58'))