diff --git a/.eslintfiles b/.eslintfiles new file mode 100644 index 000000000..d91e3c883 --- /dev/null +++ b/.eslintfiles @@ -0,0 +1,16 @@ +bench/ +bin/cli +bin/node +bin/spvnode +bin/wallet +browser/server.js +browser/wsproxy.js +examples/ +lib/ +migrate/ +scripts/ +test/ +webpack/ +webpack.browser.js +webpack.compat.js +webpack.node.js diff --git a/.eslintrc.json b/.eslintrc.json index 7b6ba3b8c..dc2f6a3e7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,41 +1,98 @@ { - "extends": "eslint:recommended", "env": { - "browser": true, "es6": true, - "node": true, - "mocha": true + "node": true }, + "extends": "eslint:recommended", "parserOptions": { "ecmaVersion": 8 }, + "root": true, "rules": { - "strict": 2, - "indent": ["error", 2, { + "array-bracket-spacing": ["error", "never"], + "arrow-parens": ["error", "as-needed", { + "requireForBlockBody": true + }], + "arrow-spacing": "error", + "block-spacing": ["error", "always"], + "brace-style": ["error", "1tbs"], + "camelcase": ["error", { + "properties": "never" + }], + "comma-dangle": ["error", "never"], + "consistent-return": "error", + "eol-last": ["error", "always"], + "eqeqeq": ["error", "always", { + "null": "ignore" + }], + "func-name-matching": "error", + "indent": ["off", 2, { "SwitchCase": 1, "CallExpression": { "arguments": "off" }, "ArrayExpression": "off" }], + "handle-callback-err": "off", "linebreak-style": ["error", "unix"], - "quotes": ["error", "single"], - "semi": ["error", "always"], - "no-console": 0, + "max-len": ["error", { + "code": 80, + "ignorePattern": "function \\w+\\(", + "ignoreUrls": true + }], + "max-statements-per-line": ["error", { + "max": 1 + }], + "new-cap": ["error", { + "newIsCap": true, + "capIsNew": false + }], + "new-parens": "error", + "no-buffer-constructor": "error", + "no-console": "off", + "no-extra-semi": "off", + "no-fallthrough": "off", + "no-func-assign": "off", + "no-implicit-coercion": "error", + "no-multi-assign": "error", + "no-multiple-empty-lines": ["error", { + "max": 1 + }], + "no-nested-ternary": "error", + "no-param-reassign": "off", + "no-return-assign": "error", + "no-return-await": "off", + "no-shadow-restricted-names": "error", + "no-tabs": "error", + "no-trailing-spaces": "error", "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }], - "no-func-assign": 0, - "no-cond-assign": 0, - "no-unreachable": 0, - "no-fallthrough": 0, - "no-useless-escape": 0, - "no-unsafe-finally": 0, - "no-extra-semi": 0, - "handle-callback-err": 0, - "no-buffer-constructor": 2, - "no-tabs": 2 + "no-use-before-define": ["error", { + "functions": false, + "classes": false + }], + "no-useless-escape": "off", + "no-var": "error", + "nonblock-statement-body-position": ["error", "below"], + "padded-blocks": ["error", "never"], + "prefer-arrow-callback": "error", + "prefer-const": ["error", { + "destructuring": "all", + "ignoreReadBeforeAssign": true + }], + "prefer-template": "off", + "quotes": ["error", "single"], + "semi": ["error", "always"], + "spaced-comment": ["error", "always", { + "exceptions": ["!"] + }], + "space-before-blocks": "error", + "strict": "error", + "unicode-bom": ["error", "never"], + "valid-jsdoc": "error", + "wrap-iife": ["error", "inside"] } } diff --git a/.gitignore b/.gitignore index 39e2841b0..f7ff5cd23 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules/ docs/reference/ docker_data/ browser/bcoin* +package-lock.json npm-debug.log diff --git a/.npmignore b/.npmignore index 897dc0df6..c93e8534f 100644 --- a/.npmignore +++ b/.npmignore @@ -5,4 +5,5 @@ docker_data/ test/ node_modules/ browser/bcoin* +package-lock.json npm-debug.log diff --git a/bench/bech32.js b/bench/bech32.js index 18a90b9e3..3b19c307a 100644 --- a/bench/bech32.js +++ b/bench/bech32.js @@ -3,24 +3,25 @@ const Address = require('../lib/primitives/address'); const random = require('../lib/crypto/random'); const bench = require('./bench'); +const addrs = []; -let i, end, addr; - -let addrs = []; - -end = bench('serialize'); -for (i = 0; i < 100000; i++) { - addr = Address.fromProgram(0, random.randomBytes(20)); - addrs.push(addr.toBech32()); +{ + const end = bench('serialize'); + for (let i = 0; i < 100000; i++) { + const addr = Address.fromProgram(0, random.randomBytes(20)); + addrs.push(addr.toBech32()); + } + end(100000); } -end(i); -end = bench('parse'); -for (i = 0; i < 100000; i++) { - addr = addrs[i]; - addr = Address.fromBech32(addr); - addrs[i] = addr; +{ + const end = bench('parse'); + for (let i = 0; i < 100000; i++) { + const b32 = addrs[i]; + const addr = Address.fromBech32(b32); + addrs[i] = addr; + } + end(100000); } -end(i); -console.error(addrs); +console.error(addrs[0][0]); diff --git a/bench/bench.js b/bench/bench.js index bcccbe722..8e486c082 100644 --- a/bench/bench.js +++ b/bench/bench.js @@ -1,11 +1,11 @@ 'use strict'; module.exports = function bench(name) { - let start = process.hrtime(); + const start = process.hrtime(); return function end(ops) { - let elapsed = process.hrtime(start); - let time = elapsed[0] + elapsed[1] / 1e9; - let rate = ops / time; + const elapsed = process.hrtime(start); + const time = elapsed[0] + elapsed[1] / 1e9; + const rate = ops / time; console.log('%s: ops=%d, time=%d, rate=%s', name, ops, time, rate.toFixed(5)); diff --git a/bench/buffer.js b/bench/buffer.js index f2af99cc1..847a0e94e 100644 --- a/bench/buffer.js +++ b/bench/buffer.js @@ -1,31 +1,33 @@ 'use strict'; -const fs = require('fs'); -const TX = require('../lib/primitives/tx'); const BufferWriter = require('../lib/utils/writer'); const StaticWriter = require('../lib/utils/staticwriter'); +const common = require('../test/util/common'); const bench = require('./bench'); -let wtx = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8'); -let i, tx, end; +const tx5 = common.readTX('tx5'); -wtx = Buffer.from(wtx.trim(), 'hex'); -tx = TX.fromRaw(wtx); - -end = bench('serialize (static-writer)'); -for (i = 0; i < 10000; i++) { - tx._raw = null; - tx._size = -1; - tx._witness = -1; - tx.writeWitness(new StaticWriter(tx.getWitnessSizes().total)).render(); +{ + const [tx] = tx5.getTX(); + const end = bench('serialize (static-writer)'); + for (let i = 0; i < 10000; i++) { + tx.refresh(); + const {size} = tx.getWitnessSizes(); + const bw = new StaticWriter(size); + tx.toWitnessWriter(bw); + bw.render(); + } + end(10000); } -end(i); -end = bench('serialize (buffer-writer)'); -for (i = 0; i < 10000; i++) { - tx._raw = null; - tx._size = -1; - tx._witness = -1; - tx.writeWitness(new BufferWriter()).render(); +{ + const [tx] = tx5.getTX(); + const end = bench('serialize (buffer-writer)'); + for (let i = 0; i < 10000; i++) { + tx.refresh(); + const bw = new BufferWriter(); + tx.toWitnessWriter(bw); + bw.render(); + } + end(10000); } -end(i); diff --git a/bench/chacha.js b/bench/chacha.js index c8a58ff4d..00249d33d 100644 --- a/bench/chacha.js +++ b/bench/chacha.js @@ -4,47 +4,53 @@ const ChaCha20 = require('../lib/crypto/chacha20'); const Poly1305 = require('../lib/crypto/poly1305'); const digest = require('../lib/crypto/digest'); const bench = require('./bench'); -let i, chacha, iv, poly, key, data, end; console.log('note: rate measured in kb/s'); -chacha = new ChaCha20(); -key = Buffer.allocUnsafe(32); -key.fill(2); -iv = Buffer.from('0102030405060708', 'hex'); +const chacha = new ChaCha20(); +const poly = new Poly1305(); +const key = Buffer.alloc(32, 0x02); +const iv = Buffer.from('0102030405060708', 'hex'); +const chunk = Buffer.allocUnsafe(32); +const data = Buffer.allocUnsafe(32); + +for (let i = 0; i < 32; i++) + chunk[i] = i; + +for (let i = 0; i < 32; i++) + data[i] = i & 0xff; + chacha.init(key, iv, 0); -data = Buffer.allocUnsafe(32); -for (i = 0; i < 32; i++) - data[i] = i; -end = bench('encrypt'); -for (i = 0; i < 1000000; i++) - chacha.encrypt(data); -end(i * 32 / 1024); - -poly = new Poly1305(); -key = Buffer.allocUnsafe(32); -key.fill(2); poly.init(key); -data = Buffer.allocUnsafe(32); -for (i = 0; i < 32; i++) - data[i] = i & 0xff; +{ + const end = bench('encrypt'); + for (let i = 0; i < 1000000; i++) + chacha.encrypt(chunk); + end(1000000 * 32 / 1024); +} -end = bench('update'); -for (i = 0; i < 1000000; i++) - poly.update(data); -end(i * 32 / 1024); +{ + const end = bench('update'); + for (let i = 0; i < 1000000; i++) + poly.update(data); + end(1000000 * 32 / 1024); +} -end = bench('finish'); -for (i = 0; i < 1000000; i++) { - poly.init(key); - poly.update(data); - poly.finish(); +{ + const end = bench('finish'); + for (let i = 0; i < 1000000; i++) { + poly.init(key); + poly.update(data); + poly.finish(); + } + end(1000000 * 32 / 1024); } -end(i * 32 / 1024); // For reference: -end = bench('sha256'); -for (i = 0; i < 1000000; i++) - digest.hash256(data); -end(i * 32 / 1024); +{ + const end = bench('sha256'); + for (let i = 0; i < 1000000; i++) + digest.hash256(data); + end(1000000 * 32 / 1024); +} diff --git a/bench/coins-old.js b/bench/coins-old.js deleted file mode 100644 index 4fcf5dfcd..000000000 --- a/bench/coins-old.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const bench = require('./bench'); -const Coins = require('../migrate/coins-old'); -const TX = require('../lib/primitives/tx'); - -let wtx = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8'); -wtx = TX.fromRaw(wtx.trim(), 'hex'); - -let coins = Coins.fromTX(wtx); -let i, j, end, raw, hash; - -//raw = coins.toRaw(); -//console.log(Coins.fromRaw(raw)); - -end = bench('serialize'); -for (i = 0; i < 10000; i++) - raw = coins.toRaw(); -end(i); - -end = bench('parse'); -for (i = 0; i < 10000; i++) - Coins.fromRaw(raw); -end(i); - -end = bench('parse-single'); -hash = wtx.hash('hex'); -for (i = 0; i < 10000; i++) - Coins.parseCoin(raw, hash, 5); -end(i); - -coins = Coins.fromRaw(raw); -end = bench('get'); - -for (i = 0; i < 10000; i++) - for (j = 0; j < coins.outputs.length; j++) - coins.get(j); -end(i * coins.outputs.length); diff --git a/bench/coins.js b/bench/coins.js index 3392b05f4..31f63c6b1 100644 --- a/bench/coins.js +++ b/bench/coins.js @@ -1,35 +1,38 @@ 'use strict'; -const fs = require('fs'); const Coins = require('../lib/coins/coins'); -const TX = require('../lib/primitives/tx'); +const common = require('../test/util/common'); const bench = require('./bench'); -let raw = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8'); -let wtx = TX.fromRaw(raw.trim(), 'hex'); -let coins = Coins.fromTX(wtx, 1); -let i, j, end, hash; - -end = bench('serialize'); -for (i = 0; i < 10000; i++) - raw = coins.toRaw(); -end(i); - -end = bench('parse'); -for (i = 0; i < 10000; i++) - Coins.fromRaw(raw); -end(i); - -end = bench('parse-single'); -hash = wtx.hash('hex'); -for (i = 0; i < 10000; i++) - Coins.parseCoin(raw, hash, 5); -end(i); - -coins = Coins.fromRaw(raw); -end = bench('get'); -for (i = 0; i < 10000; i++) { - for (j = 0; j < coins.outputs.length; j++) - coins.get(j); +const [tx] = common.readTX('tx5').getTX(); +const coins = Coins.fromTX(tx, 1); +const raw = coins.toRaw(); + +{ + const end = bench('serialize'); + + for (let i = 0; i < 10000; i++) + coins.toRaw(); + + end(10000); +} + +{ + const end = bench('parse'); + + for (let i = 0; i < 10000; i++) + Coins.fromRaw(raw); + + end(10000); +} + +{ + const end = bench('get'); + + for (let i = 0; i < 10000; i++) { + for (let j = 0; j < coins.outputs.length; j++) + coins.get(j); + } + + end(10000 * coins.outputs.length); } -end(i * coins.outputs.length); diff --git a/bench/merkle.js b/bench/merkle.js index bcbe090a8..85f6d6a09 100644 --- a/bench/merkle.js +++ b/bench/merkle.js @@ -11,12 +11,11 @@ for (let i = 0; i < 3000; i++) leaves.push(random.randomBytes(32)); { - let end = bench('tree'); - let i; - for (i = 0; i < 1000; i++) { - let [n, m] = merkle.createTree(leaves.slice()); + const end = bench('tree'); + for (let i = 0; i < 1000; i++) { + const [n, m] = merkle.createTree(leaves.slice()); assert(n); assert(!m); } - end(i); + end(1000); } diff --git a/bench/mnemonic.js b/bench/mnemonic.js index e37e5953a..ce9f250e4 100644 --- a/bench/mnemonic.js +++ b/bench/mnemonic.js @@ -5,15 +5,16 @@ const bench = require('./bench'); const HD = require('../lib/hd'); const Mnemonic = require('../lib/hd/mnemonic'); -let mnemonic = new Mnemonic(); +const mnemonic = new Mnemonic(); HD.fromMnemonic(mnemonic); -let phrase = mnemonic.getPhrase(); -let i, end; +const phrase = mnemonic.getPhrase(); -assert.equal(Mnemonic.fromPhrase(phrase).getPhrase(), phrase); +assert.strictEqual(Mnemonic.fromPhrase(phrase).getPhrase(), phrase); -end = bench('fromPhrase'); -for (i = 0; i < 10000; i++) - Mnemonic.fromPhrase(phrase); -end(i); +{ + const end = bench('fromPhrase'); + for (let i = 0; i < 10000; i++) + Mnemonic.fromPhrase(phrase); + end(10000); +} diff --git a/bench/script.js b/bench/script.js index c867073a9..e138b43ca 100644 --- a/bench/script.js +++ b/bench/script.js @@ -1,37 +1,17 @@ 'use strict'; -const assert = require('assert'); const random = require('../lib/crypto/random'); const Script = require('../lib/script/script'); const bench = require('./bench'); -const opcodes = Script.opcodes; -let i, hashes, end; -Script.prototype.fromPubkeyhashOld = function fromScripthash(hash) { - assert(Buffer.isBuffer(hash) && hash.length === 20); - this.push(opcodes.OP_DUP); - this.push(opcodes.OP_HASH160); - this.push(hash); - this.push(opcodes.OP_EQUALVERIFY); - this.push(opcodes.OP_CHECKSIG); - this.compile(); - return this; -}; +const hashes = []; -Script.fromPubkeyhashOld = function fromScripthash(hash) { - return new Script().fromPubkeyhashOld(hash); -}; - -hashes = []; -for (i = 0; i < 100000; i++) +for (let i = 0; i < 100000; i++) hashes.push(random.randomBytes(20)); -end = bench('old'); -for (i = 0; i < hashes.length; i++) - Script.fromPubkeyhashOld(hashes[i]); -end(i); - -end = bench('hash'); -for (i = 0; i < hashes.length; i++) - Script.fromPubkeyhash(hashes[i]); -end(i); +{ + const end = bench('hash'); + for (let i = 0; i < hashes.length; i++) + Script.fromPubkeyhash(hashes[i]); + end(100000); +} diff --git a/bench/tx.js b/bench/tx.js index 7d0374260..b6baa7cef 100644 --- a/bench/tx.js +++ b/bench/tx.js @@ -1,144 +1,200 @@ 'use strict'; -const fs = require('fs'); -const Block = require('../lib/primitives/block'); const Address = require('../lib/primitives/address'); const TX = require('../lib/primitives/tx'); const Script = require('../lib/script/script'); const MTX = require('../lib/primitives/mtx'); -const Coin = require('../lib/primitives/coin'); -const CoinView = require('../lib/coins/coinview'); const encoding = require('../lib/utils/encoding'); const random = require('../lib/crypto/random'); +const common = require('../test/util/common'); const bench = require('./bench'); -let json = require('../test/data/block300025.json'); -let block = Block.fromJSON(json); -let btx = { tx: block.txs[397], view: new CoinView() }; +const tx3 = common.readTX('tx3'); +const tx5 = common.readTX('tx5'); +const tx10 = common.readTX('tx10'); -let tx3 = parseTX('../test/data/tx3.hex'); -let wtx = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8'); -let i, tx, end, flags, input; +{ + const raw = tx5.getRaw(); + const end = bench('parse'); -wtx = Buffer.from(wtx.trim(), 'hex'); + for (let i = 0; i < 10000; i++) + TX.fromRaw(raw); -tx = json.txs[397]; -for (i = 0; i < tx.inputs.length; i++) { - input = tx.inputs[i]; - btx.view.addCoin(Coin.fromJSON(input.coin)); + end(10000); } -function parseTX(file) { - let data = fs.readFileSync(`${__dirname}/${file}`, 'utf8'); - let parts = data.trim().split(/\n+/); - let raw = parts[0]; - let tx = TX.fromRaw(raw.trim(), 'hex'); - let view = new CoinView(); - let i, prev; +{ + const [tx, view] = tx5.getTX(); + const end = bench('sigops'); - for (i = 1; i < parts.length; i++) { - raw = parts[i]; - prev = TX.fromRaw(raw.trim(), 'hex'); - view.addTX(prev, -1); + for (let i = 0; i < 100000; i++) + tx.getSigopsCost(view); + + end(100000); +} + +{ + const [tx] = tx5.getTX(); + const end = bench('serialize'); + + for (let i = 0; i < 10000; i++) { + tx._raw = null; + tx.toRaw(); } - return { tx: tx, view: view }; + end(10000); } -end = bench('parse'); -for (i = 0; i < 1000; i++) - tx = TX.fromRaw(wtx); -end(i); +{ + const [tx] = tx3.getTX(); + const end = bench('hash'); + + for (let i = 0; i < 30000; i++) { + tx.hash(); + tx._hash = null; + } -end = bench('serialize'); -for (i = 0; i < 1000; i++) { - tx._raw = null; - tx.toRaw(); + end(30000); } -end(i); -end = bench('hash'); -for (i = 0; i < 3000; i++) { - tx3.tx.hash(); - tx3.tx._hash = null; +{ + const [tx] = tx5.getTX(); + const end = bench('witness hash'); + + for (let i = 0; i < 30000; i++) { + tx.witnessHash(); + tx._whash = null; + } + + end(30000); } -end(i); -end = bench('witness hash'); -for (i = 0; i < 3000; i++) { - tx.witnessHash(); - tx._whash = null; +{ + const [tx] = tx5.getTX(); + const end = bench('sanity'); + + for (let i = 0; i < 10000; i++) + tx.isSane(); + + end(10000); } -end(i); -end = bench('sanity'); -for (i = 0; i < 1000; i++) - tx.isSane(); -end(i); +{ + const [tx] = tx5.getTX(); + const end = bench('input hashes'); -end = bench('input hashes'); -for (i = 0; i < 1000; i++) - tx.getInputHashes(null, 'hex'); -end(i); + for (let i = 0; i < 10000; i++) + tx.getInputHashes(null, 'hex'); -end = bench('output hashes'); -for (i = 0; i < 1000; i++) - tx.getOutputHashes('hex'); -end(i); + end(10000); +} + +{ + const [tx] = tx5.getTX(); + const end = bench('output hashes'); + + for (let i = 0; i < 10000; i++) + tx.getOutputHashes('hex'); + + end(10000); +} -end = bench('all hashes'); -for (i = 0; i < 1000; i++) - tx.getHashes(null, 'hex'); -end(i); +{ + const [tx] = tx5.getTX(); + const end = bench('all hashes'); -end = bench('verify'); -for (i = 0; i < 3000; i++) - tx3.tx.verify(tx3.view, Script.flags.VERIFY_P2SH); -end(i * tx3.tx.inputs.length); + for (let i = 0; i < 10000; i++) + tx.getHashes(null, 'hex'); -end = bench('fee'); -for (i = 0; i < 1000; i++) - tx3.tx.getFee(tx3.view); -end(i); + end(10000); +} + +{ + const [tx, view] = tx3.getTX(); + const end = bench('verify'); + + for (let i = 0; i < 30000; i++) + tx.verify(view, Script.flags.VERIFY_P2SH); + + end(30000 * tx.inputs.length); +} -flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; -end = bench('verify multisig'); -for (i = 0; i < 3000; i++) - btx.tx.verify(btx.view, flags); -end(i * btx.tx.inputs.length); +{ + const [tx, view] = tx3.getTX(); + const {script} = view.getOutputFor(tx.inputs[0]); + const end = bench('sighash'); -tx = new MTX(); + for (let i = 0; i < 1000000; i++) + tx.signatureHashV0(0, script, Script.hashType.ALL); -for (i = 0; i < 100; i++) { - tx.addInput({ + end(1000000); +} + +{ + const [tx, view] = tx3.getTX(); + const end = bench('fee'); + + for (let i = 0; i < 10000; i++) + tx.getFee(view); + + end(10000); +} + +{ + const [tx, view] = tx10.getTX(); + const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; + const end = bench('verify multisig'); + + for (let i = 0; i < 30000; i++) + tx.verify(view, flags); + + end(30000 * tx.inputs.length); +} + +const mtx = new MTX(); + +for (let i = 0; i < 100; i++) { + mtx.addInput({ prevout: { hash: encoding.NULL_HASH, index: 0 }, - script: [ - Buffer.allocUnsafe(9), - random.randomBytes(33) - ] + script: new Script() + .pushData(Buffer.allocUnsafe(9)) + .pushData(random.randomBytes(33)) + .compile() }); - tx.addOutput({ + mtx.addOutput({ address: Address.fromHash(random.randomBytes(20)), value: 0 }); } -tx = tx.toTX(); +const tx2 = mtx.toTX(); + +{ + const end = bench('input hashes'); + + for (let i = 0; i < 10000; i++) + tx2.getInputHashes(null, 'hex'); + + end(10000); +} + +{ + const end = bench('output hashes'); + + for (let i = 0; i < 10000; i++) + tx2.getOutputHashes('hex'); -end = bench('input hashes'); -for (i = 0; i < 1000; i++) - tx.getInputHashes(null, 'hex'); -end(i); + end(10000); +} -end = bench('output hashes'); -for (i = 0; i < 1000; i++) - tx.getOutputHashes('hex'); -end(i); +{ + const end = bench('all hashes'); -end = bench('all hashes'); -for (i = 0; i < 1000; i++) - tx.getHashes(null, 'hex'); -end(i); + for (let i = 0; i < 10000; i++) + tx2.getHashes(null, 'hex'); + + end(10000); +} diff --git a/bench/walletdb.js b/bench/walletdb.js index 2d7c04930..226024c86 100644 --- a/bench/walletdb.js +++ b/bench/walletdb.js @@ -5,115 +5,128 @@ const random = require('../lib/crypto/random'); const WalletDB = require('../lib/wallet/walletdb'); const MTX = require('../lib/primitives/mtx'); const Outpoint = require('../lib/primitives/outpoint'); -let walletdb; function dummy() { - let hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32).toString('hex'); return new Outpoint(hash, 0); } -walletdb = new WalletDB({ +const walletdb = new WalletDB({ name: 'wallet-test', db: 'memory', resolution: false, verify: false }); -async function runBench() { - let i, j, wallet, addrs, jobs, end; - let result, tx, mtx, options; - +(async () => { // Open and Create await walletdb.open(); - wallet = await walletdb.create(); - addrs = []; + + const wallet = await walletdb.create(); + const addrs = []; + let tx; // Accounts - jobs = []; - for (i = 0; i < 1000; i++) - jobs.push(wallet.createAccount({})); + { + const jobs = []; + for (let i = 0; i < 1000; i++) + jobs.push(wallet.createAccount({})); - end = bench('accounts'); - result = await Promise.all(jobs); - end(1000); + const end = bench('accounts'); + const result = await Promise.all(jobs); + end(1000); - for (i = 0; i < result.length; i++) - addrs.push(result[i].receive.getAddress()); + for (const addr of result) + addrs.push(addr.receive.getAddress()); + } // Keys - jobs = []; - for (i = 0; i < 1000; i++) { - for (j = 0; j < 10; j++) - jobs.push(wallet.createReceive(i)); + { + const jobs = []; + for (let i = 0; i < 1000; i++) { + for (let j = 0; j < 10; j++) + jobs.push(wallet.createReceive(i)); + } + + const end = bench('keys'); + const result = await Promise.all(jobs); + end(1000 * 10); + + for (const addr of result) + addrs.push(addr.getAddress()); } - end = bench('keys'); - result = await Promise.all(jobs); - end(1000 * 10); - - for (i = 0; i < result.length; i++) - addrs.push(result[i].getAddress()); - // TX deposit - jobs = []; - for (i = 0; i < 10000; i++) { - mtx = new MTX(); - mtx.addOutpoint(dummy()); - mtx.addOutput(addrs[(i + 0) % addrs.length], 50460); - mtx.addOutput(addrs[(i + 1) % addrs.length], 50460); - mtx.addOutput(addrs[(i + 2) % addrs.length], 50460); - mtx.addOutput(addrs[(i + 3) % addrs.length], 50460); - tx = mtx.toTX(); - - jobs.push(walletdb.addTX(tx)); + { + const jobs = []; + for (let i = 0; i < 10000; i++) { + const mtx = new MTX(); + mtx.addOutpoint(dummy()); + mtx.addOutput(addrs[(i + 0) % addrs.length], 50460); + mtx.addOutput(addrs[(i + 1) % addrs.length], 50460); + mtx.addOutput(addrs[(i + 2) % addrs.length], 50460); + mtx.addOutput(addrs[(i + 3) % addrs.length], 50460); + tx = mtx.toTX(); + + jobs.push(walletdb.addTX(tx)); + } + + const end = bench('deposit'); + await Promise.all(jobs); + end(10000); } - end = bench('deposit'); - result = await Promise.all(jobs); - end(10000); - // TX redemption - jobs = []; - for (i = 0; i < 10000; i++) { - mtx = new MTX(); - mtx.addTX(tx, 0); - mtx.addTX(tx, 1); - mtx.addTX(tx, 2); - mtx.addTX(tx, 3); - mtx.addOutput(addrs[(i + 0) % addrs.length], 50460); - mtx.addOutput(addrs[(i + 1) % addrs.length], 50460); - mtx.addOutput(addrs[(i + 2) % addrs.length], 50460); - mtx.addOutput(addrs[(i + 3) % addrs.length], 50460); - tx = mtx.toTX(); - - jobs.push(walletdb.addTX(tx)); + { + const jobs = []; + for (let i = 0; i < 10000; i++) { + const mtx = new MTX(); + mtx.addTX(tx, 0); + mtx.addTX(tx, 1); + mtx.addTX(tx, 2); + mtx.addTX(tx, 3); + mtx.addOutput(addrs[(i + 0) % addrs.length], 50460); + mtx.addOutput(addrs[(i + 1) % addrs.length], 50460); + mtx.addOutput(addrs[(i + 2) % addrs.length], 50460); + mtx.addOutput(addrs[(i + 3) % addrs.length], 50460); + tx = mtx.toTX(); + + jobs.push(walletdb.addTX(tx)); + } + + const end = bench('redemption'); + await Promise.all(jobs); + end(10000); } - end = bench('redemption'); - result = await Promise.all(jobs); - end(10000); - // Balance - end = bench('balance'); - result = await wallet.getBalance(); - end(1); + { + const end = bench('balance'); + await wallet.getBalance(); + end(1); + } // Coins - end = bench('coins'); - result = await wallet.getCoins(); - end(1); + { + const end = bench('coins'); + await wallet.getCoins(); + end(1); + } // Create - end = bench('create'); - options = { - rate: 10000, - outputs: [{ - value: 50460, - address: addrs[0] - }] - }; - await wallet.createTX(options); - end(1); -} - -runBench().then(process.exit); + { + const end = bench('create'); + const options = { + rate: 10000, + outputs: [{ + value: 50460, + address: addrs[0] + }] + }; + await wallet.createTX(options); + end(1); + } +})().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/bin/cli b/bin/cli index 353237ee3..77abe537c 100755 --- a/bin/cli +++ b/bin/cli @@ -7,6 +7,10 @@ const util = require('../lib/utils/util'); const Client = require('../lib/http/client'); const Wallet = require('../lib/http/wallet'); +const ANTIREPLAY = '' + + '6a2e426974636f696e3a204120506565722d746f2d5065657' + + '220456c656374726f6e696320436173682053797374656d'; + function CLI() { this.config = new Config('bcoin'); @@ -25,29 +29,27 @@ function CLI() { CLI.prototype.log = function log(json) { if (typeof json === 'string') return console.log.apply(console, arguments); - console.log(JSON.stringify(json, null, 2)); + return console.log(JSON.stringify(json, null, 2)); }; CLI.prototype.getInfo = async function getInfo() { - let info = await this.client.getInfo(); + const info = await this.client.getInfo(); this.log(info); }; CLI.prototype.getWallets = async function getWallets() { - let wallets = await this.client.getWallets(); + const wallets = await this.client.getWallets(); this.log(wallets); }; CLI.prototype.createWallet = async function createWallet() { - let options, wallet; - - options = { + const options = { id: this.config.str([0, 'id']), type: this.config.str('type'), master: this.config.str('master'), mnemonic: this.config.str('mnemonic'), - m: this.config.num('m'), - n: this.config.num('n'), + m: this.config.uint('m'), + n: this.config.uint('n'), witness: this.config.bool('witness'), passphrase: this.config.str('passphrase'), watchOnly: false, @@ -59,111 +61,117 @@ CLI.prototype.createWallet = async function createWallet() { options.accountKey = this.config.str('watch'); } - wallet = await this.client.createWallet(options); + const wallet = await this.client.createWallet(options); this.log(wallet); }; CLI.prototype.getMaster = async function getMaster() { - let master = await this.wallet.getMaster(); + const master = await this.wallet.getMaster(); this.log(master); }; CLI.prototype.getKey = async function getKey() { - let address = this.config.str(0); - let key = await this.wallet.getKey(address); + const address = this.config.str(0); + const key = await this.wallet.getKey(address); this.log(key); }; CLI.prototype.getWIF = async function getWIF() { - let address = this.config.str(0); - let passphrase = this.config.str('passphrase'); - let key = await this.wallet.getWIF(address, passphrase); + const address = this.config.str(0); + const passphrase = this.config.str('passphrase'); + const key = await this.wallet.getWIF(address, passphrase); + if (!key) { + this.log('Key not found.'); + return; + } this.log(key.privateKey); }; CLI.prototype.addSharedKey = async function addSharedKey() { - let key = this.config.str(0); - let account = this.config.str('account'); + const key = this.config.str(0); + const account = this.config.str('account'); await this.wallet.addSharedKey(account, key); this.log('Added key.'); }; CLI.prototype.removeSharedKey = async function removeSharedKey() { - let key = this.config.str(0); - let account = this.config.str('account'); + const key = this.config.str(0); + const account = this.config.str('account'); await this.wallet.removeSharedKey(account, key); this.log('Removed key.'); }; CLI.prototype.getSharedKeys = async function getSharedKeys() { - let acct = this.config.str([0, 'account']); - let account = await this.wallet.getAccount(acct); + const acct = this.config.str([0, 'account']); + const account = await this.wallet.getAccount(acct); + if (!account) { + this.log('Account not found.'); + return; + } this.log(account.keys); }; CLI.prototype.getAccount = async function getAccount() { - let acct = this.config.str([0, 'account']); - let account = await this.wallet.getAccount(acct); + const acct = this.config.str([0, 'account']); + const account = await this.wallet.getAccount(acct); this.log(account); }; CLI.prototype.createAccount = async function createAccount() { - let name = this.config.str([0, 'name']); - let options, account; + const name = this.config.str([0, 'name']); - options = { + const options = { type: this.config.str('type'), - m: this.config.num('m'), - n: this.config.num('n'), + m: this.config.uint('m'), + n: this.config.uint('n'), witness: this.config.bool('witness'), accountKey: this.config.str('watch') }; - account = await this.wallet.createAccount(name, options); + const account = await this.wallet.createAccount(name, options); this.log(account); }; CLI.prototype.createAddress = async function createAddress() { - let account = this.config.str([0, 'account']); - let addr = await this.wallet.createAddress(account); + const account = this.config.str([0, 'account']); + const addr = await this.wallet.createAddress(account); this.log(addr); }; CLI.prototype.createChange = async function createChange() { - let account = this.config.str([0, 'account']); - let addr = await this.wallet.createChange(account); + const account = this.config.str([0, 'account']); + const addr = await this.wallet.createChange(account); this.log(addr); }; CLI.prototype.createNested = async function createNested() { - let account = this.config.str([0, 'account']); - let addr = await this.wallet.createNested(account); + const account = this.config.str([0, 'account']); + const addr = await this.wallet.createNested(account); this.log(addr); }; CLI.prototype.getAccounts = async function getAccounts() { - let accounts = await this.wallet.getAccounts(); + const accounts = await this.wallet.getAccounts(); this.log(accounts); }; CLI.prototype.getWallet = async function getWallet() { - let info = await this.wallet.getInfo(); + const info = await this.wallet.getInfo(); this.log(info); }; CLI.prototype.getTX = async function getTX() { - let hash = this.config.str(0); - let txs, tx; + const hash = this.config.str(0); if (util.isBase58(hash)) { - txs = await this.client.getTXByAddress(hash); + const txs = await this.client.getTXByAddress(hash); this.log(txs); return; } - tx = await this.client.getTX(hash); + const tx = await this.client.getTX(hash); if (!tx) { this.log('TX not found.'); @@ -175,12 +183,11 @@ CLI.prototype.getTX = async function getTX() { CLI.prototype.getBlock = async function getBlock() { let hash = this.config.str(0); - let block; if (hash.length !== 64) - hash = +hash; + hash = parseInt(hash, 10); - block = await this.client.getBlock(hash); + const block = await this.client.getBlock(hash); if (!block) { this.log('Block not found.'); @@ -191,17 +198,16 @@ CLI.prototype.getBlock = async function getBlock() { }; CLI.prototype.getCoin = async function getCoin() { - let hash = this.config.str(0); - let index = this.config.num(1); - let coins, coin; + const hash = this.config.str(0); + const index = this.config.uint(1); if (util.isBase58(hash)) { - coins = await this.client.getCoinsByAddress(hash); + const coins = await this.client.getCoinsByAddress(hash); this.log(coins); return; } - coin = await this.client.getCoin(hash, index); + const coin = await this.client.getCoin(hash, index); if (!coin) { this.log('Coin not found.'); @@ -212,20 +218,20 @@ CLI.prototype.getCoin = async function getCoin() { }; CLI.prototype.getWalletHistory = async function getWalletHistory() { - let account = this.config.str('account'); - let txs = await this.wallet.getHistory(account); + const account = this.config.str('account'); + const txs = await this.wallet.getHistory(account); this.log(txs); }; CLI.prototype.getWalletPending = async function getWalletPending() { - let account = this.config.str('account'); - let txs = await this.wallet.getPending(account); + const account = this.config.str('account'); + const txs = await this.wallet.getPending(account); this.log(txs); }; CLI.prototype.getWalletCoins = async function getWalletCoins() { - let account = this.config.str('account'); - let coins = await this.wallet.getCoins(account); + const account = this.config.str('account'); + const coins = await this.wallet.getCoins(account); this.log(coins); }; @@ -266,124 +272,132 @@ CLI.prototype.listenWallet = async function listenWallet() { }; CLI.prototype.getBalance = async function getBalance() { - let account = this.config.str('account'); - let balance = await this.wallet.getBalance(account); + const account = this.config.str('account'); + const balance = await this.wallet.getBalance(account); this.log(balance); }; CLI.prototype.getMempool = async function getMempool() { - let txs = await this.client.getMempool(); + const txs = await this.client.getMempool(); this.log(txs); }; CLI.prototype.sendTX = async function sendTX() { - let output, options, tx; + const outputs = []; if (this.config.has('script')) { - output = { + outputs.push({ script: this.config.str('script'), - value: this.config.amt([0, 'value']) - }; + value: this.config.ufixed([0, 'value'], 8) + }); } else { - output = { + outputs.push({ address: this.config.str([0, 'address']), - value: this.config.amt([1, 'value']) - }; + value: this.config.ufixed([1, 'value'], 8) + }); } - options = { + if (this.config.bool('no-replay')) { + outputs.push({ + script: ANTIREPLAY, + value: 0 + }); + } + + const options = { account: this.config.str('account'), passphrase: this.config.str('passphrase'), - outputs: [output], + outputs: outputs, smart: this.config.bool('smart'), - rate: this.config.amt('rate'), + rate: this.config.ufixed('rate', 8), subtractFee: this.config.bool('subtract-fee') }; - tx = await this.wallet.send(options); + const tx = await this.wallet.send(options); this.log(tx); }; CLI.prototype.createTX = async function createTX() { - let output, options, tx; + let output; if (this.config.has('script')) { output = { script: this.config.str('script'), - value: this.config.amt([0, 'value']) + value: this.config.ufixed([0, 'value'], 8) }; } else { output = { address: this.config.str([0, 'address']), - value: this.config.amt([1, 'value']) + value: this.config.ufixed([1, 'value'], 8) }; } - options = { + const options = { account: this.config.str('account'), passphrase: this.config.str('passphrase'), outputs: [output], smart: this.config.bool('smart'), - rate: this.config.amt('rate') + rate: this.config.ufixed('rate', 8), + subtractFee: this.config.bool('subtract-fee') }; - tx = await this.wallet.createTX(options); + const tx = await this.wallet.createTX(options); this.log(tx); }; CLI.prototype.signTX = async function signTX() { - let passphrase = this.config.str('passphrase'); - let raw = this.config.str([0, 'tx']); - let tx = await this.wallet.sign(raw, { passphrase }); + const passphrase = this.config.str('passphrase'); + const raw = this.config.str([0, 'tx']); + const tx = await this.wallet.sign(raw, { passphrase }); this.log(tx); }; CLI.prototype.zapWallet = async function zapWallet() { - let age = this.config.num([0, 'age'], 72 * 60 * 60); + const age = this.config.uint([0, 'age'], 72 * 60 * 60); await this.wallet.zap(this.config.str('account'), age); this.log('Zapped!'); }; CLI.prototype.broadcast = async function broadcast() { - let raw = this.config.str([0, 'tx']); - let tx = await this.client.broadcast(raw); + const raw = this.config.str([0, 'tx']); + const tx = await this.client.broadcast(raw); this.log('Broadcasted:'); this.log(tx); }; CLI.prototype.viewTX = async function viewTX() { - let raw = this.config.str([0, 'tx']); - let tx = await this.wallet.fill(raw); + const raw = this.config.str([0, 'tx']); + const tx = await this.wallet.fill(raw); this.log(tx); }; CLI.prototype.getDetails = async function getDetails() { - let hash = this.config.str(0); - let details = await this.wallet.getTX(hash); + const hash = this.config.str(0); + const details = await this.wallet.getTX(hash); this.log(details); }; CLI.prototype.getWalletBlocks = async function getWalletBlocks() { - let blocks = await this.wallet.getBlocks(); + const blocks = await this.wallet.getBlocks(); this.log(blocks); }; CLI.prototype.getWalletBlock = async function getWalletBlock() { - let height = this.config.num(0); - let block = await this.wallet.getBlock(height); + const height = this.config.uint(0); + const block = await this.wallet.getBlock(height); this.log(block); }; CLI.prototype.retoken = async function retoken() { - let result = await this.wallet.retoken(); + const result = await this.wallet.retoken(); this.log(result); }; CLI.prototype.rescan = async function rescan() { - let height = this.config.num(0); + const height = this.config.uint(0); await this.client.rescan(height); this.log('Rescanning...'); }; @@ -392,7 +406,7 @@ CLI.prototype.reset = async function reset() { let hash = this.config.str(0); if (hash.length !== 64) - hash = +hash; + hash = parseInt(hash, 10); await this.client.reset(hash); @@ -410,7 +424,7 @@ CLI.prototype.resendWallet = async function resendWallet() { }; CLI.prototype.backup = async function backup() { - let path = this.config.str(0); + const path = this.config.str(0); await this.client.backup(path); @@ -418,8 +432,8 @@ CLI.prototype.backup = async function backup() { }; CLI.prototype.importKey = async function importKey() { - let key = this.config.str(0); - let account = this.config.str('account'); + const key = this.config.str(0); + const account = this.config.str('account'); if (!key) throw new Error('No key for import.'); @@ -439,9 +453,9 @@ CLI.prototype.importKey = async function importKey() { throw new Error('Bad key for import.'); }; -CLI.prototype.importAddress = async function importKey() { - let address = this.config.str(0); - let account = this.config.str('account'); +CLI.prototype.importAddress = async function importAddress() { + const address = this.config.str(0); + const account = this.config.str('account'); await this.wallet.importAddress(account, address); this.log('Imported address.'); }; @@ -452,18 +466,17 @@ CLI.prototype.lock = async function lock() { }; CLI.prototype.unlock = async function unlock() { - let passphrase = this.config.str(0); - let timeout = this.config.num(1); + const passphrase = this.config.str(0); + const timeout = this.config.uint(1); await this.wallet.unlock(passphrase, timeout); this.log('Unlocked.'); }; CLI.prototype.rpc = async function rpc() { - let method = this.argv.shift(); - let params = []; - let result; + const method = this.argv.shift(); + const params = []; - for (let arg of this.argv) { + for (const arg of this.argv) { let param; try { param = JSON.parse(arg); @@ -473,6 +486,7 @@ CLI.prototype.rpc = async function rpc() { params.push(param); } + let result; try { result = await this.client.rpc.execute(method, params); } catch (e) { @@ -497,81 +511,113 @@ CLI.prototype.handleWallet = async function handleWallet() { switch (this.argv.shift()) { case 'listen': - return await this.listenWallet(); + await this.listenWallet(); + break; case 'get': - return await this.getWallet(); + await this.getWallet(); + break; case 'master': - return await this.getMaster(); + await this.getMaster(); + break; case 'shared': if (this.argv[0] === 'add') { this.argv.shift(); - return await this.addSharedKey(); + await this.addSharedKey(); + break; } if (this.argv[0] === 'remove') { this.argv.shift(); - return await this.removeSharedKey(); + await this.removeSharedKey(); + break; } if (this.argv[0] === 'list') this.argv.shift(); - return await this.getSharedKeys(); + await this.getSharedKeys(); + break; case 'balance': - return await this.getBalance(); + await this.getBalance(); + break; case 'history': - return await this.getWalletHistory(); + await this.getWalletHistory(); + break; case 'pending': - return await this.getWalletPending(); + await this.getWalletPending(); + break; case 'coins': - return await this.getWalletCoins(); + await this.getWalletCoins(); + break; case 'account': if (this.argv[0] === 'list') { this.argv.shift(); - return await this.getAccounts(); + await this.getAccounts(); + break; } if (this.argv[0] === 'create') { this.argv.shift(); - return await this.createAccount(); + await this.createAccount(); + break; } if (this.argv[0] === 'get') this.argv.shift(); - return await this.getAccount(); + await this.getAccount(); + break; case 'address': - return await this.createAddress(); + await this.createAddress(); + break; case 'change': - return await this.createChange(); + await this.createChange(); + break; case 'nested': - return await this.createNested(); + await this.createNested(); + break; case 'retoken': - return await this.retoken(); + await this.retoken(); + break; case 'sign': - return await this.signTX(); + await this.signTX(); + break; case 'mktx': - return await this.createTX(); + await this.createTX(); + break; case 'send': - return await this.sendTX(); + await this.sendTX(); + break; case 'zap': - return await this.zapWallet(); + await this.zapWallet(); + break; case 'tx': - return await this.getDetails(); + await this.getDetails(); + break; case 'blocks': - return await this.getWalletBlocks(); + await this.getWalletBlocks(); + break; case 'block': - return await this.getWalletBlock(); + await this.getWalletBlock(); + break; case 'view': - return await this.viewTX(); + await this.viewTX(); + break; case 'import': - return await this.importKey(); + await this.importKey(); + break; case 'watch': - return await this.importAddress(); + await this.importAddress(); + break; case 'key': - return await this.getKey(); + await this.getKey(); + break; case 'dump': - return await this.getWIF(); + await this.getWIF(); + break; case 'lock': - return await this.lock(); + await this.lock(); + break; case 'unlock': - return await this.unlock(); + await this.unlock(); + break; case 'resend': - return await this.resendWallet(); + await this.resendWallet(); + break; default: this.log('Unrecognized command.'); this.log('Commands:'); @@ -607,9 +653,9 @@ CLI.prototype.handleWallet = async function handleWallet() { this.log(' $ unlock [passphrase] [timeout?]: Unlock wallet.'); this.log(' $ resend: Resend pending transactions.'); this.log('Other Options:'); - this.log(' --passphrase [passphrase]: For signing and account creation.'); + this.log(' --passphrase [passphrase]: For signing & account creation.'); this.log(' --account [account-name]: Account name.'); - return; + break; } }; @@ -622,31 +668,44 @@ CLI.prototype.handleNode = async function handleNode() { switch (this.argv.shift()) { case 'info': - return await this.getInfo(); + await this.getInfo(); + break; case 'wallets': - return await this.getWallets(); + await this.getWallets(); + break; case 'mkwallet': - return await this.createWallet(); + await this.createWallet(); + break; case 'broadcast': - return await this.broadcast(); + await this.broadcast(); + break; case 'mempool': - return await this.getMempool(); + await this.getMempool(); + break; case 'tx': - return await this.getTX(); + await this.getTX(); + break; case 'coin': - return await this.getCoin(); + await this.getCoin(); + break; case 'block': - return await this.getBlock(); + await this.getBlock(); + break; case 'rescan': - return await this.rescan(); + await this.rescan(); + break; case 'reset': - return await this.reset(); + await this.reset(); + break; case 'resend': - return await this.resend(); + await this.resend(); + break; case 'backup': - return await this.backup(); + await this.backup(); + break; case 'rpc': - return await this.rpc(); + await this.rpc(); + break; default: this.log('Unrecognized command.'); this.log('Commands:'); @@ -663,7 +722,7 @@ CLI.prototype.handleNode = async function handleNode() { this.log(' $ resend: Resend pending transactions.'); this.log(' $ backup [path]: Backup the wallet db.'); this.log(' $ rpc [command] [args]: Execute RPC command.'); - return; + break; } }; @@ -674,29 +733,33 @@ CLI.prototype.open = async function open() { this.argv.shift(); if (this.argv[0] === 'create') { this.argv[0] = 'mkwallet'; - return await this.handleNode(); + await this.handleNode(); + break; } - return await this.handleWallet(); + await this.handleWallet(); + break; default: - return await this.handleNode(); + await this.handleNode(); + break; } }; CLI.prototype.destroy = function destroy() { if (this.wallet) this.wallet.client.destroy(); + if (this.client) this.client.destroy(); + return Promise.resolve(); }; -async function main() { - let cli = new CLI(); +(async () => { + const cli = new CLI(); await cli.open(); await cli.destroy(); -} - -main().then(process.exit).catch((err) => { - console.error(err.stack + ''); - return process.exit(1); + process.exit(0); +})().catch((err) => { + console.error(err.stack); + process.exit(1); }); diff --git a/bin/node b/bin/node index e3b15645f..3ed9a5ee5 100755 --- a/bin/node +++ b/bin/node @@ -19,10 +19,9 @@ if (process.argv.indexOf('--version') !== -1 throw new Error('Could not exit.'); } -const bcoin = require('../'); -const plugin = require('../lib/wallet/plugin'); +const FullNode = require('../lib/node/fullnode'); -const node = new bcoin.fullnode({ +const node = new FullNode({ config: true, argv: true, env: true, @@ -37,8 +36,10 @@ const node = new bcoin.fullnode({ }); // Temporary hack -if (!node.config.bool('no-wallet') && !node.has('walletdb')) +if (!node.config.bool('no-wallet') && !node.has('walletdb')) { + const plugin = require('../lib/wallet/plugin'); node.use(plugin); +} process.on('unhandledRejection', (err, promise) => { throw err; diff --git a/bin/spvnode b/bin/spvnode index d10e981ad..71fae73e3 100755 --- a/bin/spvnode +++ b/bin/spvnode @@ -5,11 +5,11 @@ process.title = 'bcoin'; const assert = require('assert'); -const bcoin = require('../'); -const plugin = require('../lib/wallet/plugin'); -const util = bcoin.util; +const SPVNode = require('../lib/node/spvnode'); +const util = require('../lib/utils/util'); +const Outpoint = require('../lib/primitives/outpoint'); -const node = bcoin.spvnode({ +const node = SPVNode({ config: true, argv: true, env: true, @@ -24,8 +24,10 @@ const node = bcoin.spvnode({ }); // Temporary hack -if (!node.has('walletdb')) +if (!node.has('walletdb')) { + const plugin = require('../lib/wallet/plugin'); node.use(plugin); +} process.on('unhandledRejection', (err, promise) => { throw err; @@ -38,7 +40,7 @@ process.on('unhandledRejection', (err, promise) => { if (node.config.bool('test')) { node.pool.watchAddress('1VayNert3x1KzbpzMGt2qdqrAThiRovi8'); - node.pool.watchOutpoint(new bcoin.outpoint()); + node.pool.watchOutpoint(new Outpoint()); node.on('block', (block) => { assert(block.txs.length >= 1); if (block.txs.length > 1) diff --git a/browser/server.js b/browser/server.js index ea3775126..9d914fbf6 100644 --- a/browser/server.js +++ b/browser/server.js @@ -1,6 +1,6 @@ 'use strict'; -const fs = require('fs'); +const fs = require('../lib/utils/fs'); const HTTPBase = require('../lib/http/base'); const WSProxy = require('./wsproxy'); @@ -10,22 +10,22 @@ const debug = fs.readFileSync(`${__dirname}/debug.html`); const bcoin = fs.readFileSync(`${__dirname}/bcoin.js`); const worker = fs.readFileSync(`${__dirname}/bcoin-worker.js`); -let proxy = new WSProxy({ +const proxy = new WSProxy({ pow: process.argv.indexOf('--pow') !== -1, ports: [8333, 18333, 18444, 28333, 28901] }); -let server = new HTTPBase({ - port: +process.argv[2] || 8080, +const server = new HTTPBase({ + port: Number(process.argv[2]) || 8080, sockets: false }); proxy.on('error', (err) => { - console.error(err.stack + ''); + console.error(err.stack); }); server.on('error', (err) => { - console.error(err.stack + ''); + console.error(err.stack); }); server.get('/favicon.ico', (req, res) => { diff --git a/browser/wsproxy.js b/browser/wsproxy.js index 5aef4e16b..b92121174 100644 --- a/browser/wsproxy.js +++ b/browser/wsproxy.js @@ -1,5 +1,6 @@ 'use strict'; +const assert = require('assert'); const net = require('net'); const EventEmitter = require('events').EventEmitter; const IOServer = require('socket.io'); @@ -8,8 +9,6 @@ const digest = require('../lib/crypto/digest'); const IP = require('../lib/utils/ip'); const BufferWriter = require('../lib/utils/writer'); -const NAME_REGEX = /^[a-z0-9\-\.]+?\.(?:be|me|org|com|net|ch|de)$/i; - const TARGET = Buffer.from( '0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 'hex'); @@ -26,27 +25,32 @@ function WSProxy(options) { this.options = options; this.target = options.target || TARGET; this.pow = options.pow === true; - this.ports = options.ports || []; + this.ports = new Set(); this.io = new IOServer(); this.sockets = new WeakMap(); - this._init(); + if (options.ports) { + for (const port of options.ports) + this.ports.add(port); + } + + this.init(); } -util.inherits(WSProxy, EventEmitter); +Object.setPrototypeOf(WSProxy.prototype, EventEmitter.prototype); -WSProxy.prototype._init = function _init() { +WSProxy.prototype.init = function init() { this.io.on('error', (err) => { this.emit('error', err); }); this.io.on('connection', (ws) => { - this._handleSocket(ws); + this.handleSocket(ws); }); }; -WSProxy.prototype._handleSocket = function _handleSocket(ws) { - let state = new SocketState(this, ws); +WSProxy.prototype.handleSocket = function handleSocket(ws) { + const state = new SocketState(this, ws); // Use a weak map to avoid // mutating the websocket object. @@ -59,20 +63,20 @@ WSProxy.prototype._handleSocket = function _handleSocket(ws) { }); ws.on('tcp connect', (port, host, nonce) => { - this._handleConnect(ws, port, host, nonce); + this.handleConnect(ws, port, host, nonce); }); }; -WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce) { - let state = this.sockets.get(ws); - let socket, pow, raw; +WSProxy.prototype.handleConnect = function handleConnect(ws, port, host, nonce) { + const state = this.sockets.get(ws); + assert(state); if (state.socket) { this.log('Client is trying to reconnect (%s).', state.host); return; } - if (!util.isNumber(port) + if (!util.isU16(port) || typeof host !== 'string' || host.length === 0) { this.log('Client gave bad arguments (%s).', state.host); @@ -82,19 +86,20 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce } if (this.pow) { - if (!util.isNumber(nonce)) { + if (!util.isU32(nonce)) { this.log('Client did not solve proof of work (%s).', state.host); ws.emit('tcp close'); ws.disconnect(); return; } - pow = new BufferWriter(); - pow.writeU32(nonce); - pow.writeBytes(state.snonce); - pow.writeU32(port); - pow.writeString(host, 'ascii'); - pow = pow.render(); + const bw = new BufferWriter(); + bw.writeU32(nonce); + bw.writeBytes(state.snonce); + bw.writeU32(port); + bw.writeString(host, 'ascii'); + + const pow = bw.render(); if (digest.hash256(pow).compare(this.target) > 0) { this.log('Client did not solve proof of work (%s).', state.host); @@ -104,9 +109,10 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce } } + let raw, addr; try { raw = IP.toBuffer(host); - host = IP.toString(raw); + addr = IP.toString(raw); } catch (e) { this.log('Client gave a bad host: %s (%s).', host, state.host); ws.emit('tcp error', { @@ -120,7 +126,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce if (!IP.isRoutable(raw) || IP.isOnion(raw)) { this.log( 'Client is trying to connect to a bad ip: %s (%s).', - host, state.host); + addr, state.host); ws.emit('tcp error', { message: 'ENETUNREACH', code: 'ENETUNREACH' @@ -129,7 +135,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce return; } - if (this.ports.indexOf(port) === -1) { + if (!this.ports.has(port)) { this.log('Client is connecting to non-whitelist port (%s).', state.host); ws.emit('tcp error', { message: 'ENETUNREACH', @@ -139,8 +145,9 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce return; } + let socket; try { - socket = state.connect(port, host); + socket = state.connect(port, addr); this.log('Connecting to %s (%s).', state.remoteHost, state.host); } catch (e) { this.log(e.message); diff --git a/docs/Example-Connecting-to-the-P2P-Network.md b/docs/Example-Connecting-to-the-P2P-Network.md deleted file mode 100644 index c25453d91..000000000 --- a/docs/Example-Connecting-to-the-P2P-Network.md +++ /dev/null @@ -1,86 +0,0 @@ -``` js -var bcoin = require('bcoin').set('main'); - -// Create a blockchain and store it in leveldb. -// `db` also accepts `rocksdb` and `lmdb`. -var prefix = process.env.HOME + '/my-bcoin-environment'; -var chain = new bcoin.chain({ db: 'leveldb', location: prefix + '/chain' }); - -var mempool = new bcoin.mempool({ chain: chain }); - -// Create a network pool of peers with a limit of 8 peers. -var pool = new bcoin.pool({ chain: chain, mempool: mempool, maxPeers: 8 }); - -// Open the pool (implicitly opens mempool and chain). -(async function() { - await pool.open(); - - // Connect, start retrieving and relaying txs - await pool.connect(); - - // Start the blockchain sync. - pool.startSync(); - - // Watch the action - chain.on('block', function(block) { - console.log('Connected block to blockchain:'); - console.log(block); - }); - - mempool.on('tx', function(tx) { - console.log('Added tx to mempool:'); - console.log(tx); - }); - - pool.on('tx', function(tx) { - console.log('Saw transaction:'); - console.log(tx.rhash); - }); -})(); - -// Start up a segnet4 sync in-memory -// while we're at it (because we can). - -var tchain = new bcoin.chain({ - network: 'segnet4', - db: 'memory' -}); - -var tmempool = new bcoin.mempool({ - network: 'segnet4', - chain: tchain -}); - -var tpool = new bcoin.pool({ - network: 'segnet4', - chain: tchain, - mempool: tmempool, - size: 8 -}); - -(async function() { - await pool.open(); - - // Connect, start retrieving and relaying txs - await tpool.connect(); - - // Start the blockchain sync. - tpool.startSync(); - - tchain.on('block', function(block) { - console.log('Added segnet4 block:'); - console.log(block); - }); - - tmempool.on('tx', function(tx) { - console.log('Added segnet4 tx to mempool:'); - console.log(tx); - }); - - tpool.on('tx', function(tx) { - console.log('Saw segnet4 transaction:'); - console.log(tx); - }); -})(); - -``` \ No newline at end of file diff --git a/docs/Example-Creating-a-Blockchain-and-Mempool.md b/docs/Example-Creating-a-Blockchain-and-Mempool.md deleted file mode 100644 index 0941d9319..000000000 --- a/docs/Example-Creating-a-Blockchain-and-Mempool.md +++ /dev/null @@ -1,35 +0,0 @@ -``` js -var bcoin = require('bcoin'); - -bcoin.set({ - // Default network (so we can avoid passing - // the `network` option into every object below. - network: 'regtest', - // Enable the global worker pool - // for mining and transaction verification. - useWorkers: true -}); - -// Start up a blockchain, mempool, and miner using in-memory -// databases (stored in a red-black tree instead of on-disk). -var chain = new bcoin.chain({ db: 'memory' }); -var mempool = new bcoin.mempool({ chain: chain }); -var miner = new bcoin.miner({ chain: chain, mempool: mempool }); - -// Open the miner (initialize the databases, etc). -// Miner will implicitly call `open` on chain and mempool. -miner.open().then(function() { - // Create a Cpu miner job - return miner.createJob(); -}).then(function(job) { - // Mine the block on the worker pool (use mine() for the master process) - return job.mineAsync(); -}).then(function(block) { - // Add the block to the chain - console.log('Adding %s to the blockchain.', block.rhash); - console.log(block); - return chain.add(block); -}).then(function() { - console.log('Added block!'); -}); -``` \ No newline at end of file diff --git a/docs/Example-Fullnode-Object.md b/docs/Example-Fullnode-Object.md deleted file mode 100644 index 92ddf4715..000000000 --- a/docs/Example-Fullnode-Object.md +++ /dev/null @@ -1,72 +0,0 @@ -``` js -var bcoin = require('bcoin').set('main'); - -var node = bcoin.fullnode({ - checkpoints: true, - // Primary wallet passphrase - passsphrase: 'node', - logLevel: 'info' -}); - -// We get a lot of errors sometimes, -// usually from peers hanging up on us. -// Just ignore them for now. -node.on('error', function(err) { - ; -}); - -// Start the node -node.open().then(function() { - // Create a new wallet (or get an existing one with the same ID) - var options = { - id: 'mywallet', - passphrase: 'foo', - witness: false, - type: 'pubkeyhash' - }; - - return node.walletdb.create(options); -}).then(function(wallet) { - console.log('Created wallet with address: %s', wallet.getAddress('base58')); - - node.connect().then(function() { - // Start syncing the blockchain - node.startSync(); - }); - - // Wait for balance and send it to a new address. - wallet.once('balance', function(balance) { - // Create a transaction, fill - // it with coins, and sign it. - var options = { - subtractFee: true, - outputs: [{ - address: newReceiving, - value: balance.total - }] - }; - wallet.createTX(options).then(function(tx) { - // Need to pass our passphrase back in to sign! - return wallet.sign(tx, 'foo'); - }).then(function(tx) { - console.log('sending tx:'); - console.log(tx); - return node.sendTX(tx); - }).then(function() { - console.log('tx sent!'); - }); - }); -}); - -node.chain.on('block', function(block) { - ; -}); - -node.mempool.on('tx', function(tx) { - ; -}); - -node.chain.on('full', function() { - node.mempool.getHistory().then(console.log); -}); -``` \ No newline at end of file diff --git a/docs/Example-SPV-Sync.md b/docs/Example-SPV-Sync.md deleted file mode 100644 index 1a08fc25a..000000000 --- a/docs/Example-SPV-Sync.md +++ /dev/null @@ -1,44 +0,0 @@ -``` js -var bcoin = require('bcoin').set('testnet'); - -// SPV chains only store the chain headers. -var chain = new bcoin.chain({ - db: 'leveldb', - location: process.env.HOME + '/spvchain', - spv: true -}); - -var pool = new bcoin.pool({ - chain: chain, - spv: true, - maxPeers: 8 -}); - -var walletdb = new bcoin.walletdb({ db: 'memory' }); - -pool.open().then(function() { - return walletdb.open(); -}).then(function() { - return walletdb.create(); -}).then(function(wallet) { - console.log('Created wallet with address %s', wallet.getAddress('base58')); - - // Add our address to the spv filter. - pool.watchAddress(wallet.getAddress()); - - // Connect, start retrieving and relaying txs - pool.connect().then(function() { - // Start the blockchain sync. - pool.startSync(); - - pool.on('tx', function(tx) { - walletdb.addTX(tx); - }); - - wallet.on('balance', function(balance) { - console.log('Balance updated.'); - console.log(bcoin.amount.btc(balance.unconfirmed)); - }); - }); -}); -``` \ No newline at end of file diff --git a/examples/client.js b/docs/Examples/client-api.js similarity index 54% rename from examples/client.js rename to docs/Examples/client-api.js index bce7efae8..2dbf1d0e2 100644 --- a/examples/client.js +++ b/docs/Examples/client-api.js @@ -1,15 +1,15 @@ 'use strict'; -const encoding = require('bcoin/lib/utils/encoding'); -const co = require('bcoin/lib/utils/co'); -const Outpoint = require('bcoin/lib/primitives/outpoint'); -const MTX = require('bcoin/lib/primitives/mtx'); -const HTTP = require('bcoin/lib/http'); -const FullNode = require('bcoin/lib/node/fullnode'); -const plugin = require('bcoin/lib/wallet/plugin'); -let node, wallet; - -node = new FullNode({ +const bcoin = require('../..'); +const encoding = bcoin.encoding; +const co = bcoin.co; +const Outpoint = bcoin.outpoint; +const MTX = bcoin.mtx; +const HTTP = bcoin.http; +const FullNode = bcoin.fullnode; +const plugin = bcoin.wallet.plugin; + +const node = new FullNode({ network: 'regtest', apiKey: 'foo', walletAuth: true, @@ -18,22 +18,21 @@ node = new FullNode({ node.use(plugin); -wallet = new HTTP.Wallet({ +const wallet = new HTTP.Wallet({ network: 'regtest', apiKey: 'foo' }); async function fundWallet(wdb, addr) { - let tx; - // Coinbase - tx = new MTX(); - tx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0)); - tx.addOutput(addr, 50460); - tx.addOutput(addr, 50460); - tx.addOutput(addr, 50460); - tx.addOutput(addr, 50460); - tx = tx.toTX(); + const mtx = new MTX(); + mtx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0)); + mtx.addOutput(addr, 50460); + mtx.addOutput(addr, 50460); + mtx.addOutput(addr, 50460); + mtx.addOutput(addr, 50460); + + const tx = mtx.toTX(); wallet.once('balance', (balance) => { console.log('New Balance:'); @@ -55,9 +54,7 @@ async function fundWallet(wdb, addr) { } async function sendTX(addr, value) { - let options, tx; - - options = { + const options = { rate: 10000, outputs: [{ value: value, @@ -65,31 +62,29 @@ async function sendTX(addr, value) { }] }; - tx = await wallet.send(options); + const tx = await wallet.send(options); return tx.hash; } async function callNodeApi() { - let info = await wallet.client.getInfo(); - let json; + const info = await wallet.client.getInfo(); console.log('Server Info:'); console.log(info); - json = await wallet.client.rpc.execute('getblocktemplate', []); + const json = await wallet.client.rpc.execute('getblocktemplate', []); console.log('Block Template (RPC):'); console.log(json); } (async () => { - let wdb = node.require('walletdb'); - let w, acct, hash, balance, tx; + const wdb = node.require('walletdb'); await node.open(); - w = await wallet.create({ id: 'test' }); + const w = await wallet.create({ id: 'test' }); console.log('Wallet:'); console.log(w); @@ -97,26 +92,29 @@ async function callNodeApi() { // Fund default account. await fundWallet(wdb, w.account.receiveAddress); - balance = await wallet.getBalance(); + const balance = await wallet.getBalance(); console.log('Balance:'); console.log(balance); - acct = await wallet.createAccount('foo'); + const acct = await wallet.createAccount('foo'); console.log('Account:'); console.log(acct); // Send to our new account. - hash = await sendTX(acct.receiveAddress, 10000); + const hash = await sendTX(acct.receiveAddress, 10000); console.log('Sent TX:'); console.log(hash); - tx = await wallet.getTX(hash); + const tx = await wallet.getTX(hash); console.log('Sent TX details:'); console.log(tx); await callNodeApi(); -})(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/examples/peer.js b/docs/Examples/connect-to-peer.js similarity index 62% rename from examples/peer.js rename to docs/Examples/connect-to-peer.js index a98757991..321cd141b 100644 --- a/examples/peer.js +++ b/docs/Examples/connect-to-peer.js @@ -1,14 +1,14 @@ 'use strict'; -// Usage: $ node ./examples/peer.js [ip]:[port] +// Usage: $ node ./docs/Examples/connect-to-peer.js [ip]:[port] -const Peer = require('bcoin/lib/net/peer'); -const NetAddress = require('bcoin/lib/primitives/netaddress'); -const Network = require('bcoin/lib/protocol/network'); +const bcoin = require('../..'); +const Peer = bcoin.peer; +const NetAddress = bcoin.netaddress; +const Network = bcoin.network; const network = Network.get('testnet'); -let peer, addr; -peer = Peer.fromOptions({ +const peer = Peer.fromOptions({ network: 'testnet', agent: 'my-subversion', hasWitness: () => { @@ -16,7 +16,9 @@ peer = Peer.fromOptions({ } }); -addr = NetAddress.fromHostname(process.argv[2], 'testnet'); +const addr = NetAddress.fromHostname(process.argv[2], 'testnet'); + +console.log(`Connecting to ${addr.hostname}`); peer.connect(addr); peer.tryOpen(); diff --git a/docs/Examples/connect-to-the-p2p-network.js b/docs/Examples/connect-to-the-p2p-network.js new file mode 100644 index 000000000..8024fa66d --- /dev/null +++ b/docs/Examples/connect-to-the-p2p-network.js @@ -0,0 +1,98 @@ +'use strict'; +const bcoin = require('../..').set('main'); +const Chain = bcoin.chain; +const Mempool = bcoin.mempool; +const Pool = bcoin.pool; + +// Create a blockchain and store it in leveldb. +// `db` also accepts `rocksdb` and `lmdb`. +const prefix = process.env.HOME + '/my-bcoin-environment'; +const chain = new Chain({ + db: 'leveldb', + location: prefix + '/chain', + network: 'main' +}); + +const mempool = new Mempool({ chain: chain }); + +// Create a network pool of peers with a limit of 8 peers. +const pool = new Pool({ + chain: chain, + mempool: mempool, + maxPeers: 8 +}); + +// Open the pool (implicitly opens mempool and chain). +(async function() { + await pool.open(); + + // Connect, start retrieving and relaying txs + await pool.connect(); + + // Start the blockchain sync. + pool.startSync(); + + // Watch the action + chain.on('block', (block) => { + console.log('Connected block to blockchain:'); + console.log(block); + }); + + mempool.on('tx', (tx) => { + console.log('Added tx to mempool:'); + console.log(tx); + }); + + pool.on('tx', (tx) => { + console.log('Saw transaction:'); + console.log(tx.rhash); + }); +})(); + +// Start up a testnet sync in-memory +// while we're at it (because we can). + +const tchain = new Chain({ + network: 'testnet', + db: 'memory' +}); + +const tmempool = new Mempool({ + network: 'testnet', + chain: tchain +}); + +const tpool = new Pool({ + network: 'testnet', + chain: tchain, + mempool: tmempool, + size: 8 +}); + +(async function() { + await tpool.open(); + + // Connect, start retrieving and relaying txs + await tpool.connect(); + + // Start the blockchain sync. + tpool.startSync(); + + tchain.on('block', (block) => { + console.log('Added testnet block:'); + console.log(block); + }); + + tmempool.on('tx', (tx) => { + console.log('Added testnet tx to mempool:'); + console.log(tx); + }); + + tpool.on('tx', (tx) => { + console.log('Saw testnet transaction:'); + console.log(tx); + }); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/docs/Examples/create-a-blockchain-and-mempool.js b/docs/Examples/create-a-blockchain-and-mempool.js new file mode 100644 index 000000000..1c3d42802 --- /dev/null +++ b/docs/Examples/create-a-blockchain-and-mempool.js @@ -0,0 +1,42 @@ +'use strict'; +const bcoin = require('../..'); +const Chain = bcoin.chain; +const Mempool = bcoin.mempool; +const Miner = bcoin.miner; + +// Default network (so we can avoid passing +// the `network` option into every object below.) +bcoin.set('regtest'); + +// Start up a blockchain, mempool, and miner using in-memory +// databases (stored in a red-black tree instead of on-disk). +const chain = new Chain({ db: 'memory' }); +const mempool = new Mempool({ chain: chain }); +const miner = new Miner({ + chain: chain, + mempool: mempool, + + // Make sure miner won't block the main thread. + useWorkers: true +}); + +(async () => { + // Open the miner (initialize the databases, etc). + // Miner will implicitly call `open` on chain and mempool. + await miner.open(); + + // Create a Cpu miner job + const job = await miner.createJob(); + + // run miner + const block = await job.mineAsync(); + + // Add the block to the chain + console.log('Adding %s to the blockchain.', block.rhash); + console.log(block); + await chain.add(block); + console.log('Added block!'); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/examples/tx.js b/docs/Examples/create-sign-tx.js similarity index 75% rename from examples/tx.js rename to docs/Examples/create-sign-tx.js index 42cfed458..6661626c2 100644 --- a/examples/tx.js +++ b/docs/Examples/create-sign-tx.js @@ -1,13 +1,15 @@ 'use strict'; -const bcoin = require('bcoin'); +/* eslint new-cap: "off" */ + +const bcoin = require('../..'); const assert = require('assert'); (async () => { - let master = bcoin.hd.generate(); - let key = master.derivePath('m/44/0/0/0/0'); - let keyring = new bcoin.keyring(key.privateKey); - let cb = new bcoin.mtx(); + const master = bcoin.hd.generate(); + const key = master.derivePath('m/44/0/0/0/0'); + const keyring = new bcoin.keyring(key.privateKey); + const cb = new bcoin.mtx(); cb.addInput({ prevout: new bcoin.outpoint(), @@ -22,16 +24,16 @@ const assert = require('assert'); }); // Our available coins. - let coins = []; + const coins = []; // Convert the coinbase output to a Coin // object and add it to our available coins. // In reality you might get these coins from a wallet. - let coin = bcoin.coin.fromTX(cb, 0, -1); + const coin = bcoin.coin.fromTX(cb, 0, -1); coins.push(coin); // Create our redeeming transaction. - let mtx = new bcoin.mtx(); + const mtx = new bcoin.mtx(); // Send 10,000 satoshis to ourself. mtx.addOutput({ @@ -39,9 +41,9 @@ const assert = require('assert'); value: 10000 }); - // Now that we've created the output, we can do some coin selection (the output - // must be added first so we know how much money is needed and also so we can - // accurately estimate the size for fee calculation). + // Now that we've created the output, we can do some coin selection (the + // output must be added first so we know how much money is needed and also so + // we can accurately estimate the size for fee calculation). // Select coins from our array and add inputs. // Calculate fee and add a change output. @@ -63,7 +65,7 @@ const assert = require('assert'); // Commit our transaction and make it immutable. // This turns it from an MTX into a TX. - let tx = mtx.toTX(); + const tx = mtx.toTX(); // The transaction should still verify. // Regular transactions require a coin diff --git a/docs/Examples/fullnode-and-wallet.js b/docs/Examples/fullnode-and-wallet.js new file mode 100644 index 000000000..50d64198f --- /dev/null +++ b/docs/Examples/fullnode-and-wallet.js @@ -0,0 +1,83 @@ +'use strict'; +const bcoin = require('../..').set('main'); +const walletPlugin = bcoin.wallet.plugin; + +const node = bcoin.fullnode({ + checkpoints: true, + // Primary wallet passphrase + passsphrase: 'node', + logLevel: 'info' +}); + +node.use(walletPlugin); + +// We get a lot of errors sometimes, +// usually from peers hanging up on us. +// Just ignore them for now. +node.on('error', (err) => { + ; +}); + +// New Address we'll be sending to. +const newReceiving = 'AddressHere'; + +// Start the node +(async () => { + await node.open(); + + const options = { + id: 'mywallet', + passphrase: 'foo', + witness: false, + type: 'pubkeyhash' + }; + + const walletdb = node.require('walletdb'); + + await walletdb.open(); + const wallet = await walletdb.create(options); + + console.log('Created wallet with address: %s', wallet.getAddress('base58')); + + await node.connect(); + + // Start syncing the blockchain + node.startSync(); + + // Wait for balance and send it to a new address. + wallet.once('balance', async (balance) => { + // Create a transaction, fill + // it with coins, and sign it. + const options = { + subtractFee: true, + outputs: [{ + address: newReceiving, + value: balance.total + }] + }; + + const tx = await wallet.createTX(options); + const stx = await wallet.sign(tx, 'foo'); + + console.log('sending tx:'); + console.log(stx); + + await node.sendTX(stx); + console.log('tx sent!'); + }); + + node.chain.on('block', (block) => { + ; + }); + + node.mempool.on('tx', (tx) => { + ; + }); + + node.chain.on('full', () => { + node.mempool.getHistory().then(console.log); + }); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/examples/node.js b/docs/Examples/fullnode.js similarity index 61% rename from examples/node.js rename to docs/Examples/fullnode.js index e9f2694e4..e45bbb106 100644 --- a/examples/node.js +++ b/docs/Examples/fullnode.js @@ -1,11 +1,14 @@ 'use strict'; -const FullNode = require('bcoin/lib/node/fullnode'); +const bcoin = require('../..'); +const FullNode = bcoin.fullnode; const node = new FullNode({ - network: 'testnet', + network: 'bitcoincash', db: 'memory', - workers: true + workers: true, + 'log-level': 'debug', + 'http-port': 8332 }); (async () => { @@ -21,4 +24,7 @@ const node = new FullNode({ }); node.startSync(); -})(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/docs/Examples/get-tx-from-chain.js b/docs/Examples/get-tx-from-chain.js new file mode 100644 index 000000000..39c1646fc --- /dev/null +++ b/docs/Examples/get-tx-from-chain.js @@ -0,0 +1,52 @@ +'use strict'; + +const path = require('path'); +const bcoin = require('../..'); +const Chain = bcoin.chain; +const Logger = bcoin.logger; +const util = bcoin.util; + +const HOME = process.env.HOME; + +// Setup logger to see what's Bcoin doing. +const logger = new Logger({ + level: 'debug' +}); + +// Create chain for testnet, specify chain directory +const chain = new Chain({ + logger: logger, + network: 'testnet', + db: 'leveldb', + prefix: path.join(HOME, '.bcoin/testnet'), + indexTX: true, + indexAddress: true +}); + +(async () => { + await logger.open(); + await chain.open(); + + console.log('Current height:', chain.height); + + const entry = await chain.getEntry(50000); + console.log('Block at 50k:', entry); + + // eslint-disable-next-line max-len + const txhash = '4dd628123dcde4f2fb3a8b8a18b806721b56007e32497ebe76cde598ce1652af'; + const txmeta = await chain.db.getMeta(util.revHex(txhash)); + const tx = txmeta.tx; + const coinview = await chain.db.getSpentView(tx); + + console.log(`Tx with hash ${txhash}:`, txmeta); + console.log(`Tx input: ${tx.getInputValue(coinview)},` + + ` output: ${tx.getOutputValue()}, fee: ${tx.getFee(coinview)}`); + + // eslint-disable-next-line max-len + const bhash = '00000000077eacdd2c803a742195ba430a6d9545e43128ba55ec3c80beea6c0c'; + const block = await chain.db.getBlock(util.revHex(bhash)); + console.log(`Block with hash ${bhash}:`, block); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/examples/miner.js b/docs/Examples/miner-configs.js similarity index 61% rename from examples/miner.js rename to docs/Examples/miner-configs.js index e9ad7efe8..b6ad820b4 100644 --- a/examples/miner.js +++ b/docs/Examples/miner-configs.js @@ -1,9 +1,10 @@ 'use strict'; -const KeyRing = require('bcoin/lib/primitives/keyring'); -const WorkerPool = require('bcoin/lib/workers/workerpool'); -const Chain = require('bcoin/lib/blockchain/chain'); -const Miner = require('bcoin/lib/mining/miner'); +const bcoin = require('../..'); +const KeyRing = bcoin.keyring; +const WorkerPool = bcoin.workerpool; +const Chain = bcoin.chain; +const Miner = bcoin.miner; const key = KeyRing.generate('regtest'); @@ -24,17 +25,15 @@ const miner = new Miner({ }); (async () => { - let tmpl, job, block; - await miner.open(); - tmpl = await miner.createBlock(); + const tmpl = await miner.createBlock(); console.log('Block template:'); console.log(tmpl); - job = await miner.cpu.createJob(); - block = await job.mineAsync(); + const job = await miner.createJob(); + const block = await job.mineAsync(); console.log('Mined block:'); console.log(block); @@ -44,4 +43,7 @@ const miner = new Miner({ console.log('New tip:'); console.log(chain.tip); -})(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/examples/plugin.js b/docs/Examples/peers-plugin.js similarity index 83% rename from examples/plugin.js rename to docs/Examples/peers-plugin.js index 3f9361bec..fb7881825 100644 --- a/examples/plugin.js +++ b/docs/Examples/peers-plugin.js @@ -1,6 +1,7 @@ 'use strict'; -const FullNode = require('bcoin/lib/node/fullnode'); +const bcoin = require('../..'); +const FullNode = bcoin.fullnode; function MyPlugin(node) { this.node = node; @@ -35,7 +36,7 @@ const node = new FullNode({ node.use(MyPlugin); (async () => { - let plugin = node.require('my-plugin'); + const plugin = node.require('my-plugin'); await node.open(); @@ -52,4 +53,7 @@ node.use(MyPlugin); }); node.startSync(); -})(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/docs/Examples/spv-sync-wallet.js b/docs/Examples/spv-sync-wallet.js new file mode 100644 index 000000000..75f5992d5 --- /dev/null +++ b/docs/Examples/spv-sync-wallet.js @@ -0,0 +1,56 @@ +'use strict'; + +const bcoin = require('../..'); +const Chain = bcoin.chain; +const Pool = bcoin.pool; +const WalletDB = bcoin.walletdb; + +bcoin.set('testnet'); + +// SPV chains only store the chain headers. +const chain = Chain({ + db: 'leveldb', + location: process.env.HOME + '/spvchain', + spv: true +}); + +const pool = new Pool({ + chain: chain, + spv: true, + maxPeers: 8 +}); + +const walletdb = new WalletDB({ db: 'memory' }); + +(async () => { + await pool.open(); + await walletdb.open(); + + const wallet = await walletdb.create(); + + console.log('Created wallet with address %s', wallet.getAddress('base58')); + + // Add our address to the spv filter. + pool.watchAddress(wallet.getAddress()); + + // Connect, start retrieving and relaying txs + await pool.connect(); + + // Start the blockchain sync. + pool.startSync(); + + pool.on('tx', async (tx) => { + console.log('received TX'); + + await walletdb.addTX(tx); + console.log('Transaction added to walletDB'); + }); + + wallet.on('balance', (balance) => { + console.log('Balance updated.'); + console.log(bcoin.amount.btc(balance.unconfirmed)); + }); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/examples/wallet.js b/docs/Examples/wallet.js similarity index 50% rename from examples/wallet.js rename to docs/Examples/wallet.js index 7268dfe79..fc066e14e 100644 --- a/examples/wallet.js +++ b/docs/Examples/wallet.js @@ -1,12 +1,13 @@ 'use strict'; -const random = require('bcoin/lib/crypto/random'); -const WalletDB = require('bcoin/lib/wallet/walletdb'); -const MTX = require('bcoin/lib/primitives/mtx'); -const Outpoint = require('bcoin/lib/primitives/outpoint'); +const bcoin = require('../..'); +const random = bcoin.crypto.random; +const WalletDB = bcoin.walletdb; +const MTX = bcoin.mtx; +const Outpoint = bcoin.outpoint; function dummy() { - let hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32).toString('hex'); return new Outpoint(hash, 0); } @@ -16,31 +17,33 @@ const walletdb = new WalletDB({ }); (async () => { - let wallet, acct, mtx, tx, wtx; - await walletdb.open(); - wallet = await walletdb.create(); + const wallet = await walletdb.create(); console.log('Created wallet'); console.log(wallet); - acct = await wallet.createAccount({ + const acct = await wallet.createAccount({ name: 'foo' }); console.log('Created account'); console.log(acct); - mtx = new MTX(); + const mtx = new MTX(); mtx.addOutpoint(dummy()); mtx.addOutput(acct.getReceive(), 50460); - tx = mtx.toTX(); + + const tx = mtx.toTX(); await walletdb.addTX(tx); - wtx = await wallet.getTX(tx.hash('hex')); + const wtx = await wallet.getTX(tx.hash('hex')); console.log('Added transaction'); console.log(wtx); -})(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/docs/README.md b/docs/README.md index 6c9e14677..928cedaa8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,10 +13,18 @@ Welcome to the bcoin docs! - [REST and RPC API][rest-rpc] ## Code Examples +- [Simple Fullnode][example-simple-fullnode] +- [Connect to Peer][example-connect-peer] - [Connecting to the P2P Network][example-p2p] - [Creating a Blockchain and Mempool][example-blockchain] -- [Fullnode Object][example-fullnode] +- [Wallet with Dummy TX][example-wallet-dummy] +- [Fullnode Object][example-fullnode-wallet] - [SPV Sync][example-spv] +- [Plugin Example][example-peers-plugin] +- [Client API Usage][example-client-api] +- [Miner with WorkerPool][example-miner-configs] +- [Create and Sign TX][example-tx-create-sign] +- [Get Transaction from Chain][example-tx-from-chain] ## Advanced - [Working with transactions][work-transactions] @@ -36,7 +44,15 @@ Welcome to the bcoin docs! [work-transactions]: Working-with-transactions.md [scripting]: Scripting.md -[example-p2p]: Example-Connecting-to-the-P2P-Network.md -[example-blockchain]: Example-Creating-a-Blockchain-and-Mempool.md -[example-fullnode]: Example-Fullnode-Object.md -[example-spv]: Example-SPV-Sync.md +[example-p2p]: Examples/connect-to-the-p2p-network.js +[example-blockchain]: Examples/create-a-blockchain-and-mempool.js +[example-fullnode-wallet]: Examples/fullnode-and-wallet.js +[example-spv]: Examples/spv-sync-wallet.js +[example-wallet-dummy]: Examples/wallet.js +[example-peers-plugin]: Examples/peers-plugin.js +[example-client-api]: Examples/client-api.js +[example-miner-configs]: Examples/miner-configs.js +[example-connect-peer]: Examples/connect-to-peer.js +[example-simple-fullnode]: Examples/fullnode.js +[example-tx-create-sign]: Examples/create-sign-tx.js +[example-tx-from-chain]: Examples/get-tx-from-chain.js diff --git a/docs/REST-RPC-API.md b/docs/REST-RPC-API.md index a37f9f61d..132d70687 100644 --- a/docs/REST-RPC-API.md +++ b/docs/REST-RPC-API.md @@ -80,6 +80,8 @@ Example: Get coins by address. Returns coins in bcoin coin json format. +*Note: Without `index-address` option, it won't return from chain(only mempool).* + ### GET /coin/:hash/:index Get coin by outpoint (hash and index). Returns coin in bcoin coin json format. @@ -95,7 +97,9 @@ Example: ### GET /tx/:hash -Get transaction by TXID. Returns TX in bcoin transaction json format. +Get transaction by TXID from Chain or Mempool. Returns TX in bcoin transaction json format. + +*Note: Without `index-tx` option, it won't return from chain.* ### GET /tx/address/:address @@ -173,29 +177,29 @@ POST /wallet/:id/send GET /wallet/:id/tx/:hash?token=[64 character hex string] ``` -### POST /rescan +### POST /wallet/_admin/rescan Initiates a blockchain rescan for the walletdb. Wallets will be rolled back to the specified height (transactions above this height will be unconfirmed). Example: -- Request: POST /rescan?height=100000 +- Request: POST /wallet/_admin/rescan?height=100000 - Response Body: `{"success":true}` -### POST /resend +### POST /wallet/_admin/resend Rebroadcast all pending transactions in all wallets. -### POST /backup +### POST /wallet/_admin/backup Safely backup the wallet database to specified path (creates a clone of the database). Example: -- Request: POST /backup?path=/home/user/walletdb-backup.ldb +- Request: POST /wallet/_admin/backup?path=/home/user/walletdb-backup.ldb - Response Body: `{"success":true}` -### GET /wallets +### GET /wallet/_admin/wallets List all wallet IDs. Returns an array of strings. @@ -478,8 +482,8 @@ Example: "hash": "0de09025e68b78e13f5543f46a9516fa37fcc06409bf03eda0e85ed34018f822", "height": -1, "block": null, - "ts": 0, - "ps": 1486685530, + "time": 0, + "mtime": 1486685530, "date": "2017-02-10T00:12:10Z", "index": -1, "size": 226, @@ -549,7 +553,7 @@ Do not broadcast or add to wallet. "witnessHash": "0799a1d3ebfd108d2578a60e1b685350d42e1ef4d5cd326f99b8bf794c81ed17", "fee": "0.0000454", "rate": "0.00020088", - "ps": 1486686322, + "mtime": 1486686322, "version": 1, "flag": 1, "inputs": [ @@ -626,7 +630,7 @@ Example: { "hash": "39864ce2f29635638bbdc3e943b3a182040fdceb6679fa3dabc8c827e05ff6a7", "height": 3, - "ts": 1485471341, + "time": 1485471341, "hashes": [ "dd1a110edcdcbb3110a1cbe0a545e4b0a7813ffa5e77df691478205191dad66f" ] @@ -716,7 +720,7 @@ Example: List all wallet coins available. -### GET /wallet/:id/coin/locked +### GET /wallet/:id/locked Get all locked outpoints. @@ -728,11 +732,11 @@ Example: [{"hash":"dd1a110edcdcbb3110a1cbe0a545e4b0a7813ffa5e77df691478205191dad66f","index":0}] ``` -### PUT /wallet/:id/coin/locked +### PUT /wallet/:id/locked/:hash/:index Lock outpoints. -### DEL /wallet/:id/coin/locked +### DEL /wallet/:id/locked/:hash/:index Unlock outpoints. @@ -846,8 +850,8 @@ Example: "hash": "0de09025e68b78e13f5543f46a9516fa37fcc06409bf03eda0e85ed34018f822", "height": -1, "block": null, - "ts": 0, - "ps": 1486685530, + "time": 0, + "mtime": 1486685530, "date": "2017-02-10T00:12:10Z", "index": -1, "size": 226, @@ -951,4 +955,4 @@ Example: "type": "pubkeyhash", "address": "mwX8J1CDGUqeQcJPnjNBG4s97vhQsJG7Eq" } -``` \ No newline at end of file +``` diff --git a/docs/Scripting.md b/docs/Scripting.md index d6c7682aa..dc44083dd 100644 --- a/docs/Scripting.md +++ b/docs/Scripting.md @@ -1,37 +1,38 @@ Scripts are array-like objects with some helper functions. ``` js -var bcoin = require('bcoin'); -var assert = require('assert'); -var BN = bcoin.bn; -var opcodes = bcoin.script.opcodes; +const bcoin = require('bcoin'); +const assert = require('assert'); +const Script = bcoin.script; +const Witness = bcoin.witness; +const Stack = bcoin.stack; -var output = new bcoin.script(); -output.push(opcodes.OP_DROP); -output.push(opcodes.OP_ADD); -output.push(new BN(7)); -output.push(opcodes.OP_NUMEQUAL); +const output = new Script(); +output.pushSym('OP_DROP'); +output.pushSym('OP_ADD'); +output.pushInt(7); +output.pushSym('OP_NUMEQUAL'); // Compile the script to its binary representation // (you must do this if you change something!). -output.compile(); assert(output.getSmall(2) === 7); // compiled as OP_7 +output.compile(); -var input = new bcoin.script(); -input.set(0, 'hello world'); // add some metadata -input.push(new BN(2)); -input.push(new BN(5)); +const input = new Script(); +input.setString(0, 'hello world'); // add some metadata +input.pushInt(2); +input.pushInt(5); input.push(input.shift()); assert(input.getString(2) === 'hello world'); input.compile(); // A stack is another array-like object which contains // only Buffers (whereas scripts contain Opcode objects). -var stack = new bcoin.stack(); +const stack = new Stack(); input.execute(stack); output.execute(stack); // Verify the script was successful in its execution: assert(stack.length === 1); -assert(bcoin.script.bool(stack.pop()) === true); +assert(stack.getBool(-1) === true); ``` Using a witness would be similar, but witnesses do not get executed, they @@ -39,11 +40,11 @@ simply _become_ the stack. The witness object itself is very similar to the Stack object (an array-like object containing Buffers). ``` js -var witness = new bcoin.witness(); -witness.push(new BN(2)); -witness.push(new BN(5)); -witness.push('hello world'); +const witness = new Witness(); +witness.pushInt(2); +witness.pushInt(5); +witness.pushString('hello world'); -var stack = witness.toStack(); +const stack = witness.toStack(); output.execute(stack); -``` \ No newline at end of file +``` diff --git a/examples/chain.js b/examples/chain.js deleted file mode 100644 index 703b7dc26..000000000 --- a/examples/chain.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -const Chain = require('bcoin/lib/blockchain/chain'); - -const chain = new Chain({ - network: 'testnet' -}); - -(async () => { - let entry; - - await chain.open(); - - entry = await chain.getEntry(0); - - console.log(entry); -})(); diff --git a/lib/bcoin-browser.js b/lib/bcoin-browser.js index 17374c9b9..1bd05f0f8 100644 --- a/lib/bcoin-browser.js +++ b/lib/bcoin-browser.js @@ -240,6 +240,7 @@ bcoin.txscript = require('./script'); bcoin.opcode = require('./script/opcode'); bcoin.program = require('./script/program'); bcoin.script = require('./script/script'); +bcoin.scriptnum = require('./script/scriptnum'); bcoin.sigcache = require('./script/sigcache'); bcoin.stack = require('./script/stack'); bcoin.witness = require('./script/witness'); diff --git a/lib/bcoin.js b/lib/bcoin.js index b6b37b2de..92dc153f5 100644 --- a/lib/bcoin.js +++ b/lib/bcoin.js @@ -5,6 +5,8 @@ * https://github.com/bcoin-org/bcoin */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; /** @@ -130,12 +132,14 @@ const bcoin = exports; * @param {String} path */ -bcoin.define = function _require(name, path) { +bcoin.define = function define(name, path) { let cache; - bcoin.__defineGetter__(name, function() { - if (!cache) - cache = require(path); - return cache; + Object.defineProperty(bcoin, name, { + get() { + if (!cache) + cache = require(path); + return cache; + } }); }; @@ -273,6 +277,7 @@ bcoin.define('txscript', './script'); bcoin.define('opcode', './script/opcode'); bcoin.define('program', './script/program'); bcoin.define('script', './script/script'); +bcoin.define('scriptnum', './script/scriptnum'); bcoin.define('sigcache', './script/sigcache'); bcoin.define('stack', './script/stack'); bcoin.define('witness', './script/witness'); diff --git a/lib/bip70/payment.js b/lib/bip70/payment.js index 7c0ff6e12..d5ab654b9 100644 --- a/lib/bip70/payment.js +++ b/lib/bip70/payment.js @@ -51,16 +51,16 @@ Payment.prototype.fromOptions = function fromOptions(options) { if (options.transactions) { assert(Array.isArray(options.transactions)); - for (let item of options.transactions) { - let tx = new TX(item); + for (const item of options.transactions) { + const tx = new TX(item); this.transactions.push(tx); } } if (options.refundTo) { assert(Array.isArray(options.refundTo)); - for (let item of options.refundTo) { - let output = new Output(item); + for (const item of options.refundTo) { + const output = new Output(item); this.refundTo.push(output); } } @@ -111,18 +111,18 @@ Payment.prototype.getData = PaymentDetails.prototype.getData; */ Payment.prototype.fromRaw = function fromRaw(data) { - let br = new ProtoReader(data); + const br = new ProtoReader(data); this.merchantData = br.readFieldBytes(1, true); while (br.nextTag() === 2) { - let tx = TX.fromRaw(br.readFieldBytes(2)); + const tx = TX.fromRaw(br.readFieldBytes(2)); this.transactions.push(tx); } while (br.nextTag() === 3) { - let op = new ProtoReader(br.readFieldBytes(3)); - let output = new Output(); + const op = new ProtoReader(br.readFieldBytes(3)); + const output = new Output(); output.value = op.readFieldU64(1, true); output.script = Script.fromRaw(op.readFieldBytes(2, true)); this.refundTo.push(output); @@ -151,16 +151,16 @@ Payment.fromRaw = function fromRaw(data, enc) { */ Payment.prototype.toRaw = function toRaw() { - let bw = new ProtoWriter(); + const bw = new ProtoWriter(); if (this.merchantData) bw.writeFieldBytes(1, this.merchantData); - for (let tx of this.transactions) + for (const tx of this.transactions) bw.writeFieldBytes(2, tx.toRaw()); - for (let output of this.refundTo) { - let op = new ProtoWriter(); + for (const output of this.refundTo) { + const op = new ProtoWriter(); op.writeFieldU64(1, output.value); op.writeFieldBytes(2, output.script.toRaw()); bw.writeFieldBytes(3, op.render()); diff --git a/lib/bip70/paymentack.js b/lib/bip70/paymentack.js index 0ded9bcc6..b755ee848 100644 --- a/lib/bip70/paymentack.js +++ b/lib/bip70/paymentack.js @@ -68,7 +68,7 @@ PaymentACK.fromOptions = function fromOptions(options) { */ PaymentACK.prototype.fromRaw = function fromRaw(data) { - let br = new ProtoReader(data); + const br = new ProtoReader(data); this.payment.fromRaw(br.readFieldBytes(1)); this.memo = br.readFieldString(2, true); @@ -94,7 +94,7 @@ PaymentACK.fromRaw = function fromRaw(data, enc) { */ PaymentACK.prototype.toRaw = function toRaw() { - let bw = new ProtoWriter(); + const bw = new ProtoWriter(); bw.writeFieldBytes(1, this.payment.toRaw()); diff --git a/lib/bip70/paymentdetails.js b/lib/bip70/paymentdetails.js index 94904c3ba..c33d8c421 100644 --- a/lib/bip70/paymentdetails.js +++ b/lib/bip70/paymentdetails.js @@ -57,19 +57,19 @@ PaymentDetails.prototype.fromOptions = function fromOptions(options) { if (options.outputs) { assert(Array.isArray(options.outputs)); - for (let item of options.outputs) { - let output = new Output(item); + for (const item of options.outputs) { + const output = new Output(item); this.outputs.push(output); } } if (options.time != null) { - assert(util.isNumber(options.time)); + assert(util.isInt(options.time)); this.time = options.time; } if (options.expires != null) { - assert(util.isNumber(options.expires)); + assert(util.isInt(options.expires)); this.expires = options.expires; } @@ -141,7 +141,7 @@ PaymentDetails.prototype.getData = function getData(enc) { let data = this.merchantData; if (!data) - return; + return null; if (!enc) return data; @@ -151,7 +151,7 @@ PaymentDetails.prototype.getData = function getData(enc) { try { data = JSON.parse(data); } catch (e) { - return; + return null; } return data; } @@ -167,13 +167,13 @@ PaymentDetails.prototype.getData = function getData(enc) { */ PaymentDetails.prototype.fromRaw = function fromRaw(data) { - let br = new ProtoReader(data); + const br = new ProtoReader(data); this.network = br.readFieldString(1, true); while (br.nextTag() === 2) { - let op = new ProtoReader(br.readFieldBytes(2)); - let output = new Output(); + const op = new ProtoReader(br.readFieldBytes(2)); + const output = new Output(); output.value = op.readFieldU64(1, true); output.script.fromRaw(op.readFieldBytes(2, true)); this.outputs.push(output); @@ -206,13 +206,13 @@ PaymentDetails.fromRaw = function fromRaw(data, enc) { */ PaymentDetails.prototype.toRaw = function toRaw() { - let bw = new ProtoWriter(); + const bw = new ProtoWriter(); if (this.network != null) bw.writeFieldString(1, this.network); - for (let output of this.outputs) { - let op = new ProtoWriter(); + for (const output of this.outputs) { + const op = new ProtoWriter(); op.writeFieldU64(1, output.value); op.writeFieldBytes(2, output.script.toRaw()); bw.writeFieldBytes(2, op.render()); diff --git a/lib/bip70/paymentrequest.js b/lib/bip70/paymentrequest.js index d76fc9a7d..6fb17555f 100644 --- a/lib/bip70/paymentrequest.js +++ b/lib/bip70/paymentrequest.js @@ -50,7 +50,7 @@ function PaymentRequest(options) { PaymentRequest.prototype.fromOptions = function fromOptions(options) { if (options.version != null) { - assert(util.isNumber(options.version)); + assert(util.isInt(options.version)); this.version = options.version; } @@ -96,7 +96,7 @@ PaymentRequest.fromOptions = function fromOptions(options) { */ PaymentRequest.prototype.fromRaw = function fromRaw(data) { - let br = new ProtoReader(data); + const br = new ProtoReader(data); this.version = br.readFieldU32(1, true); this.pkiType = br.readFieldString(2, true); @@ -125,7 +125,7 @@ PaymentRequest.fromRaw = function fromRaw(data, enc) { */ PaymentRequest.prototype.toRaw = function toRaw() { - let bw = new ProtoWriter(); + const bw = new ProtoWriter(); if (this.version !== -1) bw.writeFieldU32(1, this.version); @@ -150,12 +150,10 @@ PaymentRequest.prototype.toRaw = function toRaw() { */ PaymentRequest.prototype.getAlgorithm = function getAlgorithm() { - let parts; - if (!this.pkiType) throw new Error('No PKI type available.'); - parts = this.pkiType.split('+'); + const parts = this.pkiType.split('+'); if (parts.length !== 2) throw new Error('Could not parse PKI algorithm.'); @@ -175,12 +173,11 @@ PaymentRequest.prototype.getAlgorithm = function getAlgorithm() { */ PaymentRequest.prototype.signatureData = function signatureData() { - let signature = this.signature; - let data; + const signature = this.signature; this.signature = Buffer.alloc(0); - data = this.toRaw(); + const data = this.toRaw(); this.signature = signature; @@ -193,7 +190,7 @@ PaymentRequest.prototype.signatureData = function signatureData() { */ PaymentRequest.prototype.signatureHash = function signatureHash() { - let alg = this.getAlgorithm(); + const alg = this.getAlgorithm(); return digest.hash(alg.hash, this.signatureData()); }; @@ -203,13 +200,13 @@ PaymentRequest.prototype.signatureHash = function signatureHash() { */ PaymentRequest.prototype.setChain = function setChain(chain) { - let bw = new ProtoWriter(); + const bw = new ProtoWriter(); assert(Array.isArray(chain), 'Chain must be an array.'); for (let cert of chain) { if (typeof cert === 'string') { - let pem = PEM.decode(cert); + const pem = PEM.decode(cert); assert(pem.type === 'certificate', 'Bad certificate PEM.'); cert = pem.data; } @@ -226,13 +223,12 @@ PaymentRequest.prototype.setChain = function setChain(chain) { */ PaymentRequest.prototype.getChain = function getChain() { - let chain = []; - let br; + const chain = []; if (!this.pkiData) return chain; - br = new ProtoReader(this.pkiData); + const br = new ProtoReader(this.pkiData); while (br.nextTag() === 1) chain.push(br.readFieldBytes(1)); @@ -243,21 +239,19 @@ PaymentRequest.prototype.getChain = function getChain() { /** * Sign payment request (chain must be set). * @param {Buffer} key - * @param {Buffer[]?} chain + * @param {Buffer[]?} certs */ -PaymentRequest.prototype.sign = function sign(key, chain) { - let alg, msg; - - if (chain) - this.setChain(chain); +PaymentRequest.prototype.sign = function sign(key, certs) { + if (certs) + this.setChain(certs); if (!this.pkiType) this.pkiType = 'x509+sha256'; - alg = this.getAlgorithm(); - msg = this.signatureData(); - chain = this.getChain(); + const alg = this.getAlgorithm(); + const msg = this.signatureData(); + const chain = this.getChain(); this.signature = x509.signSubject(alg.hash, msg, key, chain); }; @@ -268,23 +262,22 @@ PaymentRequest.prototype.sign = function sign(key, chain) { */ PaymentRequest.prototype.verify = function verify() { - let alg, msg, sig, chain; - if (!this.pkiType || this.pkiType === 'none') return false; if (!this.signature) return false; + let alg; try { alg = this.getAlgorithm(); } catch (e) { return false; } - msg = this.signatureData(); - sig = this.signature; - chain = this.getChain(); + const msg = this.signatureData(); + const sig = this.signature; + const chain = this.getChain(); try { return x509.verifySubject(alg.hash, msg, sig, chain); @@ -315,17 +308,15 @@ PaymentRequest.prototype.verifyChain = function verifyChain() { */ PaymentRequest.prototype.getCA = function getCA() { - let chain, root; - if (!this.pkiType || this.pkiType === 'none') throw new Error('No CA found (pkiType).'); - chain = this.getChain(); + const chain = this.getChain(); if (chain.length === 0) throw new Error('No CA found (chain).'); - root = x509.parse(chain[chain.length - 1]); + const root = x509.parse(chain[chain.length - 1]); return new CA(root); }; diff --git a/lib/bip70/x509.js b/lib/bip70/x509.js index 4620caec9..87bf3507f 100644 --- a/lib/bip70/x509.js +++ b/lib/bip70/x509.js @@ -22,10 +22,10 @@ const x509 = exports; /** * Map of trusted root certs. - * @type {Object} + * @type {Set} */ -x509.trusted = {}; +x509.trusted = new Set(); /** * Whether to allow untrusted root @@ -86,12 +86,14 @@ x509.curves = { */ x509.getSubjectOID = function getSubjectOID(cert, oid) { - let subject = cert.tbs.subject; + const subject = cert.tbs.subject; - for (let entry of subject) { + for (const entry of subject) { if (entry.type === oid) return entry.value; } + + return null; }; /** @@ -125,9 +127,9 @@ x509.getCAName = function getCAName(cert) { */ x509.isTrusted = function isTrusted(cert) { - let fingerprint = digest.sha256(cert.raw); - let hash = fingerprint.toString('hex'); - return x509.trusted[hash] === true; + const fingerprint = digest.sha256(cert.raw); + const hash = fingerprint.toString('hex'); + return x509.trusted.has(hash); }; /** @@ -139,10 +141,8 @@ x509.setTrust = function setTrust(certs) { assert(Array.isArray(certs), 'Certs must be an array.'); for (let cert of certs) { - let hash; - if (typeof cert === 'string') { - let pem = PEM.decode(cert); + const pem = PEM.decode(cert); assert(pem.type === 'certificate', 'Must add certificates to trust.'); cert = pem.data; } @@ -151,10 +151,10 @@ x509.setTrust = function setTrust(certs) { cert = x509.parse(cert); - hash = digest.sha256(cert.raw); - hash = hash.toString('hex'); + const hash = digest.sha256(cert.raw); + const fingerprint = hash.toString('hex'); - x509.trusted[hash] = true; + x509.trusted.add(fingerprint); } }; @@ -174,7 +174,7 @@ x509.setFingerprints = function setFingerprints(hashes) { assert(hash.length === 32, 'Fingerprint must be a sha256 hash.'); hash = hash.toString('hex'); - x509.trusted[hash] = true; + x509.trusted.add(hash); } }; @@ -185,8 +185,8 @@ x509.setFingerprints = function setFingerprints(hashes) { */ x509.getKeyAlgorithm = function getKeyAlgorithm(cert) { - let oid = cert.tbs.pubkey.alg.alg; - let alg = x509.oid[oid]; + const oid = cert.tbs.pubkey.alg.alg; + const alg = x509.oid[oid]; if (!alg) throw new Error(`Unknown key algorithm: ${oid}.`); @@ -201,8 +201,8 @@ x509.getKeyAlgorithm = function getKeyAlgorithm(cert) { */ x509.getSigAlgorithm = function getSigAlgorithm(cert) { - let oid = cert.sigAlg.alg; - let alg = x509.oid[oid]; + const oid = cert.sigAlg.alg; + const alg = x509.oid[oid]; if (!alg || !alg.hash) throw new Error(`Unknown signature algorithm: ${oid}.`); @@ -217,7 +217,7 @@ x509.getSigAlgorithm = function getSigAlgorithm(cert) { */ x509.getCurve = function getCurve(params) { - let oid, curve; + let oid; try { oid = ASN1.parseOID(params); @@ -225,7 +225,7 @@ x509.getCurve = function getCurve(params) { throw new Error('Could not parse curve OID.'); } - curve = x509.curves[oid]; + const curve = x509.curves[oid]; if (!curve) throw new Error(`Unknown ECDSA curve: ${oid}.`); @@ -254,10 +254,10 @@ x509.parse = function parse(der) { */ x509.getPublicKey = function getPublicKey(cert) { - let alg = x509.getKeyAlgorithm(cert); - let key = cert.tbs.pubkey.pubkey; - let params = cert.tbs.pubkey.alg.params; - let curve; + const alg = x509.getKeyAlgorithm(cert); + const key = cert.tbs.pubkey.pubkey; + const params = cert.tbs.pubkey.alg.params; + let curve = null; if (alg.key === 'ecdsa') { if (!params) @@ -281,8 +281,8 @@ x509.getPublicKey = function getPublicKey(cert) { */ x509.verifyTime = function verifyTime(cert) { - let time = cert.tbs.validity; - let now = util.now(); + const time = cert.tbs.validity; + const now = util.now(); return now > time.notBefore && now < time.notAfter; }; @@ -297,7 +297,7 @@ x509.getSigningKey = function getSigningKey(key, chain) { assert(chain.length !== 0, 'No chain available.'); if (typeof key === 'string') { - let curve; + let curve = null; key = PEM.decode(key); @@ -315,8 +315,8 @@ x509.getSigningKey = function getSigningKey(key, chain) { curve: curve }; } else { - let cert = x509.parse(chain[0]); - let pub = x509.getPublicKey(cert); + const cert = x509.parse(chain[0]); + const pub = x509.getPublicKey(cert); key = { alg: pub.alg, @@ -339,7 +339,7 @@ x509.getSigningKey = function getSigningKey(key, chain) { */ x509.signSubject = function signSubject(hash, msg, key, chain) { - let priv = x509.getSigningKey(key, chain); + const priv = x509.getSigningKey(key, chain); return pk.sign(hash, msg, priv); }; @@ -350,15 +350,12 @@ x509.signSubject = function signSubject(hash, msg, key, chain) { */ x509.getVerifyKey = function getVerifyKey(chain) { - let cert, key; - if (chain.length === 0) throw new Error('No verify key available (cert chain).'); - cert = x509.parse(chain[0]); - key = x509.getPublicKey(cert); + const cert = x509.parse(chain[0]); - return key; + return x509.getPublicKey(cert); }; /** @@ -371,7 +368,7 @@ x509.getVerifyKey = function getVerifyKey(chain) { */ x509.verifySubject = function verifySubject(hash, msg, sig, chain) { - let key = x509.getVerifyKey(chain); + const key = x509.getVerifyKey(chain); return pk.verify(hash, msg, sig, key); }; @@ -382,10 +379,10 @@ x509.verifySubject = function verifySubject(hash, msg, sig, chain) { */ x509.parseChain = function parseChain(chain) { - let certs = []; + const certs = []; - for (let item of chain) { - let cert = x509.parse(item); + for (const item of chain) { + const cert = x509.parse(item); certs.push(cert); } @@ -399,7 +396,7 @@ x509.parseChain = function parseChain(chain) { */ x509.verifyTimes = function verifyTimes(chain) { - for (let cert of chain) { + for (const cert of chain) { if (!x509.verifyTime(cert)) return false; } @@ -422,7 +419,7 @@ x509.verifyTrust = function verifyTrust(chain) { // Make sure we trust one // of the certs in the chain. - for (let cert of chain) { + for (const cert of chain) { // If any certificate in the chain // is trusted, assume we also trust // the parent. @@ -440,7 +437,7 @@ x509.verifyTrust = function verifyTrust(chain) { */ x509.verifyChain = function verifyChain(certs) { - let chain = x509.parseChain(certs); + const chain = x509.parseChain(certs); // Parse certificates and // check validity time. @@ -449,12 +446,12 @@ x509.verifyChain = function verifyChain(certs) { // Verify signatures. for (let i = 1; i < chain.length; i++) { - let child = chain[i - 1]; - let parent = chain[i]; - let alg = x509.getSigAlgorithm(child); - let key = x509.getPublicKey(parent); - let msg = child.tbs.raw; - let sig = child.sig; + const child = chain[i - 1]; + const parent = chain[i]; + const alg = x509.getSigAlgorithm(child); + const key = x509.getPublicKey(parent); + const msg = child.tbs.raw; + const sig = child.sig; if (!pk.verify(alg.hash, msg, sig, key)) throw new Error(`${alg.key} verification failed for chain.`); diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 8a3f6cb4c..bfbdb59f3 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -71,13 +71,12 @@ function Chain(options) { this.network = this.options.network; this.logger = this.options.logger.context('chain'); this.workers = this.options.workers; - this.checkpoints = this.options.checkpoints; this.locker = new Lock(true); this.invalid = new LRU(100); this.state = new DeploymentState(); - this.tip = null; + this.tip = new ChainEntry(this); this.height = -1; this.synced = false; @@ -87,7 +86,7 @@ function Chain(options) { this.db = new ChainDB(this); } -util.inherits(Chain, AsyncObject); +Object.setPrototypeOf(Chain.prototype, AsyncObject.prototype); /** * Open the chain, wait for the database to load. @@ -96,9 +95,7 @@ util.inherits(Chain, AsyncObject); * @returns {Promise} */ -Chain.prototype._open = async function open() { - let tip, state; - +Chain.prototype._open = async function _open() { this.logger.info('Chain is loading.'); if (this.options.checkpoints) @@ -115,7 +112,7 @@ Chain.prototype._open = async function open() { await this.db.open(); - tip = await this.db.getTip(); + const tip = await this.db.getTip(); assert(tip); @@ -126,7 +123,7 @@ Chain.prototype._open = async function open() { this.logger.memory(); - state = await this.getDeploymentState(); + const state = await this.getDeploymentState(); this.setDeploymentState(state); @@ -143,7 +140,7 @@ Chain.prototype._open = async function open() { * @returns {Promise} */ -Chain.prototype._close = function close() { +Chain.prototype._close = function _close() { return this.db.close(); }; @@ -158,16 +155,14 @@ Chain.prototype._close = function close() { */ Chain.prototype.verifyContext = async function verifyContext(block, prev, flags) { - let state, view; - // Initial non-contextual verification. - state = await this.verify(block, prev, flags); + const state = await this.verify(block, prev, flags); // BIP30 - Verify there are no duplicate txids. await this.verifyDuplicates(block, prev, state); // Verify scripts, spend and add coins. - view = await this.verifyInputs(block, prev, state); + const view = await this.verifyInputs(block, prev, state); return [view, state]; }; @@ -181,7 +176,7 @@ Chain.prototype.verifyContext = async function verifyContext(block, prev, flags) */ Chain.prototype.verifyBlock = async function verifyBlock(block) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._verifyBlock(block); } finally { @@ -198,8 +193,8 @@ Chain.prototype.verifyBlock = async function verifyBlock(block) { * @returns {Promise} */ -Chain.prototype._verifyBlock = async function verifyBlock(block) { - let flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; +Chain.prototype._verifyBlock = async function _verifyBlock(block) { + const flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; return await this.verifyContext(block, this.tip, flags); }; @@ -226,11 +221,10 @@ Chain.prototype.isGenesis = function isGenesis(block) { */ Chain.prototype.verify = async function verify(block, prev, flags) { - let deployments = this.network.deployments; - let hash = block.hash('hex'); - let now = this.network.now(); - let height = prev.height + 1; - let ts, mtp, commit, state, bits; + const deployments = this.network.deployments; + const hash = block.hash('hex'); + const now = this.network.now(); + const height = prev.height + 1; assert(typeof flags === 'number'); @@ -264,7 +258,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) { // Non-contextual checks. if (flags & common.flags.VERIFY_BODY) { - let [valid, reason, score] = block.checkBody(); + const [valid, reason, score] = block.checkBody(); if (!valid) throw new VerifyError(block, 'invalid', reason, score, true); @@ -275,7 +269,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) { return this.state; // Ensure the POW is what we expect. - bits = await this.getTarget(block.ts, prev); + const bits = await this.getTarget(block.time, prev); if (block.bits !== bits) { throw new VerifyError(block, @@ -285,9 +279,9 @@ Chain.prototype.verify = async function verify(block, prev, flags) { } // Ensure the timestamp is correct. - mtp = await prev.getMedianTime(); + const mtp = await prev.getMedianTime(); - if (block.ts <= mtp) { + if (block.time <= mtp) { throw new VerifyError(block, 'invalid', 'time-too-old', @@ -297,7 +291,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) { // Check timestamp against adj-time+2hours. // If this fails we may be able to accept // the block later. - if (block.ts > now + 2 * 60 * 60) { + if (block.time > now + 2 * 60 * 60) { throw new VerifyError(block, 'invalid', 'time-too-new', @@ -321,7 +315,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) { throw new VerifyError(block, 'obsolete', 'bad-version', 0); // Get the new deployment state. - state = await this.getDeployments(block.ts, prev); + const state = await this.getDeployments(block.time, prev); // Enforce BIP91/BIP148. if (state.hasBIP91() || state.hasBIP148()) { @@ -330,12 +324,12 @@ Chain.prototype.verify = async function verify(block, prev, flags) { } // Get timestamp for tx.isFinal(). - ts = state.hasMTP() ? mtp : block.ts; + const time = state.hasMTP() ? mtp : block.time; // Transactions must be finalized with // regards to nSequence and nLockTime. - for (let tx of block.txs) { - if (!tx.isFinal(height, ts)) { + for (const tx of block.txs) { + if (!tx.isFinal(height, time)) { throw new VerifyError(block, 'invalid', 'bad-txns-nonfinal', @@ -355,6 +349,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) { } // Check the commitment hash for segwit. + let commit; if (state.hasWitness()) { commit = block.getCommitmentHash(); if (commit) { @@ -409,16 +404,15 @@ Chain.prototype.verify = async function verify(block, prev, flags) { /** * Check all deployments on a chain, ranging from p2sh to segwit. * @method - * @param {Number} ts + * @param {Number} time * @param {ChainEntry} prev * @returns {Promise} - Returns {@link DeploymentState}. */ -Chain.prototype.getDeployments = async function getDeployments(ts, prev) { - let deployments = this.network.deployments; - let height = prev.height + 1; - let state = new DeploymentState(); - let witness; +Chain.prototype.getDeployments = async function getDeployments(time, prev) { + const deployments = this.network.deployments; + const height = prev.height + 1; + const state = new DeploymentState(); // For some reason bitcoind has p2sh in the // mandatory flags by default, when in reality @@ -428,7 +422,7 @@ Chain.prototype.getDeployments = async function getDeployments(ts, prev) { // not have a signature. See: // 6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192 // 9c08a4d78931342b37fd5f72900fb9983087e6f46c4a097d8a1f52c74e28eaf6 - if (ts >= consensus.BIP16_TIME) + if (time >= consensus.BIP16_TIME) state.flags |= Script.flags.VERIFY_P2SH; // Coinbase heights are now enforced (bip34). @@ -452,7 +446,7 @@ Chain.prototype.getDeployments = async function getDeployments(ts, prev) { } // Check the state of the segwit deployment. - witness = await this.getState(prev, deployments.segwit); + const witness = await this.getState(prev, deployments.segwit); // Segregrated witness (bip141) is now usable // along with SCRIPT_VERIFY_NULLDUMMY (bip147). @@ -480,7 +474,7 @@ Chain.prototype.getDeployments = async function getDeployments(ts, prev) { // assumption that deployment checks should // only ever examine the values of the // previous block (necessary for mining). - let mtp = await prev.getMedianTime(ts); + const mtp = await prev.getMedianTime(time); if (mtp >= 1501545600 && mtp <= 1510704000) state.bip148 = true; } @@ -495,6 +489,11 @@ Chain.prototype.getDeployments = async function getDeployments(ts, prev) { */ Chain.prototype.setDeploymentState = function setDeploymentState(state) { + if (this.options.checkpoints && this.height < this.network.lastCheckpoint) { + this.state = state; + return; + } + if (!this.state.hasP2SH() && state.hasP2SH()) this.logger.warning('P2SH has been activated.'); @@ -547,11 +546,11 @@ Chain.prototype.verifyDuplicates = async function verifyDuplicates(block, prev, return; // Check all transactions. - for (let tx of block.txs) { - let result = await this.db.hasCoins(tx.hash()); + for (const tx of block.txs) { + const result = await this.db.hasCoins(tx); if (result) { - let height = prev.height + 1; + const height = prev.height + 1; // Blocks 91842 and 91880 created duplicate // txids by using the same exact output script @@ -586,24 +585,25 @@ Chain.prototype.verifyDuplicates = async function verifyDuplicates(block, prev, */ Chain.prototype.verifyInputs = async function verifyInputs(block, prev, state) { - let interval = this.network.halvingInterval; - let view = new CoinView(); - let height = prev.height + 1; - let historical = prev.isHistorical(); - let jobs = []; - let sigops = 0; - let reward = 0; + const view = new CoinView(); if (this.options.spv) return view; + const interval = this.network.halvingInterval; + const height = prev.height + 1; + const historical = prev.isHistorical(); + + let sigops = 0; + let reward = 0; + // Check all transactions for (let i = 0; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; // Ensure tx is not double spending an output. if (i > 0) { - if (!(await view.spendInputs(this.db, tx))) { + if (!await view.spendInputs(this.db, tx)) { assert(!historical, 'BUG: Spent inputs in historical data!'); throw new VerifyError(block, 'invalid', @@ -621,7 +621,7 @@ Chain.prototype.verifyInputs = async function verifyInputs(block, prev, state) { // Verify sequence locks. if (i > 0 && tx.version >= 2) { - let valid = await this.verifyLocks(prev, tx, view, state.lockFlags); + const valid = await this.verifyLocks(prev, tx, view, state.lockFlags); if (!valid) { throw new VerifyError(block, @@ -643,7 +643,7 @@ Chain.prototype.verifyInputs = async function verifyInputs(block, prev, state) { // Contextual sanity checks. if (i > 0) { - let [fee, reason, score] = tx.checkInputs(view, height); + const [fee, reason, score] = tx.checkInputs(view, height); if (fee === -1) { throw new VerifyError(block, @@ -681,13 +681,14 @@ Chain.prototype.verifyInputs = async function verifyInputs(block, prev, state) { } // Push onto verification queue. + const jobs = []; for (let i = 1; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; jobs.push(tx.verifyAsync(view, state.flags, this.workers)); } // Verify all txs in parallel. - if (!(await co.every(jobs))) { + if (!await co.every(jobs)) { throw new VerifyError(block, 'invalid', 'mandatory-script-verify-flag-failed', @@ -705,7 +706,7 @@ Chain.prototype.verifyInputs = async function verifyInputs(block, prev, state) { */ Chain.prototype.checkHeight = function checkHeight(hash) { - let entry = this.db.getCache(hash); + const entry = this.db.getCache(hash); if (!entry) return -1; @@ -753,16 +754,14 @@ Chain.prototype.findFork = async function findFork(fork, longer) { */ Chain.prototype.reorganize = async function reorganize(competitor) { - let tip = this.tip; - let fork = await this.findFork(tip, competitor); - let disconnect = []; - let connect = []; - let entry; + const tip = this.tip; + const fork = await this.findFork(tip, competitor); assert(fork, 'No free space or data corruption.'); // Blocks to disconnect. - entry = tip; + const disconnect = []; + let entry = tip; while (entry.hash !== fork.hash) { disconnect.push(entry); entry = await entry.getPrevious(); @@ -770,6 +769,7 @@ Chain.prototype.reorganize = async function reorganize(competitor) { } // Blocks to connect. + const connect = []; entry = competitor; while (entry.hash !== fork.hash) { connect.push(entry); @@ -779,7 +779,7 @@ Chain.prototype.reorganize = async function reorganize(competitor) { // Disconnect blocks/txs. for (let i = 0; i < disconnect.length; i++) { - let entry = disconnect[i]; + const entry = disconnect[i]; await this.disconnect(entry); } @@ -787,7 +787,7 @@ Chain.prototype.reorganize = async function reorganize(competitor) { // We don't want to connect the new tip here. // That will be done outside in setBestChain. for (let i = connect.length - 1; i >= 1; i--) { - let entry = connect[i]; + const entry = connect[i]; await this.reconnect(entry); } @@ -812,14 +812,14 @@ Chain.prototype.reorganize = async function reorganize(competitor) { */ Chain.prototype.reorganizeSPV = async function reorganizeSPV(competitor) { - let tip = this.tip; - let fork = await this.findFork(tip, competitor); - let disconnect = []; - let entry = tip; + const tip = this.tip; + const fork = await this.findFork(tip, competitor); assert(fork, 'No free space or data corruption.'); // Buffer disconnected blocks. + const disconnect = []; + let entry = tip; while (entry.hash !== fork.hash) { disconnect.push(entry); entry = await entry.getPrevious(); @@ -834,9 +834,9 @@ Chain.prototype.reorganizeSPV = async function reorganizeSPV(competitor) { // Emit disconnection events now that // the chain has successfully reset. - for (let entry of disconnect) { - let headers = entry.toHeaders(); - let view = new CoinView(); + for (const entry of disconnect) { + const headers = entry.toHeaders(); + const view = new CoinView(); await this.fire('disconnect', entry, headers, view); } @@ -864,7 +864,6 @@ Chain.prototype.reorganizeSPV = async function reorganizeSPV(competitor) { Chain.prototype.disconnect = async function disconnect(entry) { let block = await this.db.getBlock(entry.hash); - let prev, view; if (!block) { if (!this.options.spv) @@ -872,8 +871,8 @@ Chain.prototype.disconnect = async function disconnect(entry) { block = entry.toHeaders(); } - prev = await entry.getPrevious(); - view = await this.db.disconnect(entry, block); + const prev = await entry.getPrevious(); + const view = await this.db.disconnect(entry, block); assert(prev); @@ -897,9 +896,9 @@ Chain.prototype.disconnect = async function disconnect(entry) { */ Chain.prototype.reconnect = async function reconnect(entry) { - let flags = common.flags.VERIFY_NONE; + const flags = common.flags.VERIFY_NONE; + let block = await this.db.getBlock(entry.hash); - let prev, view, state; if (!block) { if (!this.options.spv) @@ -907,9 +906,10 @@ Chain.prototype.reconnect = async function reconnect(entry) { block = entry.toHeaders(); } - prev = await entry.getPrevious(); + const prev = await entry.getPrevious(); assert(prev); + let view, state; try { [view, state] = await this.verifyContext(block, prev, flags); } catch (err) { @@ -950,8 +950,6 @@ Chain.prototype.reconnect = async function reconnect(entry) { */ Chain.prototype.setBestChain = async function setBestChain(entry, block, prev, flags) { - let view, state; - // A higher fork has arrived. // Time to reorganize the chain. if (entry.prevBlock !== this.tip.hash) { @@ -959,8 +957,10 @@ Chain.prototype.setBestChain = async function setBestChain(entry, block, prev, f // In spv-mode, we reset the // chain and redownload the blocks. - if (this.options.spv) - return await this.reorganizeSPV(entry); + if (this.options.spv) { + await this.reorganizeSPV(entry); + return; + } await this.reorganize(entry); } @@ -976,6 +976,7 @@ Chain.prototype.setBestChain = async function setBestChain(entry, block, prev, f // Do "contextual" verification on our block // now that we're certain its previous // block is in the chain. + let view, state; try { [view, state] = await this.verifyContext(block, prev, flags); } catch (err) { @@ -1067,7 +1068,7 @@ Chain.prototype.saveAlternate = async function saveAlternate(entry, block, prev, */ Chain.prototype.reset = async function reset(block) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._reset(block, false); } finally { @@ -1083,16 +1084,15 @@ Chain.prototype.reset = async function reset(block) { * @returns {Promise} */ -Chain.prototype._reset = async function reset(block, silent) { - let tip = await this.db.reset(block); - let state; +Chain.prototype._reset = async function _reset(block, silent) { + const tip = await this.db.reset(block); // Reset state. this.tip = tip; this.height = tip.height; this.synced = false; - state = await this.getDeploymentState(); + const state = await this.getDeploymentState(); this.setDeploymentState(state); @@ -1118,7 +1118,7 @@ Chain.prototype._reset = async function reset(block, silent) { */ Chain.prototype.replay = async function replay(block) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._replay(block, true); } finally { @@ -1135,17 +1135,19 @@ Chain.prototype.replay = async function replay(block) { * @returns {Promise} */ -Chain.prototype._replay = async function replay(block, silent) { - let entry = await this.db.getEntry(block); +Chain.prototype._replay = async function _replay(block, silent) { + const entry = await this.db.getEntry(block); if (!entry) throw new Error('Block not found.'); - if (!(await entry.isMainChain())) + if (!await entry.isMainChain()) throw new Error('Cannot reset on alternate chain.'); - if (entry.isGenesis()) - return await this._reset(entry.hash, silent); + if (entry.isGenesis()) { + await this._reset(entry.hash, silent); + return; + } await this._reset(entry.prevBlock, silent); }; @@ -1158,7 +1160,7 @@ Chain.prototype._replay = async function replay(block, silent) { */ Chain.prototype.invalidate = async function invalidate(hash) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._invalidate(hash); } finally { @@ -1175,7 +1177,7 @@ Chain.prototype.invalidate = async function invalidate(hash) { Chain.prototype._invalidate = async function _invalidate(hash) { await this._replay(hash, false); - this.chain.setInvalid(hash); + this.setInvalid(hash); }; /** @@ -1185,7 +1187,7 @@ Chain.prototype._invalidate = async function _invalidate(hash) { */ Chain.prototype.prune = async function prune() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this.db.prune(this.tip.hash); } finally { @@ -1203,7 +1205,7 @@ Chain.prototype.prune = async function prune() { */ Chain.prototype.scan = async function scan(start, filter, iter) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this.db.scan(start, filter, iter); } finally { @@ -1221,8 +1223,8 @@ Chain.prototype.scan = async function scan(start, filter, iter) { */ Chain.prototype.add = async function add(block, flags, id) { - let hash = block.hash('hex'); - let unlock = await this.locker.lock(hash); + const hash = block.hash('hex'); + const unlock = await this.locker.lock(hash); try { return await this._add(block, flags, id); } finally { @@ -1240,9 +1242,8 @@ Chain.prototype.add = async function add(block, flags, id) { * @returns {Promise} */ -Chain.prototype._add = async function add(block, flags, id) { - let hash = block.hash('hex'); - let entry, prev; +Chain.prototype._add = async function _add(block, flags, id) { + const hash = block.hash('hex'); if (flags == null) flags = common.flags.DEFAULT_FLAGS; @@ -1288,7 +1289,7 @@ Chain.prototype._add = async function add(block, flags, id) { } // Find the previous block entry. - prev = await this.db.getEntry(block.prevBlock); + const prev = await this.db.getEntry(block.prevBlock); // If previous block wasn't ever seen, // add it current to orphans and return. @@ -1298,7 +1299,7 @@ Chain.prototype._add = async function add(block, flags, id) { } // Connect the block. - entry = await this.connect(prev, block, flags); + const entry = await this.connect(prev, block, flags); // Handle any orphans. if (this.hasNextOrphan(hash)) @@ -1318,8 +1319,7 @@ Chain.prototype._add = async function add(block, flags, id) { */ Chain.prototype.connect = async function connect(prev, block, flags) { - let start = util.hrtime(); - let entry; + const start = util.hrtime(); // Sanity check. assert(block.prevBlock === prev.hash); @@ -1334,7 +1334,7 @@ Chain.prototype.connect = async function connect(prev, block, flags) { // validated, and connected. Hopefully the // deserialized blocks get cleaned up by the // GC quickly. - if (block.memory) { + if (block.isMemory()) { try { block = block.toBlock(); } catch (e) { @@ -1342,12 +1342,13 @@ Chain.prototype.connect = async function connect(prev, block, flags) { throw new VerifyError(block, 'malformed', 'error parsing message', - 10); + 10, + true); } } // Create a new chain entry. - entry = ChainEntry.fromBlock(this, block, prev); + const entry = ChainEntry.fromBlock(this, block, prev); // The block is on a alternate chain if the // chainwork is less than or equal to @@ -1382,7 +1383,7 @@ Chain.prototype.handleOrphans = async function handleOrphans(entry) { let orphan = this.resolveOrphan(entry.hash); while (orphan) { - let {block, flags, id} = orphan; + const {block, flags, id} = orphan; try { entry = await this.connect(entry, block, flags); @@ -1441,15 +1442,13 @@ Chain.prototype.isSlow = function isSlow() { */ Chain.prototype.logStatus = function logStatus(start, block, entry) { - let elapsed; - if (!this.isSlow()) return; // Report memory for debugging. this.logger.memory(); - elapsed = util.hrtime(start); + const elapsed = util.hrtime(start); this.logger.info( 'Block %s (%d) added to chain (size=%d txs=%d time=%d).', @@ -1474,13 +1473,11 @@ Chain.prototype.logStatus = function logStatus(start, block, entry) { */ Chain.prototype.verifyCheckpoint = function verifyCheckpoint(prev, hash) { - let height, checkpoint; - - if (!this.checkpoints) + if (!this.options.checkpoints) return true; - height = prev.height + 1; - checkpoint = this.network.checkpointMap[height]; + const height = prev.height + 1; + const checkpoint = this.network.checkpointMap[height]; if (!checkpoint) return true; @@ -1517,8 +1514,8 @@ Chain.prototype.verifyCheckpoint = function verifyCheckpoint(prev, hash) { */ Chain.prototype.storeOrphan = function storeOrphan(block, flags, id) { - let hash = block.hash('hex'); - let height = block.getCoinbaseHeight(); + const hash = block.hash('hex'); + const height = block.getCoinbaseHeight(); let orphan = this.orphanPrev.get(block.prevBlock); // The orphan chain forked. @@ -1554,8 +1551,8 @@ Chain.prototype.storeOrphan = function storeOrphan(block, flags, id) { */ Chain.prototype.addOrphan = function addOrphan(orphan) { - let block = orphan.block; - let hash = block.hash('hex'); + const block = orphan.block; + const hash = block.hash('hex'); assert(!this.orphanMap.has(hash)); assert(!this.orphanPrev.has(block.prevBlock)); @@ -1575,8 +1572,8 @@ Chain.prototype.addOrphan = function addOrphan(orphan) { */ Chain.prototype.removeOrphan = function removeOrphan(orphan) { - let block = orphan.block; - let hash = block.hash('hex'); + const block = orphan.block; + const hash = block.hash('hex'); assert(this.orphanMap.has(hash)); assert(this.orphanPrev.has(block.prevBlock)); @@ -1607,10 +1604,10 @@ Chain.prototype.hasNextOrphan = function hasNextOrphan(hash) { */ Chain.prototype.resolveOrphan = function resolveOrphan(hash) { - let orphan = this.orphanPrev.get(hash); + const orphan = this.orphanPrev.get(hash); if (!orphan) - return; + return null; return this.removeOrphan(orphan); }; @@ -1620,7 +1617,7 @@ Chain.prototype.resolveOrphan = function resolveOrphan(hash) { */ Chain.prototype.purgeOrphans = function purgeOrphans() { - let count = this.orphanMap.size; + const count = this.orphanMap.size; if (count === 0) return; @@ -1637,12 +1634,12 @@ Chain.prototype.purgeOrphans = function purgeOrphans() { */ Chain.prototype.limitOrphans = function limitOrphans() { - let now = util.now(); - let oldest; + const now = util.now(); - for (let orphan of this.orphanMap.values()) { - if (now < orphan.ts + 60 * 60) { - if (!oldest || orphan.ts < oldest.ts) + let oldest; + for (const orphan of this.orphanMap.values()) { + if (now < orphan.time + 60 * 60) { + if (!oldest || orphan.time < oldest.time) oldest = orphan; continue; } @@ -1667,7 +1664,7 @@ Chain.prototype.limitOrphans = function limitOrphans() { */ Chain.prototype.hasInvalid = function hasInvalid(block) { - let hash = block.hash('hex'); + const hash = block.hash('hex'); if (this.invalid.has(hash)) return true; @@ -1779,7 +1776,7 @@ Chain.prototype.hasPending = function hasPending(hash) { */ Chain.prototype.getSpentView = async function getSpentView(tx) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this.db.getSpentView(tx); } finally { @@ -1805,15 +1802,12 @@ Chain.prototype.maybeSync = function maybeSync() { if (this.synced) return; - if (this.checkpoints) { - if (this.tip.height < this.network.lastCheckpoint) + if (this.options.checkpoints) { + if (this.height < this.network.lastCheckpoint) return; - - this.logger.info('Last checkpoint reached. Disabling checkpoints.'); - this.checkpoints = false; } - if (this.tip.ts < util.now() - this.network.block.maxTipAge) + if (this.tip.time < util.now() - this.network.block.maxTipAge) return; if (!this.hasChainwork()) @@ -1831,7 +1825,7 @@ Chain.prototype.maybeSync = function maybeSync() { */ Chain.prototype.hasChainwork = function hasChainwork() { - return this.tip.chainwork.cmp(this.network.pow.chainwork) >= 0; + return this.tip.chainwork.gte(this.network.pow.chainwork); }; /** @@ -1840,9 +1834,9 @@ Chain.prototype.hasChainwork = function hasChainwork() { */ Chain.prototype.getProgress = function getProgress() { - let start = this.network.genesis.ts; - let current = this.tip.ts - start; - let end = util.now() - start - 40 * 60; + const start = this.network.genesis.time; + const current = this.tip.time - start; + const end = util.now() - start - 40 * 60; return Math.min(1, current / end); }; @@ -1856,7 +1850,7 @@ Chain.prototype.getProgress = function getProgress() { */ Chain.prototype.getLocator = async function getLocator(start) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._getLocator(start); } finally { @@ -1872,26 +1866,24 @@ Chain.prototype.getLocator = async function getLocator(start) { * @returns {Promise} */ -Chain.prototype._getLocator = async function getLocator(start) { - let hashes = []; - let step = 1; - let height, entry, main, hash; - +Chain.prototype._getLocator = async function _getLocator(start) { if (start == null) start = this.tip.hash; assert(typeof start === 'string'); - entry = await this.db.getEntry(start); + let entry = await this.db.getEntry(start); + const hashes = []; if (!entry) { entry = this.tip; hashes.push(start); } - hash = entry.hash; - height = entry.height; - main = await entry.isMainChain(); + let hash = entry.hash; + let height = entry.height; + const main = await entry.isMainChain(); + let step = 1; hashes.push(hash); @@ -1910,9 +1902,9 @@ Chain.prototype._getLocator = async function getLocator(start) { hash = await this.db.getHash(height); assert(hash); } else { - let entry = await entry.getAncestor(height); - assert(entry); - hash = entry.hash; + const ancestor = await entry.getAncestor(height); + assert(ancestor); + hash = ancestor.hash; } hashes.push(hash); @@ -1928,12 +1920,12 @@ Chain.prototype._getLocator = async function getLocator(start) { */ Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) { - let root; + let root = null; assert(hash); for (;;) { - let orphan = this.orphanMap.get(hash); + const orphan = this.orphanMap.get(hash); if (!orphan) break; @@ -1954,7 +1946,7 @@ Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) { */ Chain.prototype.getProofTime = function getProofTime(to, from) { - let pow = this.network.pow; + const pow = this.network.pow; let sign, work; if (to.chainwork.cmp(from.chainwork) > 0) { @@ -1988,19 +1980,18 @@ Chain.prototype.getCurrentTarget = async function getCurrentTarget() { /** * Calculate the next target. * @method - * @param {Number} ts - Next block timestamp. + * @param {Number} time - Next block timestamp. * @param {ChainEntry} prev - Previous entry. * @returns {Promise} - returns Number * (target is in compact/mantissa form). */ -Chain.prototype.getTarget = async function getTarget(ts, prev) { - let pow = this.network.pow; - let first, height; +Chain.prototype.getTarget = async function getTarget(time, prev) { + const pow = this.network.pow; // Genesis if (!prev) { - assert(ts === this.network.genesis.ts); + assert(time === this.network.genesis.time); return pow.bits; } @@ -2008,13 +1999,13 @@ Chain.prototype.getTarget = async function getTarget(ts, prev) { if ((prev.height + 1) % pow.retargetInterval !== 0) { if (pow.targetReset) { // Special behavior for testnet: - if (ts > prev.ts + pow.targetSpacing * 2) + if (time > prev.time + pow.targetSpacing * 2) return pow.bits; while (prev.height !== 0 && prev.height % pow.retargetInterval !== 0 && prev.bits === pow.bits) { - let cache = prev.getPrevCache(); + const cache = prev.getPrevCache(); if (cache) { prev = cache; @@ -2029,10 +2020,10 @@ Chain.prototype.getTarget = async function getTarget(ts, prev) { } // Back 2 weeks - height = prev.height - (pow.retargetInterval - 1); + const height = prev.height - (pow.retargetInterval - 1); assert(height >= 0); - first = await prev.getAncestor(height); + const first = await prev.getAncestor(height); assert(first); return this.retarget(prev, first); @@ -2047,15 +2038,15 @@ Chain.prototype.getTarget = async function getTarget(ts, prev) { */ Chain.prototype.retarget = function retarget(prev, first) { - let pow = this.network.pow; - let targetTimespan = pow.targetTimespan; - let actualTimespan, target; + const pow = this.network.pow; + const targetTimespan = pow.targetTimespan; if (pow.noRetargeting) return prev.bits; - actualTimespan = prev.ts - first.ts; - target = consensus.fromCompact(prev.bits); + const target = consensus.fromCompact(prev.bits); + + let actualTimespan = prev.time - first.time; if (actualTimespan < targetTimespan / 4 | 0) actualTimespan = targetTimespan / 4 | 0; @@ -2081,7 +2072,7 @@ Chain.prototype.retarget = function retarget(prev, first) { */ Chain.prototype.findLocator = async function findLocator(locator) { - for (let hash of locator) { + for (const hash of locator) { if (await this.db.isMainChain(hash)) return hash; } @@ -2101,7 +2092,7 @@ Chain.prototype.findLocator = async function findLocator(locator) { */ Chain.prototype.isActive = async function isActive(prev, deployment) { - let state = await this.getState(prev, deployment); + const state = await this.getState(prev, deployment); return state === thresholdStates.ACTIVE; }; @@ -2119,9 +2110,7 @@ Chain.prototype.isActive = async function isActive(prev, deployment) { Chain.prototype.getState = async function getState(prev, deployment) { let window = this.network.minerWindow; let threshold = this.network.activationThreshold; - let bit = deployment.bit; - let compute = []; - let entry, state; + const bit = deployment.bit; if (deployment.threshold !== -1) threshold = deployment.threshold; @@ -2130,7 +2119,7 @@ Chain.prototype.getState = async function getState(prev, deployment) { window = deployment.window; if (((prev.height + 1) % window) !== 0) { - let height = prev.height - ((prev.height + 1) % window); + const height = prev.height - ((prev.height + 1) % window); prev = await prev.getAncestor(height); if (!prev) @@ -2140,19 +2129,19 @@ Chain.prototype.getState = async function getState(prev, deployment) { assert(((prev.height + 1) % window) === 0); } - entry = prev; - state = thresholdStates.DEFINED; + let entry = prev; + let state = thresholdStates.DEFINED; + const compute = []; while (entry) { - let cached = this.db.stateCache.get(bit, entry); - let time, height; + const cached = this.db.stateCache.get(bit, entry); if (cached !== -1) { state = cached; break; } - time = await entry.getMedianTime(); + const time = await entry.getMedianTime(); if (time < deployment.startTime) { state = thresholdStates.DEFINED; @@ -2162,16 +2151,16 @@ Chain.prototype.getState = async function getState(prev, deployment) { compute.push(entry); - height = entry.height - window; + const height = entry.height - window; entry = await entry.getAncestor(height); } while (compute.length) { - let entry = compute.pop(); + const entry = compute.pop(); switch (state) { case thresholdStates.DEFINED: { - let time = await entry.getMedianTime(); + const time = await entry.getMedianTime(); if (time >= deployment.timeout) { state = thresholdStates.FAILED; @@ -2186,7 +2175,7 @@ Chain.prototype.getState = async function getState(prev, deployment) { break; } case thresholdStates.STARTED: { - let time = await entry.getMedianTime(); + const time = await entry.getMedianTime(); let block = entry; let count = 0; @@ -2241,8 +2230,8 @@ Chain.prototype.getState = async function getState(prev, deployment) { Chain.prototype.computeBlockVersion = async function computeBlockVersion(prev) { let version = 0; - for (let deployment of this.network.deploys) { - let state = await this.getState(prev, deployment); + for (const deployment of this.network.deploys) { + const state = await this.getState(prev, deployment); if (state === thresholdStates.LOCKED_IN || state === thresholdStates.STARTED) { @@ -2264,7 +2253,7 @@ Chain.prototype.computeBlockVersion = async function computeBlockVersion(prev) { */ Chain.prototype.getDeploymentState = async function getDeploymentState() { - let prev = await this.tip.getPrevious(); + const prev = await this.tip.getPrevious(); if (!prev) { assert(this.tip.isGenesis()); @@ -2274,7 +2263,7 @@ Chain.prototype.getDeploymentState = async function getDeploymentState() { if (this.options.spv) return this.state; - return await this.getDeployments(this.tip.ts, prev); + return await this.getDeployments(this.tip.time, prev); }; /** @@ -2288,15 +2277,15 @@ Chain.prototype.getDeploymentState = async function getDeploymentState() { */ Chain.prototype.verifyFinal = async function verifyFinal(prev, tx, flags) { - let height = prev.height + 1; + const height = prev.height + 1; // We can skip MTP if the locktime is height. if (tx.locktime < consensus.LOCKTIME_THRESHOLD) return tx.isFinal(height, -1); if (flags & common.lockFlags.MEDIAN_TIME_PAST) { - let ts = await prev.getMedianTime(); - return tx.isFinal(height, ts); + const time = await prev.getMedianTime(); + return tx.isFinal(height, time); } return tx.isFinal(height, this.network.now()); @@ -2313,40 +2302,42 @@ Chain.prototype.verifyFinal = async function verifyFinal(prev, tx, flags) { */ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) { - let mask = consensus.SEQUENCE_MASK; - let granularity = consensus.SEQUENCE_GRANULARITY; - let disableFlag = consensus.SEQUENCE_DISABLE_FLAG; - let typeFlag = consensus.SEQUENCE_TYPE_FLAG; - let hasFlag = flags & common.lockFlags.VERIFY_SEQUENCE; - let minHeight = -1; - let minTime = -1; + const GRANULARITY = consensus.SEQUENCE_GRANULARITY; + const DISABE_FLAG = consensus.SEQUENCE_DISABLE_FLAG; + const TYPE_FLAG = consensus.SEQUENCE_TYPE_FLAG; + const MASK = consensus.SEQUENCE_MASK; - if (tx.isCoinbase() || tx.version < 2 || !hasFlag) - return [minHeight, minTime]; + if (!(flags & common.lockFlags.VERIFY_SEQUENCE)) + return [-1, -1]; - for (let input of tx.inputs) { - let height, time, entry; + if (tx.isCoinbase() || tx.version < 2) + return [-1, -1]; - if (input.sequence & disableFlag) + let minHeight = -1; + let minTime = -1; + + for (const {prevout, sequence} of tx.inputs) { + if (sequence & DISABE_FLAG) continue; - height = view.getHeight(input); + let height = view.getHeight(prevout); if (height === -1) height = this.height + 1; - if ((input.sequence & typeFlag) === 0) { - height += (input.sequence & mask) - 1; + if (!(sequence & TYPE_FLAG)) { + height += (sequence & MASK) - 1; minHeight = Math.max(minHeight, height); continue; } height = Math.max(height - 1, 0); - entry = await prev.getAncestor(height); + + const entry = await prev.getAncestor(height); assert(entry, 'Database is corrupt.'); - time = await entry.getMedianTime(); - time += ((input.sequence & mask) << granularity) - 1; + let time = await entry.getMedianTime(); + time += ((sequence & MASK) << GRANULARITY) - 1; minTime = Math.max(minTime, time); } @@ -2364,8 +2355,7 @@ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) { */ Chain.prototype.verifyLocks = async function verifyLocks(prev, tx, view, flags) { - let [height, time] = await this.getLocks(prev, tx, view, flags); - let mtp; + const [height, time] = await this.getLocks(prev, tx, view, flags); // Also catches case where // height is `-1`. Fall through. @@ -2375,7 +2365,7 @@ Chain.prototype.verifyLocks = async function verifyLocks(prev, tx, view, flags) if (time === -1) return true; - mtp = await prev.getMedianTime(); + const mtp = await prev.getMedianTime(); if (time >= mtp) return false; @@ -2468,12 +2458,12 @@ ChainOptions.prototype.fromOptions = function fromOptions(options) { } if (options.maxFiles != null) { - assert(util.isNumber(options.maxFiles)); + assert(util.isU32(options.maxFiles)); this.maxFiles = options.maxFiles; } if (options.cacheSize != null) { - assert(util.isNumber(options.cacheSize)); + assert(util.isU64(options.cacheSize)); this.cacheSize = options.cacheSize; } @@ -2513,17 +2503,17 @@ ChainOptions.prototype.fromOptions = function fromOptions(options) { } if (options.coinCache != null) { - assert(util.isNumber(options.coinCache)); + assert(util.isU64(options.coinCache)); this.coinCache = options.coinCache; } if (options.entryCache != null) { - assert(util.isNumber(options.entryCache)); + assert(util.isU32(options.entryCache)); this.entryCache = options.entryCache; } if (options.maxOrphans != null) { - assert(util.isNumber(options.maxOrphans)); + assert(util.isU32(options.maxOrphans)); this.maxOrphans = options.maxOrphans; } @@ -2657,7 +2647,7 @@ function Orphan(block, flags, id) { this.block = block; this.flags = flags; this.id = id; - this.ts = util.now(); + this.time = util.now(); } /* diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index dbbc25772..cf742bce0 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -25,6 +25,7 @@ const Outpoint = require('../primitives/outpoint'); const Address = require('../primitives/address'); const ChainEntry = require('./chainentry'); const TXMeta = require('../primitives/txmeta'); +const CoinEntry = require('../coins/coinentry'); const U8 = encoding.U8; const U32 = encoding.U32; @@ -78,14 +79,12 @@ ChainDB.layout = layout; */ ChainDB.prototype.open = async function open() { - let state; - this.logger.info('Opening ChainDB...'); await this.db.open(); - await this.db.checkVersion('V', 2); + await this.db.checkVersion('V', 3); - state = await this.getState(); + const state = await this.getState(); if (state) { // Verify options have not changed. @@ -184,7 +183,7 @@ ChainDB.prototype.batch = function batch() { */ ChainDB.prototype.drop = function drop() { - let batch = this.current; + const batch = this.current; assert(this.current); assert(this.pending); @@ -274,8 +273,6 @@ ChainDB.prototype.getCache = function getCache(block) { */ ChainDB.prototype.getHeight = async function getHeight(hash) { - let entry, height; - if (typeof hash === 'number') return hash; @@ -284,12 +281,12 @@ ChainDB.prototype.getHeight = async function getHeight(hash) { if (hash === encoding.NULL_HASH) return -1; - entry = this.cacheHash.get(hash); + const entry = this.cacheHash.get(hash); if (entry) return entry.height; - height = await this.db.get(layout.h(hash)); + const height = await this.db.get(layout.h(hash)); if (!height) return -1; @@ -306,25 +303,23 @@ ChainDB.prototype.getHeight = async function getHeight(hash) { */ ChainDB.prototype.getHash = async function getHash(height) { - let entry, hash; - if (typeof height === 'string') return height; assert(typeof height === 'number'); if (height < 0) - return; + return null; - entry = this.cacheHeight.get(height); + const entry = this.cacheHeight.get(height); if (entry) return entry.hash; - hash = await this.db.get(layout.H(height)); + const hash = await this.db.get(layout.H(height)); if (!hash) - return; + return null; return hash.toString('hex'); }; @@ -337,30 +332,28 @@ ChainDB.prototype.getHash = async function getHash(height) { */ ChainDB.prototype.getEntryByHeight = async function getEntryByHeight(height) { - let state, entry, hash; - assert(typeof height === 'number'); if (height < 0) - return; + return null; - entry = this.cacheHeight.get(height); + const cache = this.cacheHeight.get(height); - if (entry) - return entry; + if (cache) + return cache; - hash = await this.db.get(layout.H(height)); + const data = await this.db.get(layout.H(height)); - if (!hash) - return; + if (!data) + return null; - hash = hash.toString('hex'); - state = this.chain.state; + const hash = data.toString('hex'); - entry = await this.getEntryByHash(hash); + const state = this.chain.state; + const entry = await this.getEntryByHash(hash); if (!entry) - return; + return null; // By the time getEntry has completed, // a reorg may have occurred. This entry @@ -379,24 +372,22 @@ ChainDB.prototype.getEntryByHeight = async function getEntryByHeight(height) { */ ChainDB.prototype.getEntryByHash = async function getEntryByHash(hash) { - let entry, raw; - assert(typeof hash === 'string'); if (hash === encoding.NULL_HASH) - return; + return null; - entry = this.cacheHash.get(hash); + const cache = this.cacheHash.get(hash); - if (entry) - return entry; + if (cache) + return cache; - raw = await this.db.get(layout.e(hash)); + const raw = await this.db.get(layout.e(hash)); if (!raw) - return; + return null; - entry = ChainEntry.fromRaw(this.chain, raw); + const entry = ChainEntry.fromRaw(this.chain, raw); // There's no efficient way to check whether // this is in the main chain or not, so @@ -426,7 +417,7 @@ ChainDB.prototype.getEntry = function getEntry(block) { */ ChainDB.prototype.hasEntry = async function hasEntry(hash) { - let height = await this.getHeight(hash); + const height = await this.getHeight(hash); return height !== -1; }; @@ -446,10 +437,10 @@ ChainDB.prototype.getTip = function getTip() { */ ChainDB.prototype.getState = async function getState() { - let data = await this.db.get(layout.R); + const data = await this.db.get(layout.R); if (!data) - return; + return null; return ChainState.fromRaw(data); }; @@ -461,9 +452,9 @@ ChainDB.prototype.getState = async function getState() { */ ChainDB.prototype.saveGenesis = async function saveGenesis() { - let genesis = this.network.genesisBlock; - let block = Block.fromRaw(genesis, 'hex'); - let entry = ChainEntry.fromBlock(this.chain, block); + const genesis = this.network.genesisBlock; + const block = Block.fromRaw(genesis, 'hex'); + const entry = ChainEntry.fromBlock(this.chain, block); this.logger.info('Writing genesis block to ChainDB.'); @@ -477,10 +468,10 @@ ChainDB.prototype.saveGenesis = async function saveGenesis() { */ ChainDB.prototype.getFlags = async function getFlags() { - let data = await this.db.get(layout.O); + const data = await this.db.get(layout.O); if (!data) - return; + return null; return ChainFlags.fromRaw(data); }; @@ -493,8 +484,8 @@ ChainDB.prototype.getFlags = async function getFlags() { */ ChainDB.prototype.verifyFlags = async function verifyFlags(state) { - let options = this.options; - let flags = await this.getFlags(); + const options = this.options; + const flags = await this.getFlags(); let needsSave = false; let needsPrune = false; @@ -567,17 +558,17 @@ ChainDB.prototype.verifyFlags = async function verifyFlags(state) { */ ChainDB.prototype.getStateCache = async function getStateCache() { - let stateCache = new StateCache(this.network); + const stateCache = new StateCache(this.network); - let items = await this.db.range({ + const items = await this.db.range({ gte: layout.v(0, encoding.ZERO_HASH), lte: layout.v(255, encoding.MAX_HASH), values: true }); - for (let item of items) { - let [bit, hash] = layout.vv(item.key); - let state = item.value[0]; + for (const item of items) { + const [bit, hash] = layout.vv(item.key); + const state = item.value[0]; stateCache.insert(bit, hash, state); } @@ -590,7 +581,7 @@ ChainDB.prototype.getStateCache = async function getStateCache() { */ ChainDB.prototype.saveDeployments = function saveDeployments() { - let batch = this.db.batch(); + const batch = this.db.batch(); this.writeDeployments(batch); return batch.write(); }; @@ -601,16 +592,16 @@ ChainDB.prototype.saveDeployments = function saveDeployments() { */ ChainDB.prototype.writeDeployments = function writeDeployments(batch) { - let bw = new StaticWriter(1 + 17 * this.network.deploys.length); + const bw = new StaticWriter(1 + 17 * this.network.deploys.length); bw.writeU8(this.network.deploys.length); - for (let deployment of this.network.deploys) { + for (const deployment of this.network.deploys) { bw.writeU8(deployment.bit); bw.writeU32(deployment.startTime); bw.writeU32(deployment.timeout); - bw.write32(deployment.threshold); - bw.write32(deployment.window); + bw.writeI32(deployment.threshold); + bw.writeI32(deployment.window); } batch.put(layout.V, bw.render()); @@ -624,22 +615,21 @@ ChainDB.prototype.writeDeployments = function writeDeployments(batch) { */ ChainDB.prototype.checkDeployments = async function checkDeployments() { - let raw = await this.db.get(layout.V); - let invalid = []; - let br, count; + const raw = await this.db.get(layout.V); assert(raw, 'No deployment table found.'); - br = new BufferReader(raw); - count = br.readU8(); + const br = new BufferReader(raw); + const count = br.readU8(); + const invalid = []; for (let i = 0; i < count; i++) { - let bit = br.readU8(); - let start = br.readU32(); - let timeout = br.readU32(); - let threshold = br.read32(); - let window = br.read32(); - let deployment = this.network.byBit(bit); + const bit = br.readU8(); + const start = br.readU32(); + const timeout = br.readU32(); + const threshold = br.readI32(); + const window = br.readI32(); + const deployment = this.network.byBit(bit); if (deployment && start === deployment.startTime @@ -662,7 +652,7 @@ ChainDB.prototype.checkDeployments = async function checkDeployments() { */ ChainDB.prototype.verifyDeployments = async function verifyDeployments() { - let invalid, batch; + let invalid; try { invalid = await this.checkDeployments(); @@ -670,16 +660,16 @@ ChainDB.prototype.verifyDeployments = async function verifyDeployments() { if (e.type !== 'EncodingError') throw e; invalid = []; - for (let {bit} of this.network.deploys) - invalid.push(bit); + for (let i = 0; i < 32; i++) + invalid.push(i); } if (invalid.length === 0) return true; - batch = this.db.batch(); + const batch = this.db.batch(); - for (let bit of invalid) { + for (const bit of invalid) { this.logger.warning('Versionbit deployment params modified.'); this.logger.warning('Invalidating cache for bit %d.', bit); await this.invalidateCache(bit, batch); @@ -700,12 +690,12 @@ ChainDB.prototype.verifyDeployments = async function verifyDeployments() { */ ChainDB.prototype.invalidateCache = async function invalidateCache(bit, batch) { - let keys = await this.db.keys({ + const keys = await this.db.keys({ gte: layout.v(bit, encoding.ZERO_HASH), lte: layout.v(bit, encoding.MAX_HASH) }); - for (let key of keys) + for (const key of keys) batch.del(key); }; @@ -717,25 +707,26 @@ ChainDB.prototype.invalidateCache = async function invalidateCache(bit, batch) { */ ChainDB.prototype.prune = async function prune(tip) { - let options = this.options; - let keepBlocks = this.network.block.keepBlocks; - let pruneAfter = this.network.block.pruneAfterHeight; - let flags = await this.getFlags(); - let height = await this.getHeight(tip); - let start, end, batch; + const options = this.options; + const keepBlocks = this.network.block.keepBlocks; + const pruneAfter = this.network.block.pruneAfterHeight; + + const flags = await this.getFlags(); if (flags.prune) throw new Error('Chain is already pruned.'); + const height = await this.getHeight(tip); + if (height <= pruneAfter + keepBlocks) return false; - start = pruneAfter + 1; - end = height - keepBlocks; - batch = this.db.batch(); + const start = pruneAfter + 1; + const end = height - keepBlocks; + const batch = this.db.batch(); for (let i = start; i <= end; i++) { - let hash = await this.getHash(i); + const hash = await this.getHash(i); if (!hash) throw new Error(`Cannot find hash for ${i}.`); @@ -747,7 +738,7 @@ ChainDB.prototype.prune = async function prune(tip) { try { options.prune = true; - flags = ChainFlags.fromOptions(options); + const flags = ChainFlags.fromOptions(options); assert(flags.prune); batch.put(layout.O, flags.toRaw()); @@ -771,10 +762,10 @@ ChainDB.prototype.prune = async function prune(tip) { */ ChainDB.prototype.getNextHash = async function getNextHash(hash) { - let data = await this.db.get(layout.n(hash)); + const data = await this.db.get(layout.n(hash)); if (!data) - return; + return null; return data.toString('hex'); }; @@ -787,8 +778,6 @@ ChainDB.prototype.getNextHash = async function getNextHash(hash) { */ ChainDB.prototype.isMainChain = async function isMainChain(hash) { - let entry; - assert(typeof hash === 'string'); if (hash === this.chain.tip.hash @@ -799,12 +788,12 @@ ChainDB.prototype.isMainChain = async function isMainChain(hash) { if (hash === encoding.NULL_HASH) return false; - entry = this.cacheHash.get(hash); + const cacheHash = this.cacheHash.get(hash); - if (entry) { - entry = this.cacheHeight.get(entry.height); - if (entry) - return entry.hash === hash; + if (cacheHash) { + const cacheHeight = this.cacheHeight.get(cacheHash.height); + if (cacheHeight) + return cacheHeight.hash === hash; } if (await this.getNextHash(hash)) @@ -842,69 +831,67 @@ ChainDB.prototype.getTips = function getTips() { /** * Get a coin (unspents only). * @method - * @param {Hash} hash - * @param {Number} index - * @returns {Promise} - Returns {@link Coin}. + * @private + * @param {Outpoint} prevout + * @returns {Promise} - Returns {@link CoinEntry}. */ -ChainDB.prototype.getCoin = async function getCoin(hash, index) { - let state = this.state; - let raw; - +ChainDB.prototype.readCoin = async function readCoin(prevout) { if (this.options.spv) - return; + return null; + + const {hash, index} = prevout; + const key = prevout.toKey(); + const state = this.state; - raw = this.coinCache.get(hash); + const cache = this.coinCache.get(key); - if (raw) - return Coins.parseCoin(raw, hash, index); + if (cache) + return CoinEntry.fromRaw(cache); - raw = await this.db.get(layout.c(hash)); + const raw = await this.db.get(layout.c(hash, index)); if (!raw) - return; + return null; if (state === this.state) - this.coinCache.set(hash, raw); + this.coinCache.set(key, raw); - return Coins.parseCoin(raw, hash, index); + return CoinEntry.fromRaw(raw); }; /** - * Get coins (unspents only). + * Get a coin (unspents only). * @method * @param {Hash} hash - * @returns {Promise} - Returns {@link Coins}. + * @param {Number} index + * @returns {Promise} - Returns {@link Coin}. */ -ChainDB.prototype.getCoins = async function getCoins(hash) { - let raw; - - if (this.options.spv) - return; - - raw = this.coinCache.get(hash); - - if (raw) - return Coins.fromRaw(raw, hash); +ChainDB.prototype.getCoin = async function getCoin(hash, index) { + const prevout = new Outpoint(hash, index); + const coin = await this.readCoin(prevout); - raw = await this.db.get(layout.c(hash)); + if (!coin) + return null; - if (!raw) - return; - - return Coins.fromRaw(raw, hash); + return coin.toCoin(prevout); }; /** * Check whether coins are still unspent. Necessary for bip30. * @see https://bitcointalk.org/index.php?topic=67738.0 - * @param {Hash} hash + * @param {TX} tx * @returns {Promise} - Returns Boolean. */ -ChainDB.prototype.hasCoins = function hasCoins(hash) { - return this.db.has(layout.c(hash)); +ChainDB.prototype.hasCoins = async function hasCoins(tx) { + for (let i = 0; i < tx.outputs.length; i++) { + const key = layout.c(tx.hash(), i); + if (await this.db.has(key)) + return true; + } + return false; }; /** @@ -915,20 +902,18 @@ ChainDB.prototype.hasCoins = function hasCoins(hash) { */ ChainDB.prototype.getCoinView = async function getCoinView(tx) { - let view = new CoinView(); - let prevout = tx.getPrevout(); + const view = new CoinView(); - for (let hash of prevout) { - let coins = await this.getCoins(hash); + for (const {prevout} of tx.inputs) { + const coin = await this.readCoin(prevout); - if (!coins) { - coins = new Coins(); - coins.hash = hash; - view.add(coins); + if (!coin) { + const coins = new Coins(); + view.add(prevout.hash, coins); continue; } - view.add(coins); + view.addEntry(prevout, coin); } return view; @@ -942,15 +927,13 @@ ChainDB.prototype.getCoinView = async function getCoinView(tx) { */ ChainDB.prototype.getSpentView = async function getSpentView(tx) { - let view = await this.getCoinView(tx); - - for (let coins of view.map.values()) { - let meta; + const view = await this.getCoinView(tx); + for (const [hash, coins] of view.map) { if (!coins.isEmpty()) continue; - meta = await this.getMeta(coins.hash); + const meta = await this.getMeta(hash); if (!meta) continue; @@ -969,9 +952,11 @@ ChainDB.prototype.getSpentView = async function getSpentView(tx) { */ ChainDB.prototype.getUndoCoins = async function getUndoCoins(hash) { - let data = await this.db.get(layout.u(hash)); + const data = await this.db.get(layout.u(hash)); + if (!data) return new UndoCoins(); + return UndoCoins.fromRaw(data); }; @@ -983,10 +968,10 @@ ChainDB.prototype.getUndoCoins = async function getUndoCoins(hash) { */ ChainDB.prototype.getBlock = async function getBlock(hash) { - let data = await this.getRawBlock(hash); + const data = await this.getRawBlock(hash); if (!data) - return; + return null; return Block.fromRaw(data); }; @@ -999,15 +984,13 @@ ChainDB.prototype.getBlock = async function getBlock(hash) { */ ChainDB.prototype.getRawBlock = async function getRawBlock(block) { - let hash; - if (this.options.spv) - return; + return null; - hash = await this.getHash(block); + const hash = await this.getHash(block); if (!hash) - return; + return null; return await this.db.get(layout.b(hash)); }; @@ -1020,30 +1003,17 @@ ChainDB.prototype.getRawBlock = async function getRawBlock(block) { */ ChainDB.prototype.getBlockView = async function getBlockView(block) { - let view = new CoinView(); - let undo = await this.getUndoCoins(block.hash()); + const view = new CoinView(); + const undo = await this.getUndoCoins(block.hash()); if (undo.isEmpty()) return view; for (let i = block.txs.length - 1; i > 0; i--) { - let tx = block.txs[i]; + const tx = block.txs[i]; for (let j = tx.inputs.length - 1; j >= 0; j--) { - let input = tx.inputs[j]; - let prev = input.prevout.hash; - - if (!view.has(prev)) { - assert(!undo.isEmpty()); - - if (undo.top().height === -1) { - let coins = new Coins(); - coins.hash = prev; - coins.coinbase = false; - view.add(coins); - } - } - + const input = tx.inputs[j]; undo.apply(view, input.prevout); } } @@ -1062,15 +1032,13 @@ ChainDB.prototype.getBlockView = async function getBlockView(block) { */ ChainDB.prototype.getMeta = async function getMeta(hash) { - let data; - if (!this.options.indexTX) - return; + return null; - data = await this.db.get(layout.t(hash)); + const data = await this.db.get(layout.t(hash)); if (!data) - return; + return null; return TXMeta.fromRaw(data); }; @@ -1083,9 +1051,11 @@ ChainDB.prototype.getMeta = async function getMeta(hash) { */ ChainDB.prototype.getTX = async function getTX(hash) { - let meta = await this.getMeta(hash); + const meta = await this.getMeta(hash); + if (!meta) - return; + return null; + return meta.tx; }; @@ -1094,11 +1064,11 @@ ChainDB.prototype.getTX = async function getTX(hash) { * @returns {Promise} - Returns Boolean. */ -ChainDB.prototype.hasTX = function hasTX(hash) { +ChainDB.prototype.hasTX = async function hasTX(hash) { if (!this.options.indexTX) - return Promise.resolve(); + return false; - return this.db.has(layout.t(hash)); + return await this.db.has(layout.t(hash)); }; /** @@ -1109,25 +1079,25 @@ ChainDB.prototype.hasTX = function hasTX(hash) { */ ChainDB.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) { - let coins = []; - if (!this.options.indexAddress) - return coins; + return []; if (!Array.isArray(addrs)) addrs = [addrs]; - for (let addr of addrs) { - let hash = Address.getHash(addr); + const coins = []; + + for (const addr of addrs) { + const hash = Address.getHash(addr); - let keys = await this.db.keys({ + const keys = await this.db.keys({ gte: layout.C(hash, encoding.ZERO_HASH, 0), lte: layout.C(hash, encoding.MAX_HASH, 0xffffffff), parse: layout.Cc }); - for (let [hash, index] of keys) { - let coin = await this.getCoin(hash, index); + for (const [hash, index] of keys) { + const coin = await this.getCoin(hash, index); assert(coin); coins.push(coin); } @@ -1144,19 +1114,19 @@ ChainDB.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) { */ ChainDB.prototype.getHashesByAddress = async function getHashesByAddress(addrs) { - let hashes = {}; - if (!this.options.indexTX || !this.options.indexAddress) return []; - for (let addr of addrs) { - let hash = Address.getHash(addr); + const hashes = Object.create(null); + + for (const addr of addrs) { + const hash = Address.getHash(addr); await this.db.keys({ gte: layout.T(hash, encoding.ZERO_HASH), lte: layout.T(hash, encoding.MAX_HASH), parse: (key) => { - let hash = layout.Tt(key); + const hash = layout.Tt(key); hashes[hash] = true; } }); @@ -1173,10 +1143,10 @@ ChainDB.prototype.getHashesByAddress = async function getHashesByAddress(addrs) */ ChainDB.prototype.getTXByAddress = async function getTXByAddress(addrs) { - let mtxs = await this.getMetaByAddress(addrs); - let out = []; + const mtxs = await this.getMetaByAddress(addrs); + const out = []; - for (let mtx of mtxs) + for (const mtx of mtxs) out.push(mtx.tx); return out; @@ -1189,20 +1159,18 @@ ChainDB.prototype.getTXByAddress = async function getTXByAddress(addrs) { * @returns {Promise} - Returns {@link TXMeta}[]. */ -ChainDB.prototype.getMetaByAddress = async function getTXByAddress(addrs) { - let txs = []; - let hashes; - +ChainDB.prototype.getMetaByAddress = async function getMetaByAddress(addrs) { if (!this.options.indexTX || !this.options.indexAddress) - return txs; + return []; if (!Array.isArray(addrs)) addrs = [addrs]; - hashes = await this.getHashesByAddress(addrs); + const hashes = await this.getHashesByAddress(addrs); + const txs = []; - for (let hash of hashes) { - let tx = await this.getMeta(hash); + for (const hash of hashes) { + const tx = await this.getMeta(hash); assert(tx); txs.push(tx); } @@ -1220,9 +1188,6 @@ ChainDB.prototype.getMetaByAddress = async function getTXByAddress(addrs) { */ ChainDB.prototype.scan = async function scan(start, filter, iter) { - let total = 0; - let entry; - if (start == null) start = this.network.genesis.hash; @@ -1231,17 +1196,19 @@ ChainDB.prototype.scan = async function scan(start, filter, iter) { else this.logger.info('Scanning from block %s.', util.revHex(start)); - entry = await this.getEntry(start); + let entry = await this.getEntry(start); if (!entry) return; - if (!(await entry.isMainChain())) + if (!await entry.isMainChain()) throw new Error('Cannot rescan an alternate chain.'); + let total = 0; + while (entry) { - let block = await this.getBlock(entry.hash); - let txs = []; + const block = await this.getBlock(entry.hash); + const txs = []; total++; @@ -1258,18 +1225,18 @@ ChainDB.prototype.scan = async function scan(start, filter, iter) { entry.rhash(), entry.height); for (let i = 0; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; let found = false; for (let j = 0; j < tx.outputs.length; j++) { - let output = tx.outputs[j]; - let hash = output.getHash(); + const output = tx.outputs[j]; + const hash = output.getHash(); if (!hash) continue; if (filter.test(hash)) { - let prevout = Outpoint.fromTX(tx, j); + const prevout = Outpoint.fromTX(tx, j); filter.add(prevout.toRaw()); found = true; } @@ -1283,7 +1250,7 @@ ChainDB.prototype.scan = async function scan(start, filter, iter) { if (i === 0) continue; - for (let {prevout} of tx.inputs) { + for (const {prevout} of tx.inputs) { if (filter.test(prevout.toRaw())) { txs.push(tx); break; @@ -1332,8 +1299,8 @@ ChainDB.prototype.save = async function save(entry, block, view) { * @returns {Promise} */ -ChainDB.prototype._save = async function save(entry, block, view) { - let hash = block.hash(); +ChainDB.prototype._save = async function _save(entry, block, view) { + const hash = block.hash(); // Hash->height index. this.put(layout.h(hash), U32(entry.height)); @@ -1400,8 +1367,8 @@ ChainDB.prototype.reconnect = async function reconnect(entry, block, view) { * @returns {Promise} */ -ChainDB.prototype._reconnect = async function reconnect(entry, block, view) { - let hash = block.hash(); +ChainDB.prototype._reconnect = async function _reconnect(entry, block, view) { + const hash = block.hash(); assert(!entry.isGenesis()); @@ -1434,10 +1401,9 @@ ChainDB.prototype._reconnect = async function reconnect(entry, block, view) { */ ChainDB.prototype.disconnect = async function disconnect(entry, block) { - let view; - this.start(); + let view; try { view = await this._disconnect(entry, block); } catch (e) { @@ -1459,9 +1425,7 @@ ChainDB.prototype.disconnect = async function disconnect(entry, block) { * @returns {Promise} - Returns {@link CoinView}. */ -ChainDB.prototype._disconnect = async function disconnect(entry, block) { - let view; - +ChainDB.prototype._disconnect = async function _disconnect(entry, block) { // Remove hash->next-block index. this.del(layout.n(entry.prevBlock)); @@ -1473,7 +1437,7 @@ ChainDB.prototype._disconnect = async function disconnect(entry, block) { this.saveUpdates(); // Disconnect inputs. - view = await this.disconnectBlock(entry, block); + const view = await this.disconnectBlock(entry, block); // Revert chain state to previous tip. this.put(layout.R, this.pending.commit(entry.prevBlock)); @@ -1487,15 +1451,15 @@ ChainDB.prototype._disconnect = async function disconnect(entry, block) { */ ChainDB.prototype.saveUpdates = function saveUpdates() { - let updates = this.stateCache.updates; + const updates = this.stateCache.updates; if (updates.length === 0) return; this.logger.info('Saving %d state cache updates.', updates.length); - for (let update of updates) { - let {bit, hash} = update; + for (const update of updates) { + const {bit, hash} = update; this.put(layout.v(bit, hash), update.toRaw()); } }; @@ -1509,13 +1473,12 @@ ChainDB.prototype.saveUpdates = function saveUpdates() { */ ChainDB.prototype.reset = async function reset(block) { - let entry = await this.getEntry(block); - let tip; + const entry = await this.getEntry(block); if (!entry) throw new Error('Block not found.'); - if (!(await entry.isMainChain())) + if (!await entry.isMainChain()) throw new Error('Cannot reset on alternate chain.'); if (this.options.prune) @@ -1527,7 +1490,7 @@ ChainDB.prototype.reset = async function reset(block) { // the chain. await this.removeChains(); - tip = await this.getTip(); + let tip = await this.getTip(); assert(tip); this.logger.debug('Resetting main chain to: %s', entry.rhash()); @@ -1586,14 +1549,14 @@ ChainDB.prototype.reset = async function reset(block) { */ ChainDB.prototype.removeChains = async function removeChains() { - let tips = await this.getTips(); + const tips = await this.getTips(); // Note that this has to be // one giant atomic write! this.start(); try { - for (let tip of tips) + for (const tip of tips) await this._removeChain(tip); } catch (e) { this.drop(); @@ -1611,7 +1574,7 @@ ChainDB.prototype.removeChains = async function removeChains() { * @returns {Promise} */ -ChainDB.prototype._removeChain = async function removeChain(hash) { +ChainDB.prototype._removeChain = async function _removeChain(hash) { let tip = await this.getEntry(hash); if (!tip) @@ -1651,7 +1614,7 @@ ChainDB.prototype._removeChain = async function removeChain(hash) { */ ChainDB.prototype.saveBlock = async function saveBlock(entry, block, view) { - let hash = block.hash(); + const hash = block.hash(); if (this.options.spv) return; @@ -1675,12 +1638,10 @@ ChainDB.prototype.saveBlock = async function saveBlock(entry, block, view) { */ ChainDB.prototype.removeBlock = async function removeBlock(entry) { - let block; - if (this.options.spv) - return; + return new CoinView(); - block = await this.getBlock(entry.hash); + const block = await this.getBlock(entry.hash); if (!block) throw new Error('Block not found.'); @@ -1697,14 +1658,18 @@ ChainDB.prototype.removeBlock = async function removeBlock(entry) { */ ChainDB.prototype.saveView = function saveView(view) { - for (let coins of view.map.values()) { - if (coins.isEmpty()) { - this.del(layout.c(coins.hash)); - this.coinCache.unpush(coins.hash); - } else { - let raw = coins.toRaw(); - this.put(layout.c(coins.hash), raw); - this.coinCache.push(coins.hash, raw); + for (const [hash, coins] of view.map) { + for (const [index, coin] of coins.outputs) { + if (coin.spent) { + this.del(layout.c(hash, index)); + this.coinCache.unpush(hash + index); + continue; + } + + const raw = coin.toRaw(); + + this.put(layout.c(hash, index), raw); + this.coinCache.push(hash + index, raw); } } }; @@ -1719,11 +1684,11 @@ ChainDB.prototype.saveView = function saveView(view) { */ ChainDB.prototype.connectBlock = async function connectBlock(entry, block, view) { - let hash = block.hash(); - if (this.options.spv) return; + const hash = block.hash(); + this.pending.connect(block); // Genesis block's coinbase is unspendable. @@ -1732,14 +1697,14 @@ ChainDB.prototype.connectBlock = async function connectBlock(entry, block, view) // Update chain state value. for (let i = 0; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; if (i > 0) { - for (let input of tx.inputs) - this.pending.spend(view.getOutput(input)); + for (const {prevout} of tx.inputs) + this.pending.spend(view.getOutput(prevout)); } - for (let output of tx.outputs) { + for (const output of tx.outputs) { if (output.script.isUnspendable()) continue; @@ -1770,28 +1735,25 @@ ChainDB.prototype.connectBlock = async function connectBlock(entry, block, view) */ ChainDB.prototype.disconnectBlock = async function disconnectBlock(entry, block) { - let view = new CoinView(); - let hash = block.hash(); - let undo; + const view = new CoinView(); if (this.options.spv) return view; - undo = await this.getUndoCoins(hash); + const hash = block.hash(); + const undo = await this.getUndoCoins(hash); this.pending.disconnect(block); // Disconnect all transactions. for (let i = block.txs.length - 1; i >= 0; i--) { - let tx = block.txs[i]; + const tx = block.txs[i]; if (i > 0) { - await view.ensureInputs(this, tx); - for (let j = tx.inputs.length - 1; j >= 0; j--) { - let input = tx.inputs[j]; - undo.apply(view, input.prevout); - this.pending.add(view.getOutput(input)); + const {prevout} = tx.inputs[j]; + undo.apply(view, prevout); + this.pending.add(view.getOutput(prevout)); } } @@ -1799,7 +1761,7 @@ ChainDB.prototype.disconnectBlock = async function disconnectBlock(entry, block) view.removeTX(tx, entry.height); for (let j = tx.outputs.length - 1; j >= 0; j--) { - let output = tx.outputs[j]; + const output = tx.outputs[j]; if (output.script.isUnspendable()) continue; @@ -1833,20 +1795,18 @@ ChainDB.prototype.disconnectBlock = async function disconnectBlock(entry, block) */ ChainDB.prototype.pruneBlock = async function pruneBlock(entry) { - let height, hash; - if (this.options.spv) return; if (!this.options.prune) return; - height = entry.height - this.network.block.keepBlocks; + const height = entry.height - this.network.block.keepBlocks; if (height <= this.network.block.pruneAfterHeight) return; - hash = await this.getHash(height); + const hash = await this.getHash(height); if (!hash) return; @@ -1861,7 +1821,7 @@ ChainDB.prototype.pruneBlock = async function pruneBlock(entry) { */ ChainDB.prototype.saveFlags = function saveFlags() { - let flags = ChainFlags.fromOptions(this.options); + const flags = ChainFlags.fromOptions(this.options); return this.db.put(layout.O, flags.toRaw()); }; @@ -1875,16 +1835,16 @@ ChainDB.prototype.saveFlags = function saveFlags() { */ ChainDB.prototype.indexTX = function indexTX(tx, view, entry, index) { - let hash = tx.hash(); + const hash = tx.hash(); if (this.options.indexTX) { - let meta = TXMeta.fromTX(tx, entry, index); + const meta = TXMeta.fromTX(tx, entry, index); this.put(layout.t(hash), meta.toRaw()); if (this.options.indexAddress) { - let hashes = tx.getHashes(view); - for (let addr of hashes) + const hashes = tx.getHashes(view); + for (const addr of hashes) this.put(layout.T(addr, hash), null); } } @@ -1893,9 +1853,8 @@ ChainDB.prototype.indexTX = function indexTX(tx, view, entry, index) { return; if (!tx.isCoinbase()) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let addr = view.getOutput(input).getHash(); + for (const {prevout} of tx.inputs) { + const addr = view.getOutput(prevout).getHash(); if (!addr) continue; @@ -1905,8 +1864,8 @@ ChainDB.prototype.indexTX = function indexTX(tx, view, entry, index) { } for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let addr = output.getHash(); + const output = tx.outputs[i]; + const addr = output.getHash(); if (!addr) continue; @@ -1923,13 +1882,13 @@ ChainDB.prototype.indexTX = function indexTX(tx, view, entry, index) { */ ChainDB.prototype.unindexTX = function unindexTX(tx, view) { - let hash = tx.hash(); + const hash = tx.hash(); if (this.options.indexTX) { this.del(layout.t(hash)); if (this.options.indexAddress) { - let hashes = tx.getHashes(view); - for (let addr of hashes) + const hashes = tx.getHashes(view); + for (const addr of hashes) this.del(layout.T(addr, hash)); } } @@ -1938,9 +1897,8 @@ ChainDB.prototype.unindexTX = function unindexTX(tx, view) { return; if (!tx.isCoinbase()) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let addr = view.getOutput(input).getHash(); + for (const {prevout} of tx.inputs) { + const addr = view.getOutput(prevout).getHash(); if (!addr) continue; @@ -1950,8 +1908,8 @@ ChainDB.prototype.unindexTX = function unindexTX(tx, view) { } for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let addr = output.getHash(); + const output = tx.outputs[i]; + const addr = output.getHash(); if (!addr) continue; @@ -2024,7 +1982,7 @@ ChainFlags.fromOptions = function fromOptions(data) { }; ChainFlags.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(12); + const bw = new StaticWriter(12); let flags = 0; if (this.spv) @@ -2056,12 +2014,11 @@ ChainFlags.prototype.toRaw = function toRaw() { }; ChainFlags.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let flags; + const br = new BufferReader(data); this.network = Network.fromMagic(br.readU32()); - flags = br.readU32(); + const flags = br.readU32(); this.spv = (flags & 1) !== 0; this.witness = (flags & 2) !== 0; @@ -2101,7 +2058,7 @@ ChainState.prototype.rhash = function rhash() { }; ChainState.prototype.clone = function clone() { - let state = new ChainState(); + const state = new ChainState(); state.tip = this.tip; state.tx = this.tx; state.coin = this.coin; @@ -2113,7 +2070,7 @@ ChainState.prototype.connect = function connect(block) { this.tx += block.txs.length; }; -ChainState.prototype.disconnect = function connect(block) { +ChainState.prototype.disconnect = function disconnect(block) { this.tx -= block.txs.length; }; @@ -2136,7 +2093,7 @@ ChainState.prototype.commit = function commit(hash) { }; ChainState.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(56); + const bw = new StaticWriter(56); bw.writeHash(this.tip); bw.writeU64(this.tx); bw.writeU64(this.coin); @@ -2145,8 +2102,8 @@ ChainState.prototype.toRaw = function toRaw() { }; ChainState.fromRaw = function fromRaw(data) { - let state = new ChainState(); - let br = new BufferReader(data); + const state = new ChainState(); + const br = new BufferReader(data); state.tip = br.readHash(); state.tx = br.readU53(); state.coin = br.readU53(); @@ -2171,14 +2128,14 @@ StateCache.prototype._init = function _init() { for (let i = 0; i < 32; i++) this.bits.push(null); - for (let {bit} of this.network.deploys) { + for (const {bit} of this.network.deploys) { assert(!this.bits[bit]); this.bits[bit] = new Map(); } }; StateCache.prototype.set = function set(bit, entry, state) { - let cache = this.bits[bit]; + const cache = this.bits[bit]; assert(cache); @@ -2189,12 +2146,11 @@ StateCache.prototype.set = function set(bit, entry, state) { }; StateCache.prototype.get = function get(bit, entry) { - let cache = this.bits[bit]; - let state; + const cache = this.bits[bit]; assert(cache); - state = cache.get(entry.hash); + const state = cache.get(entry.hash); if (state == null) return -1; @@ -2207,8 +2163,8 @@ StateCache.prototype.commit = function commit() { }; StateCache.prototype.drop = function drop() { - for (let {bit, hash} of this.updates) { - let cache = this.bits[bit]; + for (const {bit, hash} of this.updates) { + const cache = this.bits[bit]; assert(cache); cache.delete(hash); } @@ -2217,7 +2173,7 @@ StateCache.prototype.drop = function drop() { }; StateCache.prototype.insert = function insert(bit, hash, state) { - let cache = this.bits[bit]; + const cache = this.bits[bit]; assert(cache); cache.set(hash, state); }; diff --git a/lib/blockchain/chainentry.js b/lib/blockchain/chainentry.js index e4782082e..b18d0e3fb 100644 --- a/lib/blockchain/chainentry.js +++ b/lib/blockchain/chainentry.js @@ -17,6 +17,7 @@ const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); const Headers = require('../primitives/headers'); const InvItem = require('../primitives/invitem'); +const ZERO = new BN(0); /** * Represents an entry in the chain. Unlike @@ -35,7 +36,7 @@ const InvItem = require('../primitives/invitem'); * This value will never be negative. * @property {Hash} prevBlock * @property {Hash} merkleRoot - * @property {Number} ts + * @property {Number} time * @property {Number} bits * @property {Number} nonce * @property {Number} height @@ -52,11 +53,11 @@ function ChainEntry(chain, options, prev) { this.version = 1; this.prevBlock = encoding.NULL_HASH; this.merkleRoot = encoding.NULL_HASH; - this.ts = 0; + this.time = 0; this.bits = 0; this.nonce = 0; - this.height = -1; - this.chainwork = null; + this.height = 0; + this.chainwork = ZERO; if (options) this.fromOptions(options, prev); @@ -87,23 +88,24 @@ ChainEntry.MEDIAN_TIMESPAN = 11; ChainEntry.prototype.fromOptions = function fromOptions(options, prev) { assert(options, 'Block data is required.'); assert(typeof options.hash === 'string'); - assert(util.isNumber(options.version)); + assert(util.isU32(options.version)); assert(typeof options.prevBlock === 'string'); assert(typeof options.merkleRoot === 'string'); - assert(util.isNumber(options.ts)); - assert(util.isNumber(options.bits)); - assert(util.isNumber(options.nonce)); + assert(util.isU32(options.time)); + assert(util.isU32(options.bits)); + assert(util.isU32(options.nonce)); + assert(util.isU32(options.height)); assert(!options.chainwork || BN.isBN(options.chainwork)); this.hash = options.hash; this.version = options.version; this.prevBlock = options.prevBlock; this.merkleRoot = options.merkleRoot; - this.ts = options.ts; + this.time = options.time; this.bits = options.bits; this.nonce = options.nonce; this.height = options.height; - this.chainwork = options.chainwork; + this.chainwork = options.chainwork || ZERO; if (!this.chainwork) this.chainwork = this.getChainwork(prev); @@ -129,9 +131,11 @@ ChainEntry.fromOptions = function fromOptions(chain, options, prev) { */ ChainEntry.prototype.getProof = function getProof() { - let target = consensus.fromCompact(this.bits); + const target = consensus.fromCompact(this.bits); + if (target.isNeg() || target.cmpn(0) === 0) return new BN(0); + return ChainEntry.MAX_CHAINWORK.div(target.iaddn(1)); }; @@ -142,7 +146,7 @@ ChainEntry.prototype.getProof = function getProof() { */ ChainEntry.prototype.getChainwork = function getChainwork(prev) { - let proof = this.getProof(); + const proof = this.getProof(); if (!prev) return proof; @@ -166,14 +170,12 @@ ChainEntry.prototype.isGenesis = function isGenesis() { */ ChainEntry.prototype.isMainChain = async function isMainChain() { - let entry; - if (this.hash === this.chain.tip.hash || this.hash === this.chain.network.genesis.hash) { return true; } - entry = this.chain.db.getCache(this.height); + const entry = this.chain.db.getCache(this.height); if (entry) { if (entry.hash === this.hash) @@ -195,10 +197,8 @@ ChainEntry.prototype.isMainChain = async function isMainChain() { */ ChainEntry.prototype.getAncestor = async function getAncestor(height) { - let entry = this; - if (height < 0) - return; + return null; assert(height >= 0); assert(height <= this.height); @@ -206,6 +206,7 @@ ChainEntry.prototype.getAncestor = async function getAncestor(height) { if (await this.isMainChain()) return await this.chain.db.getEntry(height); + let entry = this; while (entry.height !== height) { entry = await entry.getPrevious(); assert(entry); @@ -239,9 +240,11 @@ ChainEntry.prototype.getPrevCache = function getPrevCache() { */ ChainEntry.prototype.getNext = async function getNext() { - let hash = await this.chain.db.getNextHash(this.hash); + const hash = await this.chain.db.getNextHash(this.hash); + if (!hash) - return; + return null; + return await this.chain.db.getEntry(hash); }; @@ -252,14 +255,14 @@ ChainEntry.prototype.getNext = async function getNext() { */ ChainEntry.prototype.getNextEntry = async function getNextEntry() { - let entry = await this.chain.db.getEntry(this.height + 1); + const entry = await this.chain.db.getEntry(this.height + 1); if (!entry) - return; + return null; // Not on main chain. if (entry.prevBlock !== this.hash) - return; + return null; return entry; }; @@ -267,29 +270,27 @@ ChainEntry.prototype.getNextEntry = async function getNextEntry() { /** * Calculate median time past. * @method - * @param {Number?} ts + * @param {Number?} time * @returns {Promise} - Returns Number. */ -ChainEntry.prototype.getMedianTime = async function getMedianTime(ts) { +ChainEntry.prototype.getMedianTime = async function getMedianTime(time) { let timespan = ChainEntry.MEDIAN_TIMESPAN; - let entry = this; - let median = []; + const median = []; // In case we ever want to check // the MTP of the _current_ block // (necessary for BIP148). - if (ts != null) { - median.push(ts); + if (time != null) { + median.push(time); timespan -= 1; } + let entry = this; for (let i = 0; i < timespan && entry; i++) { - let cache; - - median.push(entry.ts); + median.push(entry.time); - cache = entry.getPrevCache(); + const cache = entry.getPrevCache(); if (cache) { entry = cache; @@ -311,7 +312,7 @@ ChainEntry.prototype.getMedianTime = async function getMedianTime(ts) { */ ChainEntry.prototype.isHistorical = function isHistorical() { - if (this.chain.checkpoints) { + if (this.chain.options.checkpoints) { if (this.height + 1 <= this.chain.network.lastCheckpoint) return true; } @@ -324,8 +325,8 @@ ChainEntry.prototype.isHistorical = function isHistorical() { */ ChainEntry.prototype.hasUnknown = function hasUnknown() { - let bits = this.version & consensus.VERSION_TOP_MASK; - let topBits = consensus.VERSION_TOP_BITS; + const bits = this.version & consensus.VERSION_TOP_MASK; + const topBits = consensus.VERSION_TOP_BITS; if ((bits >>> 0) !== topBits) return false; @@ -364,7 +365,7 @@ ChainEntry.prototype.fromBlock = function fromBlock(block, prev) { this.version = block.version; this.prevBlock = block.prevBlock; this.merkleRoot = block.merkleRoot; - this.ts = block.ts; + this.time = block.time; this.bits = block.bits; this.nonce = block.nonce; this.height = prev ? prev.height + 1: 0; @@ -390,16 +391,16 @@ ChainEntry.fromBlock = function fromBlock(chain, block, prev) { */ ChainEntry.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(116); + const bw = new StaticWriter(116); bw.writeU32(this.version); bw.writeHash(this.prevBlock); bw.writeHash(this.merkleRoot); - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU32(this.bits); bw.writeU32(this.nonce); bw.writeU32(this.height); - bw.writeBytes(this.chainwork.toBuffer('le', 32)); + bw.writeBytes(this.chainwork.toArrayLike(Buffer, 'le', 32)); return bw.render(); }; @@ -411,8 +412,8 @@ ChainEntry.prototype.toRaw = function toRaw() { */ ChainEntry.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let hash = digest.hash256(br.readBytes(80)); + const br = new BufferReader(data, true); + const hash = digest.hash256(br.readBytes(80)); br.seek(-80); @@ -420,7 +421,7 @@ ChainEntry.prototype.fromRaw = function fromRaw(data) { this.version = br.readU32(); this.prevBlock = br.readHash('hex'); this.merkleRoot = br.readHash('hex'); - this.ts = br.readU32(); + this.time = br.readU32(); this.bits = br.readU32(); this.nonce = br.readU32(); this.height = br.readU32(); @@ -452,7 +453,7 @@ ChainEntry.prototype.toJSON = function toJSON() { version: this.version, prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce, height: this.height, @@ -469,19 +470,19 @@ ChainEntry.prototype.toJSON = function toJSON() { ChainEntry.prototype.fromJSON = function fromJSON(json) { assert(json, 'Block data is required.'); assert(typeof json.hash === 'string'); - assert(util.isUInt32(json.version)); + assert(util.isU32(json.version)); assert(typeof json.prevBlock === 'string'); assert(typeof json.merkleRoot === 'string'); - assert(util.isUInt32(json.ts)); - assert(util.isUInt32(json.bits)); - assert(util.isUInt32(json.nonce)); + assert(util.isU32(json.time)); + assert(util.isU32(json.bits)); + assert(util.isU32(json.nonce)); assert(typeof json.chainwork === 'string'); this.hash = util.revHex(json.hash); this.version = json.version; this.prevBlock = util.revHex(json.prevBlock); this.merkleRoot = util.revHex(json.merkleRoot); - this.ts = json.ts; + this.time = json.time; this.bits = json.bits; this.nonce = json.nonce; this.height = json.height; @@ -525,7 +526,7 @@ ChainEntry.prototype.toInv = function toInv() { */ ChainEntry.prototype.inspect = function inspect() { - let json = this.toJSON(); + const json = this.toJSON(); json.version = util.hex32(json.version); return json; }; diff --git a/lib/blockchain/layout-browser.js b/lib/blockchain/layout-browser.js index fc82b13c2..701a627b8 100644 --- a/lib/blockchain/layout-browser.js +++ b/lib/blockchain/layout-browser.js @@ -6,6 +6,7 @@ 'use strict'; +const assert = require('assert'); const util = require('../utils/util'); const pad8 = util.pad8; const pad32 = util.pad32; @@ -36,8 +37,8 @@ const layout = { t: function t(hash) { return 't' + hex(hash); }, - c: function c(hash) { - return 'c' + hex(hash); + c: function c(hash, index) { + return 'c' + hex(hash) + pad32(index); }, u: function u(hash) { return 'u' + hex(hash); @@ -46,44 +47,57 @@ const layout = { return 'v' + pad8(bit) + hex(hash); }, vv: function vv(key) { - return [+key.slice(1, 4), key.slice(4, 36)]; + assert(typeof key === 'string'); + assert(key.length === 36); + return [parseInt(key.slice(1, 4), 10), key.slice(4, 36)]; }, - T: function T(address, hash) { - address = hex(address); + T: function T(addr, hash) { + addr = hex(addr); - if (address.length === 64) - return 'W' + address + hex(hash); + if (addr.length === 64) + return 'W' + addr + hex(hash); - return 'T' + address + hex(hash); + assert(addr.length === 40); + return 'T' + addr + hex(hash); }, - C: function C(address, hash, index) { - address = hex(address); + C: function C(addr, hash, index) { + addr = hex(addr); - if (address.length === 64) - return 'X' + address + hex(hash) + pad32(index); + if (addr.length === 64) + return 'X' + addr + hex(hash) + pad32(index); - return 'C' + address + hex(hash) + pad32(index); + assert(addr.length === 40); + return 'C' + addr + hex(hash) + pad32(index); }, - pp: function aa(key) { + pp: function pp(key) { + assert(typeof key === 'string'); + assert(key.length === 65); return key.slice(1, 65); }, Cc: function Cc(key) { - let hash, index; + assert(typeof key === 'string'); + let hash, index; if (key.length === 139) { hash = key.slice(65, 129); - index = +key.slice(129); - } else { + index = parseInt(key.slice(129), 10); + } else if (key.length === 115) { hash = key.slice(41, 105); - index = +key.slice(105); + index = parseInt(key.slice(105), 10); + } else { + assert(false); } return [hash, index]; }, Tt: function Tt(key) { - return key.length === 129 - ? key.slice(64) - : key.slice(41); + assert(typeof key === 'string'); + + if (key.length === 129) + return key.slice(64); + + assert(key.length === 105); + return key.slice(41); } }; @@ -92,8 +106,9 @@ const layout = { */ function hex(hash) { - if (typeof hash !== 'string') + if (Buffer.isBuffer(hash)) hash = hash.toString('hex'); + assert(typeof hash === 'string'); return hash; } diff --git a/lib/blockchain/layout.js b/lib/blockchain/layout.js index 162ffaee3..5a232962e 100644 --- a/lib/blockchain/layout.js +++ b/lib/blockchain/layout.js @@ -6,6 +6,8 @@ 'use strict'; +const assert = require('assert'); + /* * Database Layout: * R -> tip hash @@ -53,86 +55,104 @@ const layout = { t: function t(hash) { return pair(0x74, hash); }, - c: function c(hash) { - return pair(0x63, hash); + c: function c(hash, index) { + return bpair(0x63, hash, index); }, u: function u(hash) { return pair(0x75, hash); }, v: function v(bit, hash) { - let key = Buffer.allocUnsafe(1 + 1 + 32); + const key = Buffer.allocUnsafe(1 + 1 + 32); + assert(typeof bit === 'number'); key[0] = 0x76; key[1] = bit; write(key, hash, 2); return key; }, vv: function vv(key) { + assert(Buffer.isBuffer(key)); + assert(key.length === 34); return [key[1], key.toString('hex', 2, 34)]; }, - T: function T(address, hash) { - let len = address.length; - let key; + T: function T(addr, hash) { + let len = addr.length; - if (typeof address === 'string') + if (typeof addr === 'string') len /= 2; + let key; if (len === 32) { key = Buffer.allocUnsafe(65); key[0] = 0xab; // W + T - write(key, address, 1); + write(key, addr, 1); write(key, hash, 33); - } else { + } else if (len === 20) { key = Buffer.allocUnsafe(53); key[0] = 0x54; // T - write(key, address, 1); + write(key, addr, 1); write(key, hash, 21); + } else { + assert(false); } return key; }, - C: function C(address, hash, index) { - let len = address.length; - let key; + C: function C(addr, hash, index) { + let len = addr.length; - if (typeof address === 'string') + assert(typeof index === 'number'); + + if (typeof addr === 'string') len /= 2; + let key; if (len === 32) { key = Buffer.allocUnsafe(69); key[0] = 0x9a; // W + C - write(key, address, 1); + write(key, addr, 1); write(key, hash, 33); key.writeUInt32BE(index, 65, true); - } else { + } else if (len === 20) { key = Buffer.allocUnsafe(57); key[0] = 0x43; // C - write(key, address, 1); + write(key, addr, 1); write(key, hash, 21); key.writeUInt32BE(index, 53, true); + } else { + assert(false); } return key; }, - pp: function aa(key) { + pp: function pp(key) { + assert(Buffer.isBuffer(key)); + assert(key.length === 33); return key.toString('hex', 1, 33); }, Cc: function Cc(key) { - let hash, index; + assert(Buffer.isBuffer(key)); + let hash, index; if (key.length === 69) { hash = key.toString('hex', 33, 65); index = key.readUInt32BE(65, 0); - } else { + } else if (key.length === 57) { hash = key.toString('hex', 21, 53); index = key.readUInt32BE(53, 0); + } else { + assert(false); } return [hash, index]; }, Tt: function Tt(key) { - return key.length === 65 - ? key.toString('hex', 33, 65) - : key.toString('hex', 21, 53); + assert(Buffer.isBuffer(key)); + + if (key.length === 65) + return key.toString('hex', 33, 65); + + assert(key.length === 53); + return key.toString('hex', 21, 53); } }; @@ -143,23 +163,34 @@ const layout = { function write(data, str, off) { if (Buffer.isBuffer(str)) return str.copy(data, off); - data.write(str, off, 'hex'); + assert(typeof str === 'string'); + return data.write(str, off, 'hex'); } function pair(prefix, hash) { - let key = Buffer.allocUnsafe(33); + const key = Buffer.allocUnsafe(33); key[0] = prefix; write(key, hash, 1); return key; } function ipair(prefix, num) { - let key = Buffer.allocUnsafe(5); + const key = Buffer.allocUnsafe(5); + assert(typeof num === 'number'); key[0] = prefix; key.writeUInt32BE(num, 1, true); return key; } +function bpair(prefix, hash, index) { + const key = Buffer.allocUnsafe(37); + assert(typeof index === 'number'); + key[0] = prefix; + write(key, hash, 1); + key.writeUInt32BE(index, 33, true); + return key; +} + /* * Expose */ diff --git a/lib/btc/amount.js b/lib/btc/amount.js index b92669020..7c9bb45d0 100644 --- a/lib/btc/amount.js +++ b/lib/btc/amount.js @@ -15,18 +15,17 @@ const util = require('../utils/util'); * @constructor * @param {(String|Number)?} value * @param {String?} unit - * @param {Boolean?} num * @property {Amount} value */ -function Amount(value, unit, num) { +function Amount(value, unit) { if (!(this instanceof Amount)) - return new Amount(value, unit, num); + return new Amount(value, unit); this.value = 0; if (value != null) - this.fromOptions(value, unit, num); + this.fromOptions(value, unit); } /** @@ -34,13 +33,12 @@ function Amount(value, unit, num) { * @private * @param {(String|Number)?} value * @param {String?} unit - * @param {Boolean?} num * @returns {Amount} */ -Amount.prototype.fromOptions = function fromOptions(value, unit, num) { +Amount.prototype.fromOptions = function fromOptions(value, unit) { if (typeof unit === 'string') - return this.from(unit, value, num); + return this.from(unit, value); if (typeof value === 'number') return this.fromValue(value); @@ -77,7 +75,7 @@ Amount.prototype.toSatoshis = function toSatoshis(num) { */ Amount.prototype.toBits = function toBits(num) { - return Amount.serialize(this.value, 2, num); + return Amount.encode(this.value, 2, num); }; /** @@ -87,7 +85,7 @@ Amount.prototype.toBits = function toBits(num) { */ Amount.prototype.toMBTC = function toMBTC(num) { - return Amount.serialize(this.value, 5, num); + return Amount.encode(this.value, 5, num); }; /** @@ -97,7 +95,7 @@ Amount.prototype.toMBTC = function toMBTC(num) { */ Amount.prototype.toBTC = function toBTC(num) { - return Amount.serialize(this.value, 8, num); + return Amount.encode(this.value, 8, num); }; /** @@ -140,7 +138,7 @@ Amount.prototype.toString = function toString() { */ Amount.prototype.fromValue = function fromValue(value) { - assert(util.isInt53(value), 'Value must be an int64.'); + assert(util.isI64(value), 'Value must be an int64.'); this.value = value; return this; }; @@ -149,12 +147,11 @@ Amount.prototype.fromValue = function fromValue(value) { * Inject properties from satoshis. * @private * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.prototype.fromSatoshis = function fromSatoshis(value, num) { - this.value = Amount.parse(value, 0, num); +Amount.prototype.fromSatoshis = function fromSatoshis(value) { + this.value = Amount.decode(value, 0); return this; }; @@ -162,12 +159,11 @@ Amount.prototype.fromSatoshis = function fromSatoshis(value, num) { * Inject properties from bits. * @private * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.prototype.fromBits = function fromBits(value, num) { - this.value = Amount.parse(value, 2, num); +Amount.prototype.fromBits = function fromBits(value) { + this.value = Amount.decode(value, 2); return this; }; @@ -175,12 +171,11 @@ Amount.prototype.fromBits = function fromBits(value, num) { * Inject properties from mbtc. * @private * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.prototype.fromMBTC = function fromMBTC(value, num) { - this.value = Amount.parse(value, 5, num); +Amount.prototype.fromMBTC = function fromMBTC(value) { + this.value = Amount.decode(value, 5); return this; }; @@ -188,12 +183,11 @@ Amount.prototype.fromMBTC = function fromMBTC(value, num) { * Inject properties from btc. * @private * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.prototype.fromBTC = function fromBTC(value, num) { - this.value = Amount.parse(value, 8, num); +Amount.prototype.fromBTC = function fromBTC(value) { + this.value = Amount.decode(value, 8); return this; }; @@ -202,21 +196,20 @@ Amount.prototype.fromBTC = function fromBTC(value, num) { * @private * @param {String} unit * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.prototype.from = function from(unit, value, num) { +Amount.prototype.from = function from(unit, value) { switch (unit) { case 'sat': - return this.fromSatoshis(value, num); + return this.fromSatoshis(value); case 'ubtc': case 'bits': - return this.fromBits(value, num); + return this.fromBits(value); case 'mbtc': - return this.fromMBTC(value, num); + return this.fromMBTC(value); case 'btc': - return this.fromBTC(value, num); + return this.fromBTC(value); } throw new Error(`Unknown unit "${unit}".`); }; @@ -225,12 +218,11 @@ Amount.prototype.from = function from(unit, value, num) { * Instantiate amount from options. * @param {(String|Number)?} value * @param {String?} unit - * @param {Boolean?} num * @returns {Amount} */ -Amount.fromOptions = function fromOptions(value, unit, num) { - return new Amount().fromOptions(value); +Amount.fromOptions = function fromOptions(value, unit) { + return new Amount().fromOptions(value, unit); }; /** @@ -247,57 +239,52 @@ Amount.fromValue = function fromValue(value) { /** * Instantiate amount from satoshis. * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.fromSatoshis = function fromSatoshis(value, num) { - return new Amount().fromSatoshis(value, num); +Amount.fromSatoshis = function fromSatoshis(value) { + return new Amount().fromSatoshis(value); }; /** * Instantiate amount from bits. * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.fromBits = function fromBits(value, num) { - return new Amount().fromBits(value, num); +Amount.fromBits = function fromBits(value) { + return new Amount().fromBits(value); }; /** * Instantiate amount from mbtc. * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.fromMBTC = function fromMBTC(value, num) { - return new Amount().fromMBTC(value, num); +Amount.fromMBTC = function fromMBTC(value) { + return new Amount().fromMBTC(value); }; /** * Instantiate amount from btc. * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.fromBTC = function fromBTC(value, num) { - return new Amount().fromBTC(value, num); +Amount.fromBTC = function fromBTC(value) { + return new Amount().fromBTC(value); }; /** * Instantiate amount from unit. * @param {String} unit * @param {Number|String} value - * @param {Bolean?} num * @returns {Amount} */ -Amount.from = function from(unit, value, num) { - return new Amount().from(unit, value, num); +Amount.from = function from(unit, value) { + return new Amount().from(unit, value); }; /** @@ -318,271 +305,54 @@ Amount.prototype.inspect = function inspect() { */ Amount.btc = function btc(value, num) { - if (util.isFloat(value)) + if (typeof value === 'string') return value; - return Amount.serialize(value, 8, num); + return Amount.encode(value, 8, num); }; /** - * Safely convert satoshis to a BTC string. - * This function explicitly avoids any - * floating point arithmetic. - * @param {Amount} value - * @param {Number} exp - Exponent. - * @param {Boolean} num - Return a number. - * @returns {String} + * Safely convert a BTC string to satoshis. + * @param {String} str - BTC + * @returns {Amount} Satoshis. + * @throws on parse error */ -Amount.serialize = function serialize(value, exp, num) { - let negative = false; - let hi, lo, result; - - assert(util.isInt(value), 'Non-satoshi value for conversion.'); - - if (value < 0) { - value = -value; - negative = true; - } - - value = value.toString(10); - - assert(value.length <= 16, 'Number exceeds 2^53-1.'); - - while (value.length < exp + 1) - value = '0' + value; - - hi = value.slice(0, -exp); - lo = value.slice(-exp); - - lo = lo.replace(/0+$/, ''); - - if (lo.length === 0) - lo += '0'; +Amount.value = function value(str) { + if (typeof str === 'number') + return str; - result = `${hi}.${lo}`; - - if (negative) - result = '-' + result; - - if (num) - return +result; - - return result; + return Amount.decode(str, 8); }; /** - * Unsafely convert satoshis to a BTC string. + * Safely convert satoshis to a BTC string. * @param {Amount} value * @param {Number} exp - Exponent. * @param {Boolean} num - Return a number. - * @returns {String} + * @returns {String|Number} */ -Amount.serializeUnsafe = function serializeUnsafe(value, exp, num) { - assert(util.isInt(value), 'Non-satoshi value for conversion.'); - - value /= pow10(exp); - value = value.toFixed(exp); - +Amount.encode = function encode(value, exp, num) { if (num) - return +value; - - if (exp !== 0) { - value = value.replace(/0+$/, ''); - if (value[value.length - 1] === '.') - value += '0'; - } - - return value; -}; - -/** - * Safely convert a BTC string to satoshis. - * @param {String} value - BTC - * @returns {Amount} Satoshis. - * @throws on parse error - */ - -Amount.value = function _value(value, num) { - if (util.isInt(value)) - return value; - - return Amount.parse(value, 8, num); + return util.toFloat(value, exp); + return util.toFixed(value, exp); }; /** * Safely convert a BTC string to satoshis. - * This function explicitly avoids any - * floating point arithmetic. It also does - * extra validation to ensure the resulting - * Number will be 53 bits or less. - * @param {String} value - BTC + * @param {String|Number} value - BTC * @param {Number} exp - Exponent. - * @param {Boolean} num - Allow numbers. * @returns {Amount} Satoshis. * @throws on parse error */ -Amount.parse = function parse(value, exp, num) { - let negative = false; - let mult = pow10(exp); - let maxLo = modSafe(mult); - let maxHi = divSafe(mult); - let parts, hi, lo, result; - - if (num && typeof value === 'number') { - assert(util.isNumber(value), 'Non-BTC value for conversion.'); - value = value.toString(10); - } - - assert(util.isFloat(value), 'Non-BTC value for conversion.'); - - if (value[0] === '-') { - negative = true; - value = value.substring(1); - } - - parts = value.split('.'); - - assert(parts.length <= 2, 'Bad decimal point.'); - - hi = parts[0] || '0'; - lo = parts[1] || '0'; - - hi = hi.replace(/^0+/, ''); - lo = lo.replace(/0+$/, ''); - - assert(hi.length <= 16 - exp, 'Number exceeds 2^53-1.'); - assert(lo.length <= exp, 'Too many decimal places.'); - - if (hi.length === 0) - hi = '0'; - - while (lo.length < exp) - lo += '0'; - - hi = parseInt(hi, 10); - lo = parseInt(lo, 10); - - assert(hi < maxHi || (hi === maxHi && lo <= maxLo), - 'Number exceeds 2^53-1.'); - - result = hi * mult + lo; - - if (negative) - result = -result; - - return result; -}; - -/** - * Unsafely convert a BTC string to satoshis. - * @param {String} value - BTC - * @param {Number} exp - Exponent. - * @param {Boolean} num - Allow numbers. - * @returns {Amount} Satoshis. - * @throws on parse error - */ - -Amount.parseUnsafe = function parseUnsafe(value, exp, num) { - if (typeof value === 'string') { - assert(util.isFloat(value), 'Non-BTC value for conversion.'); - value = parseFloat(value); - } else { - assert(util.isNumber(value), 'Non-BTC value for conversion.'); - assert(num, 'Cannot parse number.'); - } - - value *= pow10(exp); - - assert(value % 1 === 0, 'Too many decimal places.'); - - return value; +Amount.decode = function decode(value, exp) { + if (typeof value === 'number') + return util.fromFloat(value, exp); + return util.fromFixed(value, exp); }; -/* - * Helpers - */ - -function pow10(exp) { - switch (exp) { - case 0: - return 1; - case 1: - return 10; - case 2: - return 100; - case 3: - return 1000; - case 4: - return 10000; - case 5: - return 100000; - case 6: - return 1000000; - case 7: - return 10000000; - case 8: - return 100000000; - default: - assert(false, 'Exponent is too large.'); - break; - } -} - -function modSafe(mod) { - switch (mod) { - case 1: - return 0; - case 10: - return 1; - case 100: - return 91; - case 1000: - return 991; - case 10000: - return 991; - case 100000: - return 40991; - case 1000000: - return 740991; - case 10000000: - return 4740991; - case 100000000: - return 54740991; - default: - assert(false, 'Exponent is too large.'); - break; - } -} - -function divSafe(div) { - switch (div) { - case 1: - return 9007199254740991; - case 10: - return 900719925474099; - case 100: - return 90071992547409; - case 1000: - return 9007199254740; - case 10000: - return 900719925474; - case 100000: - return 90071992547; - case 1000000: - return 9007199254; - case 10000000: - return 900719925; - case 100000000: - return 90071992; - default: - assert(false, 'Exponent is too large.'); - break; - } -} - /* * Expose */ diff --git a/lib/btc/uri.js b/lib/btc/uri.js index addbdfcd6..fa44142df 100644 --- a/lib/btc/uri.js +++ b/lib/btc/uri.js @@ -52,7 +52,7 @@ URI.prototype.fromOptions = function fromOptions(options) { this.address.fromOptions(options.address); if (options.amount != null) { - assert(util.isUInt53(options.amount), 'Amount must be a uint53.'); + assert(util.isU64(options.amount), 'Amount must be a uint64.'); this.amount = options.amount; } @@ -93,32 +93,31 @@ URI.fromOptions = function fromOptions(options) { */ URI.prototype.fromString = function fromString(str, network) { - let prefix, index, query, address; - assert(typeof str === 'string'); assert(str.length > 8, 'Not a bitcoin URI.'); - prefix = str.substring(0, 8); + const prefix = str.substring(0, 8); assert(prefix === 'bitcoin:', 'Not a bitcoin URI.'); str = str.substring(8); - index = str.indexOf('?'); + const index = str.indexOf('?'); + let addr, qs; if (index === -1) { - address = str; + addr = str; } else { - address = str.substring(0, index); - query = str.substring(index + 1); + addr = str.substring(0, index); + qs = str.substring(index + 1); } - this.address.fromString(address, network); + this.address.fromString(addr, network); - if (!query) + if (!qs) return this; - query = parsePairs(query); + const query = parsePairs(qs); if (query.amount) { assert(query.amount.length > 0, 'Value is empty.'); @@ -156,10 +155,11 @@ URI.fromString = function fromString(str, network) { URI.prototype.toString = function toString() { let str = 'bitcoin:'; - let query = []; str += this.address.toString(); + const query = []; + if (this.amount !== -1) query.push(`amount=${Amount.btc(this.amount)}`); @@ -199,12 +199,12 @@ function BitcoinQuery() { } function parsePairs(str) { - let parts = str.split('&'); - let data = new BitcoinQuery(); + const parts = str.split('&'); + const data = new BitcoinQuery(); let size = 0; - for (let pair of parts) { - let index = pair.indexOf('='); + for (const pair of parts) { + const index = pair.indexOf('='); let key, value; if (index === -1) { diff --git a/lib/coins/coinentry.js b/lib/coins/coinentry.js new file mode 100644 index 000000000..757ca6a7d --- /dev/null +++ b/lib/coins/coinentry.js @@ -0,0 +1,277 @@ +/*! + * coinentry.js - coin entry object for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +const assert = require('assert'); +const Coin = require('../primitives/coin'); +const Output = require('../primitives/output'); +const BufferReader = require('../utils/reader'); +const StaticWriter = require('../utils/staticwriter'); +const encoding = require('../utils/encoding'); +const compress = require('./compress'); + +/* + * Constants + */ + +const NUM_FLAGS = 1; +const MAX_HEIGHT = ((1 << (32 - NUM_FLAGS)) >>> 0) - 1; + +/** + * Represents an unspent output. + * @alias module:coins.CoinEntry + * @constructor + * @property {Number} version - Transaction version. + * @property {Number} height - Transaction height (-1 if unconfirmed). + * @property {Boolean} coinbase - Whether the containing + * transaction is a coinbase. + * @property {Output} output + * @property {Boolean} spent + * @property {Buffer} raw + */ + +function CoinEntry() { + if (!(this instanceof CoinEntry)) + return new CoinEntry(); + + this.version = 1; + this.height = -1; + this.coinbase = false; + this.output = new Output(); + this.spent = false; + this.raw = null; +} + +/** + * Convert coin entry to an output. + * @returns {Output} + */ + +CoinEntry.prototype.toOutput = function toOutput() { + return this.output; +}; + +/** + * Convert coin entry to a coin. + * @param {Outpoint} prevout + * @returns {Coin} + */ + +CoinEntry.prototype.toCoin = function toCoin(prevout) { + const coin = new Coin(); + coin.version = this.version; + coin.height = this.height; + coin.coinbase = this.coinbase; + coin.script = this.output.script; + coin.value = this.output.value; + coin.hash = prevout.hash; + coin.index = prevout.index; + return coin; +}; + +/** + * Inject properties from TX. + * @param {TX} tx + * @param {Number} index + */ + +CoinEntry.prototype.fromOutput = function fromOutput(output) { + this.output = output; + return this; +}; + +/** + * Instantiate a coin from a TX + * @param {TX} tx + * @param {Number} index - Output index. + * @returns {CoinEntry} + */ + +CoinEntry.fromOutput = function fromOutput(output) { + return new CoinEntry().fromOutput(output); +}; + +/** + * Inject properties from TX. + * @param {TX} tx + * @param {Number} index + */ + +CoinEntry.prototype.fromCoin = function fromCoin(coin) { + this.version = coin.version; + this.height = coin.height; + this.coinbase = coin.coinbase; + this.output.script = coin.script; + this.output.value = coin.value; + return this; +}; + +/** + * Instantiate a coin from a TX + * @param {TX} tx + * @param {Number} index - Output index. + * @returns {CoinEntry} + */ + +CoinEntry.fromCoin = function fromCoin(coin) { + return new CoinEntry().fromCoin(coin); +}; + +/** + * Inject properties from TX. + * @param {TX} tx + * @param {Number} index + */ + +CoinEntry.prototype.fromTX = function fromTX(tx, index, height) { + assert(typeof index === 'number'); + assert(typeof height === 'number'); + assert(index >= 0 && index < tx.outputs.length); + this.version = tx.version; + this.height = height; + this.coinbase = tx.isCoinbase(); + this.output = tx.outputs[index]; + return this; +}; + +/** + * Instantiate a coin from a TX + * @param {TX} tx + * @param {Number} index - Output index. + * @returns {CoinEntry} + */ + +CoinEntry.fromTX = function fromTX(tx, index, height) { + return new CoinEntry().fromTX(tx, index, height); +}; + +/** + * Calculate size of coin. + * @returns {Number} + */ + +CoinEntry.prototype.getSize = function getSize() { + if (this.raw) + return this.raw.length; + + let size = 0; + size += encoding.sizeVarint(this.version); + size += 4; + size += compress.size(this.output); + + return size; +}; + +/** + * Write the coin to a buffer writer. + * @param {BufferWriter} bw + */ + +CoinEntry.prototype.toWriter = function toWriter(bw) { + if (this.raw) { + bw.writeBytes(this.raw); + return bw; + } + + let height = this.height; + let field = 0; + + if (this.coinbase) + field |= 1; + + if (height === -1) + height = MAX_HEIGHT; + + field |= height << NUM_FLAGS; + + bw.writeVarint(this.version); + bw.writeU32(field); + compress.pack(this.output, bw); + + return bw; +}; + +/** + * Serialize the coin. + * @returns {Buffer} + */ + +CoinEntry.prototype.toRaw = function toRaw() { + if (this.raw) + return this.raw; + + const size = this.getSize(); + const bw = new StaticWriter(size); + + this.toWriter(bw); + + this.raw = bw.render(); + + return this.raw; +}; + +/** + * Inject properties from serialized buffer writer. + * @private + * @param {BufferReader} br + */ + +CoinEntry.prototype.fromReader = function fromReader(br) { + const version = br.readVarint(); + const field = br.readU32(); + + let height = field >>> NUM_FLAGS; + + if (height === MAX_HEIGHT) + height = -1; + + this.version = version; + this.coinbase = (field & 1) !== 0; + this.height = height; + + compress.unpack(this.output, br); + + return this; +}; + +/** + * Instantiate a coin from a serialized Buffer. + * @param {Buffer} data + * @returns {CoinEntry} + */ + +CoinEntry.fromReader = function fromReader(data) { + return new CoinEntry().fromReader(data); +}; + +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + +CoinEntry.prototype.fromRaw = function fromRaw(data) { + this.fromReader(new BufferReader(data)); + this.raw = data; + return this; +}; + +/** + * Instantiate a coin from a serialized Buffer. + * @param {Buffer} data + * @returns {CoinEntry} + */ + +CoinEntry.fromRaw = function fromRaw(data) { + return new CoinEntry().fromRaw(data); +}; + +/* + * Expose + */ + +module.exports = CoinEntry; diff --git a/lib/coins/coins.js b/lib/coins/coins.js index df706bdd0..97516f68a 100644 --- a/lib/coins/coins.js +++ b/lib/coins/coins.js @@ -6,126 +6,60 @@ 'use strict'; -const util = require('../utils/util'); const assert = require('assert'); -const Coin = require('../primitives/coin'); -const Output = require('../primitives/output'); -const BufferReader = require('../utils/reader'); -const StaticWriter = require('../utils/staticwriter'); -const encoding = require('../utils/encoding'); -const compressor = require('./compress'); -const compress = compressor.compress; -const decompress = compressor.decompress; +const CoinEntry = require('./coinentry'); /** * Represents the outputs for a single transaction. * @alias module:coins.Coins * @constructor - * @param {Object?} options - Options object. - * @property {Hash} hash - Transaction hash. - * @property {Number} version - Transaction version. - * @property {Number} height - Transaction height (-1 if unconfirmed). - * @property {Boolean} coinbase - Whether the containing - * transaction is a coinbase. - * @property {CoinEntry[]} outputs - Coins. + * @property {Map[]} outputs - Coins. */ -function Coins(options) { +function Coins() { if (!(this instanceof Coins)) - return new Coins(options); + return new Coins(); - this.version = 1; - this.hash = encoding.NULL_HASH; - this.height = -1; - this.coinbase = true; - this.outputs = []; - - if (options) - this.fromOptions(options); + this.outputs = new Map(); } -/** - * Inject properties from options object. - * @private - * @param {Object} options - */ - -Coins.prototype.fromOptions = function fromOptions(options) { - if (options.version != null) { - assert(util.isUInt32(options.version)); - this.version = options.version; - } - - if (options.hash) { - assert(typeof options.hash === 'string'); - this.hash = options.hash; - } - - if (options.height != null) { - assert(util.isNumber(options.height)); - this.height = options.height; - } - - if (options.coinbase != null) { - assert(typeof options.coinbase === 'boolean'); - this.coinbase = options.coinbase; - } - - if (options.outputs) { - assert(Array.isArray(options.outputs)); - this.outputs = options.outputs; - this.cleanup(); - } - - return this; -}; - -/** - * Instantiate coins from options object. - * @param {Object} options - * @returns {Coins} - */ - -Coins.fromOptions = function fromOptions(options) { - return new Coins().fromOptions(options); -}; - /** * Add a single entry to the collection. * @param {Number} index - * @param {CoinEntry} entry + * @param {CoinEntry} coin + * @returns {CoinEntry} */ -Coins.prototype.add = function add(index, entry) { +Coins.prototype.add = function add(index, coin) { assert(index >= 0); + assert(!this.outputs.has(index)); - while (this.outputs.length <= index) - this.outputs.push(null); - - assert(!this.outputs[index]); + this.outputs.set(index, coin); - this.outputs[index] = entry; + return coin; }; /** * Add a single output to the collection. * @param {Number} index * @param {Output} output + * @returns {CoinEntry} */ Coins.prototype.addOutput = function addOutput(index, output) { assert(!output.script.isUnspendable()); - this.add(index, CoinEntry.fromOutput(output)); + return this.add(index, CoinEntry.fromOutput(output)); }; /** * Add a single coin to the collection. * @param {Coin} coin + * @returns {CoinEntry} */ Coins.prototype.addCoin = function addCoin(coin) { assert(!coin.script.isUnspendable()); - this.add(coin.index, CoinEntry.fromCoin(coin)); + return this.add(coin.index, CoinEntry.fromCoin(coin)); }; /** @@ -135,28 +69,19 @@ Coins.prototype.addCoin = function addCoin(coin) { */ Coins.prototype.has = function has(index) { - if (index >= this.outputs.length) - return false; - - return this.outputs[index] != null; + return this.outputs.has(index); }; /** - * Test whether the collection - * has an unspent coin. + * Test whether the collection has an unspent coin. * @param {Number} index * @returns {Boolean} */ Coins.prototype.isUnspent = function isUnspent(index) { - let output; - - if (index >= this.outputs.length) - return false; + const coin = this.outputs.get(index); - output = this.outputs[index]; - - if (!output || output.spent) + if (!coin || coin.spent) return false; return true; @@ -165,106 +90,75 @@ Coins.prototype.isUnspent = function isUnspent(index) { /** * Get a coin entry. * @param {Number} index - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ Coins.prototype.get = function get(index) { - if (index >= this.outputs.length) - return; - - return this.outputs[index]; + return this.outputs.get(index) || null; }; /** * Get an output. * @param {Number} index - * @returns {Output} + * @returns {Output|null} */ Coins.prototype.getOutput = function getOutput(index) { - let entry = this.get(index); + const coin = this.outputs.get(index); - if (!entry) - return; + if (!coin) + return null; - return entry.toOutput(); + return coin.output; }; /** * Get a coin. - * @param {Number} index - * @returns {Coin} + * @param {Outpoint} prevout + * @returns {Coin|null} */ -Coins.prototype.getCoin = function getCoin(index) { - let entry = this.get(index); +Coins.prototype.getCoin = function getCoin(prevout) { + const coin = this.outputs.get(prevout.index); - if (!entry) - return; + if (!coin) + return null; - return entry.toCoin(this, index); + return coin.toCoin(prevout); }; /** * Spend a coin entry and return it. * @param {Number} index - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ Coins.prototype.spend = function spend(index) { - let entry = this.get(index); + const coin = this.get(index); - if (!entry || entry.spent) - return; + if (!coin || coin.spent) + return null; - entry.spent = true; + coin.spent = true; - return entry; + return coin; }; /** * Remove a coin entry and return it. * @param {Number} index - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ Coins.prototype.remove = function remove(index) { - let entry = this.get(index); - - if (!entry) - return false; - - this.outputs[index] = null; - this.cleanup(); - - return entry; -}; - -/** - * Calculate unspent length of coins. - * @returns {Number} - */ + const coin = this.get(index); -Coins.prototype.length = function length() { - let len = this.outputs.length; + if (!coin) + return null; - while (len > 0 && !this.isUnspent(len - 1)) - len--; + this.outputs.delete(index); - return len; -}; - -/** - * Cleanup spent outputs (remove pruned). - */ - -Coins.prototype.cleanup = function cleanup() { - let len = this.outputs.length; - - while (len > 0 && !this.outputs[len - 1]) - len--; - - this.outputs.length = len; + return coin; }; /** @@ -273,285 +167,7 @@ Coins.prototype.cleanup = function cleanup() { */ Coins.prototype.isEmpty = function isEmpty() { - return this.length() === 0; -}; - -/* - * Coins serialization: - * version: varint - * height: uint32 - * header-code: varint - * bit 1: coinbase - * bit 2: first output unspent - * bit 3: second output unspent - * bit 4-32: spent-field size - * spent-field: bitfield (0=spent, 1=unspent) - * outputs (repeated): - * value: varint - * compressed-script: - * prefix: 0x00 = 20 byte pubkey hash - * 0x01 = 20 byte script hash - * 0x02-0x05 = 32 byte ec-key x-value - * 0x06-0x09 = reserved - * >=0x10 = varint-size + 10 | raw script - * data: script data, dictated by the prefix - * - * The compression below sacrifices some cpu in exchange - * for reduced size, but in some cases the use of varints - * actually increases speed (varint versions and values - * for example). We do as much compression as possible - * without sacrificing too much cpu. Value compression - * is intentionally excluded for now as it seems to be - * too much of a perf hit. Maybe when v8 optimizes - * non-smi arithmetic better we can enable it. - */ - -/** - * Calculate header code. - * @param {Number} len - * @param {Number} size - * @returns {Number} - */ - -Coins.prototype.header = function header(len, size) { - let first = this.isUnspent(0); - let second = this.isUnspent(1); - let offset = 0; - let code; - - // Throw if we're fully spent. - assert(len !== 0, 'Cannot serialize fully-spent coins.'); - - // First and second bits - // have a double meaning. - if (!first && !second) { - assert(size !== 0); - offset = 1; - } - - // Calculate header code. - code = 8 * (size - offset); - - if (this.coinbase) - code += 1; - - if (first) - code += 2; - - if (second) - code += 4; - - return code; -}; - -/** - * Serialize the coins object. - * @returns {Buffer} - */ - -Coins.prototype.toRaw = function toRaw() { - let len = this.length(); - let size = Math.floor((len + 5) / 8); - let code = this.header(len, size); - let total = this.getSize(len, size, code); - let bw = new StaticWriter(total); - - // Write headers. - bw.writeVarint(this.version); - bw.writeU32(this.height); - bw.writeVarint(code); - - // Write the spent field. - for (let i = 0; i < size; i++) { - let ch = 0; - for (let j = 0; j < 8 && 2 + i * 8 + j < len; j++) { - if (this.isUnspent(2 + i * 8 + j)) - ch |= 1 << j; - } - bw.writeU8(ch); - } - - // Write the compressed outputs. - for (let i = 0; i < len; i++) { - let output = this.outputs[i]; - - if (!output || output.spent) - continue; - - output.toWriter(bw); - } - - return bw.render(); -}; - -/** - * Calculate coins size. - * @param {Number} code - * @param {Number} size - * @param {Number} len - * @returns {Number} - */ - -Coins.prototype.getSize = function getSize(len, size, code) { - let total = 0; - - total += encoding.sizeVarint(this.version); - total += 4; - total += encoding.sizeVarint(code); - total += size; - - // Write the compressed outputs. - for (let i = 0; i < len; i++) { - let output = this.outputs[i]; - - if (!output || output.spent) - continue; - - total += output.getSize(); - } - - return total; -}; - -/** - * Inject data from serialized coins. - * @private - * @param {Buffer} data - * @param {Hash} hash - * @returns {Coins} - */ - -Coins.prototype.fromRaw = function fromRaw(data, hash) { - let br = new BufferReader(data); - let first = null; - let second = null; - let code, size, offset; - - // Inject hash (passed by caller). - this.hash = hash; - - // Read headers. - this.version = br.readVarint(); - this.height = br.readU32(); - code = br.readVarint(); - this.coinbase = (code & 1) !== 0; - - // Recalculate size. - size = code / 8 | 0; - - if ((code & 6) === 0) - size += 1; - - // Setup spent field. - offset = br.offset; - br.seek(size); - - // Read first two outputs. - if ((code & 2) !== 0) - first = CoinEntry.fromReader(br); - - if ((code & 4) !== 0) - second = CoinEntry.fromReader(br); - - this.outputs.push(first); - this.outputs.push(second); - - // Read outputs. - for (let i = 0; i < size; i++) { - let ch = br.data[offset++]; - for (let j = 0; j < 8; j++) { - if ((ch & (1 << j)) === 0) { - this.outputs.push(null); - continue; - } - this.outputs.push(CoinEntry.fromReader(br)); - } - } - - this.cleanup(); - - return this; -}; - -/** - * Parse a single serialized coin. - * @param {Buffer} data - * @param {Hash} hash - * @param {Number} index - * @returns {Coin} - */ - -Coins.parseCoin = function parseCoin(data, hash, index) { - let br = new BufferReader(data); - let coin = new Coin(); - let code, size, offset; - - // Inject outpoint (passed by caller). - coin.hash = hash; - coin.index = index; - - // Read headers. - coin.version = br.readVarint(); - coin.height = br.readU32(); - code = br.readVarint(); - coin.coinbase = (code & 1) !== 0; - - // Recalculate size. - size = code / 8 | 0; - - if ((code & 6) === 0) - size += 1; - - if (index >= 2 + size * 8) - return; - - // Setup spent field. - offset = br.offset; - br.seek(size); - - // Read first two outputs. - for (let i = 0; i < 2; i++) { - if ((code & (2 << i)) !== 0) { - if (index === 0) { - decompress.coin(coin, br); - return coin; - } - decompress.skip(br); - } else { - if (index === 0) - return; - } - index -= 1; - } - - // Read outputs. - for (let i = 0; i < size; i++) { - let ch = br.data[offset++]; - for (let j = 0; j < 8; j++) { - if ((ch & (1 << j)) !== 0) { - if (index === 0) { - decompress.coin(coin, br); - return coin; - } - decompress.skip(br); - } else { - if (index === 0) - return; - } - index -= 1; - } - } -}; - -/** - * Instantiate coins from a buffer. - * @param {Buffer} data - * @param {Hash} hash - Transaction hash. - * @returns {Coins} - */ - -Coins.fromRaw = function fromRaw(data, hash) { - return new Coins().fromRaw(data, hash); + return this.outputs.size === 0; }; /** @@ -559,27 +175,20 @@ Coins.fromRaw = function fromRaw(data, hash) { * @private * @param {TX} tx * @param {Number} height + * @returns {Coins} */ Coins.prototype.fromTX = function fromTX(tx, height) { - let output; - assert(typeof height === 'number'); - this.version = tx.version; - this.hash = tx.hash('hex'); - this.height = height; - this.coinbase = tx.isCoinbase(); + for (let i = 0; i < tx.outputs.length; i++) { + const output = tx.outputs[i]; - for (output of tx.outputs) { - if (output.script.isUnspendable()) { - this.outputs.push(null); + if (output.script.isUnspendable()) continue; - } - this.outputs.push(CoinEntry.fromOutput(output)); - } - this.cleanup(); + this.outputs.set(i, CoinEntry.fromTX(tx, i, height)); + } return this; }; @@ -595,169 +204,8 @@ Coins.fromTX = function fromTX(tx, height) { return new Coins().fromTX(tx, height); }; -/** - * A coin entry is an object which defers - * parsing of a coin. Say there is a transaction - * with 100 outputs. When a block comes in, - * there may only be _one_ input in that entire - * block which redeems an output from that - * transaction. When parsing the Coins, there - * is no sense to get _all_ of them into their - * abstract form. A coin entry is just a - * pointer to that coin in the Coins buffer, as - * well as a size. Parsing and decompression - * is done only if that coin is being redeemed. - * @alias module:coins.CoinEntry - * @constructor - * @property {Number} offset - * @property {Number} size - * @property {Buffer} raw - * @property {Output|null} output - * @property {Boolean} spent - */ - -function CoinEntry() { - this.offset = 0; - this.size = 0; - this.raw = null; - this.output = null; - this.spent = false; -} - -/** - * Instantiate a reader at the correct offset. - * @private - * @returns {BufferReader} - */ - -CoinEntry.prototype.reader = function reader() { - let br; - - assert(this.raw); - - br = new BufferReader(this.raw); - br.offset = this.offset; - - return br; -}; - -/** - * Parse the deferred data and return a coin. - * @param {Coins} coins - * @param {Number} index - * @returns {Coin} - */ - -CoinEntry.prototype.toCoin = function toCoin(coins, index) { - let coin = new Coin(); - let output = this.toOutput(); - - // Load in all necessary properties - // from the parent Coins object. - coin.version = coins.version; - coin.coinbase = coins.coinbase; - coin.height = coins.height; - coin.hash = coins.hash; - coin.index = index; - coin.script = output.script; - coin.value = output.value; - - return coin; -}; - -/** - * Parse the deferred data and return an output. - * @returns {Output} - */ - -CoinEntry.prototype.toOutput = function toOutput() { - if (!this.output) { - this.output = new Output(); - decompress.output(this.output, this.reader()); - } - return this.output; -}; - -/** - * Calculate coin entry size. - * @returns {Number} - */ - -CoinEntry.prototype.getSize = function getSize() { - if (!this.raw) - return compress.size(this.output); - - return this.size; -}; - -/** - * Slice off the part of the buffer - * relevant to this particular coin. - */ - -CoinEntry.prototype.toWriter = function toWriter(bw) { - if (!this.raw) { - assert(this.output); - compress.output(this.output, bw); - return bw; - } - - // If we read this coin from the db and - // didn't use it, it's still in its - // compressed form. Just write it back - // as a buffer for speed. - bw.copy(this.raw, this.offset, this.offset + this.size); - - return bw; -}; - -/** - * Instantiate coin entry from reader. - * @param {BufferReader} br - * @returns {CoinEntry} - */ - -CoinEntry.fromReader = function fromReader(br) { - let entry = new CoinEntry(); - entry.offset = br.offset; - entry.size = decompress.skip(br); - entry.raw = br.data; - return entry; -}; - -/** - * Instantiate coin entry from output. - * @param {Output} output - * @returns {CoinEntry} - */ - -CoinEntry.fromOutput = function fromOutput(output) { - let entry = new CoinEntry(); - entry.output = output; - return entry; -}; - -/** - * Instantiate coin entry from coin. - * @param {Coin} coin - * @returns {CoinEntry} - */ - -CoinEntry.fromCoin = function fromCoin(coin) { - let entry = new CoinEntry(); - let output = new Output(); - output.value = coin.value; - output.script = coin.script; - entry.output = output; - return entry; -}; - /* * Expose */ -exports = Coins; -exports.Coins = Coins; -exports.CoinEntry = CoinEntry; - -module.exports = exports; +module.exports = Coins; diff --git a/lib/coins/coinview.js b/lib/coins/coinview.js index 00e4864f7..836896255 100644 --- a/lib/coins/coinview.js +++ b/lib/coins/coinview.js @@ -6,10 +6,9 @@ 'use strict'; -const assert = require('assert'); const Coins = require('./coins'); const UndoCoins = require('./undocoins'); -const CoinEntry = Coins.CoinEntry; +const CoinEntry = require('./coinentry'); /** * Represents a coin viewpoint: @@ -50,270 +49,375 @@ CoinView.prototype.has = function has(hash) { /** * Add coins to the collection. + * @param {Hash} hash * @param {Coins} coins + * @returns {Coins} */ -CoinView.prototype.add = function add(coins) { - this.map.set(coins.hash, coins); +CoinView.prototype.add = function add(hash, coins) { + this.map.set(hash, coins); return coins; }; /** * Remove coins from the collection. * @param {Coins} coins - * @returns {Boolean} + * @returns {Coins|null} */ CoinView.prototype.remove = function remove(hash) { - if (!this.map.has(hash)) - return false; + const coins = this.map.get(hash); + + if (!coins) + return null; this.map.delete(hash); - return true; + return coins; }; /** * Add a tx to the collection. * @param {TX} tx * @param {Number} height + * @returns {Coins} */ CoinView.prototype.addTX = function addTX(tx, height) { - let coins = Coins.fromTX(tx, height); - return this.add(coins); + const hash = tx.hash('hex'); + const coins = Coins.fromTX(tx, height); + return this.add(hash, coins); }; /** * Remove a tx from the collection. * @param {TX} tx * @param {Number} height + * @returns {Coins} */ CoinView.prototype.removeTX = function removeTX(tx, height) { - let coins = Coins.fromTX(tx, height); - coins.outputs.length = 0; - return this.add(coins); + const hash = tx.hash('hex'); + const coins = Coins.fromTX(tx, height); + + for (const coin of coins.outputs.values()) + coin.spent = true; + + return this.add(hash, coins); +}; + +/** + * Add an entry to the collection. + * @param {Outpoint} prevout + * @param {CoinEntry} coin + * @returns {CoinEntry|null} + */ + +CoinView.prototype.addEntry = function addEntry(prevout, coin) { + const {hash, index} = prevout; + let coins = this.get(hash); + + if (!coins) { + coins = new Coins(); + this.add(hash, coins); + } + + if (coin.output.script.isUnspendable()) + return null; + + if (coins.has(index)) + return null; + + return coins.add(index, coin); }; /** * Add a coin to the collection. * @param {Coin} coin + * @returns {CoinEntry|null} */ CoinView.prototype.addCoin = function addCoin(coin) { - let coins = this.get(coin.hash); + const {hash, index} = coin; + let coins = this.get(hash); if (!coins) { coins = new Coins(); - coins.hash = coin.hash; - coins.height = coin.height; - coins.coinbase = coin.coinbase; - this.add(coins); + this.add(hash, coins); } if (coin.script.isUnspendable()) - return; + return null; + + if (coins.has(index)) + return null; - if (!coins.has(coin.index)) - coins.addCoin(coin); + return coins.addCoin(coin); }; /** * Add an output to the collection. - * @param {Hash} hash - * @param {Number} index + * @param {Outpoint} prevout * @param {Output} output + * @returns {CoinEntry|null} */ -CoinView.prototype.addOutput = function addOutput(hash, index, output) { +CoinView.prototype.addOutput = function addOutput(prevout, output) { + const {hash, index} = prevout; let coins = this.get(hash); if (!coins) { coins = new Coins(); - coins.hash = hash; - coins.height = -1; - coins.coinbase = false; - this.add(coins); + this.add(hash, coins); } if (output.script.isUnspendable()) - return; + return null; + + if (coins.has(index)) + return null; - if (!coins.has(index)) - coins.addOutput(index, output); + return coins.addOutput(index, output); }; /** * Spend an output. - * @param {Hash} hash - * @param {Number} index - * @returns {Boolean} + * @param {Outpoint} prevout + * @returns {CoinEntry|null} */ -CoinView.prototype.spendOutput = function spendOutput(hash, index) { - let coins = this.get(hash); +CoinView.prototype.spendEntry = function spendEntry(prevout) { + const {hash, index} = prevout; + const coins = this.get(hash); if (!coins) - return false; + return null; - return this.spendFrom(coins, index); + const coin = coins.spend(index); + + if (!coin) + return null; + + this.undo.push(coin); + + return coin; }; /** * Remove an output. - * @param {Hash} hash - * @param {Number} index - * @returns {Boolean} + * @param {Outpoint} prevout + * @returns {CoinEntry|null} */ -CoinView.prototype.removeOutput = function removeOutput(hash, index) { - let coins = this.get(hash); +CoinView.prototype.removeEntry = function removeEntry(prevout) { + const {hash, index} = prevout; + const coins = this.get(hash); if (!coins) - return false; + return null; return coins.remove(index); }; /** - * Spend a coin from coins object. - * @param {Coins} coins - * @param {Number} index + * Test whether the view has an entry by prevout. + * @param {Outpoint} prevout * @returns {Boolean} */ -CoinView.prototype.spendFrom = function spendFrom(coins, index) { - let entry = coins.spend(index); - let undo; +CoinView.prototype.hasEntry = function hasEntry(prevout) { + const {hash, index} = prevout; + const coins = this.get(hash); - if (!entry) + if (!coins) return false; - this.undo.push(entry); + return coins.has(index); +}; - if (coins.isEmpty()) { - undo = this.undo.top(); - undo.height = coins.height; - undo.coinbase = coins.coinbase; - undo.version = coins.version; - assert(undo.height !== -1); - } +/** + * Get a single entry by prevout. + * @param {Outpoint} prevout + * @returns {CoinEntry|null} + */ - return true; +CoinView.prototype.getEntry = function getEntry(prevout) { + const {hash, index} = prevout; + const coins = this.get(hash); + + if (!coins) + return null; + + return coins.get(index); }; /** - * Get a single coin by input. - * @param {Input} input - * @returns {Coin} + * Test whether an entry has been spent by prevout. + * @param {Outpoint} prevout + * @returns {Boolean} */ -CoinView.prototype.getCoin = function getCoin(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.isUnspent = function isUnspent(prevout) { + const {hash, index} = prevout; + const coins = this.get(hash); if (!coins) - return; + return false; - return coins.getCoin(input.prevout.index); + return coins.isUnspent(index); }; /** - * Get a single output by input. - * @param {Input} input - * @returns {Output} + * Get a single coin by prevout. + * @param {Outpoint} prevout + * @returns {Coin|null} */ -CoinView.prototype.getOutput = function getOutput(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.getCoin = function getCoin(prevout) { + const coins = this.get(prevout.hash); if (!coins) - return; + return null; - return coins.getOutput(input.prevout.index); + return coins.getCoin(prevout); }; /** - * Get a single entry by input. - * @param {Input} input - * @returns {CoinEntry} + * Get a single output by prevout. + * @param {Outpoint} prevout + * @returns {Output|null} */ -CoinView.prototype.getEntry = function getEntry(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.getOutput = function getOutput(prevout) { + const {hash, index} = prevout; + const coins = this.get(hash); if (!coins) - return; + return null; - return coins.get(input.prevout.index); + return coins.getOutput(index); }; /** - * Test whether the view has an entry by input. - * @param {Input} input + * Get coins height by prevout. + * @param {Outpoint} prevout + * @returns {Number} + */ + +CoinView.prototype.getHeight = function getHeight(prevout) { + const coin = this.getEntry(prevout); + + if (!coin) + return -1; + + return coin.height; +}; + +/** + * Get coins coinbase flag by prevout. + * @param {Outpoint} prevout * @returns {Boolean} */ -CoinView.prototype.hasEntry = function hasEntry(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.isCoinbase = function isCoinbase(prevout) { + const coin = this.getEntry(prevout); - if (!coins) + if (!coin) return false; - return coins.has(input.prevout.index); + return coin.coinbase; }; /** - * Get coins height by input. + * Test whether the view has an entry by input. * @param {Input} input - * @returns {Number} + * @returns {Boolean} */ -CoinView.prototype.getHeight = function getHeight(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.hasEntryFor = function hasEntryFor(input) { + return this.hasEntry(input.prevout); +}; - if (!coins) - return -1; +/** + * Get a single entry by input. + * @param {Input} input + * @returns {CoinEntry|null} + */ - return coins.height; +CoinView.prototype.getEntryFor = function getEntryFor(input) { + return this.getEntry(input.prevout); }; /** - * Get coins coinbase flag by input. + * Test whether an entry has been spent by input. * @param {Input} input * @returns {Boolean} */ -CoinView.prototype.isCoinbase = function isCoinbase(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.isUnspentFor = function isUnspentFor(input) { + return this.isUnspent(input.prevout); +}; - if (!coins) - return false; +/** + * Get a single coin by input. + * @param {Input} input + * @returns {Coin|null} + */ - return coins.coinbase; +CoinView.prototype.getCoinFor = function getCoinFor(input) { + return this.getCoin(input.prevout); +}; + +/** + * Get a single output by input. + * @param {Input} input + * @returns {Output|null} + */ + +CoinView.prototype.getOutputFor = function getOutputFor(input) { + return this.getOutput(input.prevout); +}; + +/** + * Get coins height by input. + * @param {Input} input + * @returns {Number} + */ + +CoinView.prototype.getHeightFor = function getHeightFor(input) { + return this.getHeight(input.prevout); +}; + +/** + * Get coins coinbase flag by input. + * @param {Input} input + * @returns {Boolean} + */ + +CoinView.prototype.isCoinbaseFor = function isCoinbaseFor(input) { + return this.isCoinbase(input.prevout); }; /** * Retrieve coins from database. * @method * @param {ChainDB} db - * @param {TX} tx - * @returns {Promise} - Returns {@link Coins}. + * @param {Outpoint} prevout + * @returns {Promise} - Returns {@link CoinEntry}. */ -CoinView.prototype.readCoins = async function readCoins(db, hash) { - let coins = this.map.get(hash); +CoinView.prototype.readCoin = async function readCoin(db, prevout) { + const cache = this.getEntry(prevout); - if (!coins) { - coins = await db.getCoins(hash); + if (cache) + return cache; - if (!coins) - return; + const coin = await db.readCoin(prevout); - this.map.set(hash, coins); - } + if (!coin) + return null; - return coins; + return this.addEntry(prevout, coin); }; /** @@ -324,11 +428,11 @@ CoinView.prototype.readCoins = async function readCoins(db, hash) { * @returns {Promise} - Returns {Boolean}. */ -CoinView.prototype.ensureInputs = async function ensureInputs(db, tx) { +CoinView.prototype.readInputs = async function readInputs(db, tx) { let found = true; - for (let input of tx.inputs) { - if (!(await this.readCoins(db, input.prevout.hash))) + for (const {prevout} of tx.inputs) { + if (!await this.readCoin(db, prevout)) found = false; } @@ -344,32 +448,36 @@ CoinView.prototype.ensureInputs = async function ensureInputs(db, tx) { */ CoinView.prototype.spendInputs = async function spendInputs(db, tx) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let coins = await this.readCoins(db, prevout.hash); + if (tx.inputs.length < 4) { + const jobs = []; - if (!coins) - return false; + for (const {prevout} of tx.inputs) + jobs.push(this.readCoin(db, prevout)); - if (!this.spendFrom(coins, prevout.index)) - return false; - } + const coins = await Promise.all(jobs); - return true; -}; + for (const coin of coins) { + if (!coin || coin.spent) + return false; -/** - * Convert collection to an array. - * @returns {Coins[]} - */ + coin.spent = true; + this.undo.push(coin); + } + + return true; + } -CoinView.prototype.toArray = function toArray() { - let out = []; + for (const {prevout} of tx.inputs) { + const coin = await this.readCoin(db, prevout); - for (let coins of this.map.values()) - out.push(coins); + if (!coin || coin.spent) + return false; + + coin.spent = true; + this.undo.push(coin); + } - return out; + return true; }; /** @@ -382,13 +490,13 @@ CoinView.prototype.getSize = function getSize(tx) { size += tx.inputs.length; - for (let input of tx.inputs) { - let entry = this.getEntry(input); + for (const {prevout} of tx.inputs) { + const coin = this.getEntry(prevout); - if (!entry) + if (!coin) continue; - size += entry.getSize(); + size += coin.getSize(); } return size; @@ -402,25 +510,16 @@ CoinView.prototype.getSize = function getSize(tx) { */ CoinView.prototype.toWriter = function toWriter(bw, tx) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let coins = this.get(prevout.hash); - let entry; + for (const {prevout} of tx.inputs) { + const coin = this.getEntry(prevout); - if (!coins) { - bw.writeU8(0); - continue; - } - - entry = coins.get(prevout.index); - - if (!entry) { + if (!coin) { bw.writeU8(0); continue; } bw.writeU8(1); - entry.toWriter(bw); + coin.toWriter(bw); } return bw; @@ -435,24 +534,13 @@ CoinView.prototype.toWriter = function toWriter(bw, tx) { */ CoinView.prototype.fromReader = function fromReader(br, tx) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let coins, entry; - + for (const {prevout} of tx.inputs) { if (br.readU8() === 0) continue; - coins = this.get(prevout.hash); - - if (!coins) { - coins = new Coins(); - coins.hash = prevout.hash; - coins.coinbase = false; - this.add(coins); - } + const coin = CoinEntry.fromReader(br); - entry = CoinEntry.fromReader(br); - coins.add(prevout.index, entry); + this.addEntry(prevout, coin); } return this; diff --git a/lib/coins/compress.js b/lib/coins/compress.js index 658fc8e35..001649420 100644 --- a/lib/coins/compress.js +++ b/lib/coins/compress.js @@ -20,7 +20,7 @@ const consensus = require('../protocol/consensus'); * Constants */ -const COMPRESS_TYPES = 10; // Space for 4 extra. +const COMPRESS_TYPES = 6; const EMPTY_BUFFER = Buffer.alloc(0); /** @@ -30,8 +30,6 @@ const EMPTY_BUFFER = Buffer.alloc(0); */ function compressScript(script, bw) { - let data; - // Attempt to compress the output scripts. // We can _only_ ever compress them if // they are serialized as minimaldata, as @@ -40,30 +38,30 @@ function compressScript(script, bw) { // P2PKH -> 0 | key-hash // Saves 5 bytes. - if (script.isPubkeyhash(true)) { - data = script.code[2].data; + const pkh = script.getPubkeyhash(true); + if (pkh) { bw.writeU8(0); - bw.writeBytes(data); + bw.writeBytes(pkh); return bw; } // P2SH -> 1 | script-hash // Saves 3 bytes. - if (script.isScripthash()) { - data = script.code[1].data; + const sh = script.getScripthash(); + if (sh) { bw.writeU8(1); - bw.writeBytes(data); + bw.writeBytes(sh); return bw; } // P2PK -> 2-5 | compressed-key // Only works if the key is valid. // Saves up to 35 bytes. - if (script.isPubkey(true)) { - data = script.code[0].data; - if (publicKeyVerify(data)) { - data = compressKey(data); - bw.writeBytes(data); + const pk = script.getPubkey(true); + if (pk) { + if (publicKeyVerify(pk)) { + const key = compressKey(pk); + bw.writeBytes(key); return bw; } } @@ -82,42 +80,44 @@ function compressScript(script, bw) { */ function decompressScript(script, br) { - let size, data; - // Decompress the script. switch (br.readU8()) { - case 0: - data = br.readBytes(20, true); - script.fromPubkeyhash(data); + case 0: { + const hash = br.readBytes(20, true); + script.fromPubkeyhash(hash); break; - case 1: - data = br.readBytes(20, true); - script.fromScripthash(data); + } + case 1: { + const hash = br.readBytes(20, true); + script.fromScripthash(hash); break; + } case 2: case 3: case 4: - case 5: + case 5: { br.offset -= 1; - data = br.readBytes(33, true); + const data = br.readBytes(33, true); // Decompress the key. If this fails, // we have database corruption! - data = decompressKey(data); - script.fromPubkey(data); + const key = decompressKey(data); + script.fromPubkey(key); break; - default: + } + default: { br.offset -= 1; - size = br.readVarint() - COMPRESS_TYPES; + const size = br.readVarint() - COMPRESS_TYPES; if (size > consensus.MAX_SCRIPT_SIZE) { // This violates consensus rules. // We don't need to read it. script.fromNulldata(EMPTY_BUFFER); br.seek(size); } else { - data = br.readBytes(size); + const data = br.readBytes(size); script.fromRaw(data); } break; + } } return script; @@ -129,21 +129,19 @@ function decompressScript(script, br) { */ function sizeScript(script) { - let size, data; - if (script.isPubkeyhash(true)) return 21; if (script.isScripthash()) return 21; - if (script.isPubkey(true)) { - data = script.code[0].data; - if (publicKeyVerify(data)) + const pk = script.getPubkey(true); + if (pk) { + if (publicKeyVerify(pk)) return 33; } - size = 0; + let size = 0; size += encoding.sizeVarint(script.raw.length + COMPRESS_TYPES); size += script.raw.length; @@ -186,63 +184,6 @@ function sizeOutput(output) { return size; } -/** - * Compress an output. - * @param {Coin} coin - * @param {BufferWriter} bw - */ - -function compressCoin(coin, bw) { - bw.writeVarint(coin.value); - compressScript(coin.script, bw); - return bw; -} - -/** - * Decompress a script from buffer reader. - * @param {Coin} coin - * @param {BufferReader} br - */ - -function decompressCoin(coin, br) { - coin.value = br.readVarint(); - decompressScript(coin.script, br); - return coin; -} - -/** - * Skip past a compressed output. - * @param {BufferWriter} bw - * @returns {Number} - */ - -function skipOutput(br) { - let start = br.offset; - - // Skip past the value. - br.skipVarint(); - - // Skip past the compressed scripts. - switch (br.readU8()) { - case 0: - case 1: - br.seek(20); - break; - case 2: - case 3: - case 4: - case 5: - br.seek(32); - break; - default: - br.offset -= 1; - br.seek(br.readVarint() - COMPRESS_TYPES); - break; - } - - return br.offset - start; -} - /** * Compress value using an exponent. Takes advantage of * the fact that many bitcoin values are divisible by 10. @@ -252,19 +193,17 @@ function skipOutput(br) { */ function compressValue(value) { - let exp, last; - if (value === 0) return 0; - exp = 0; + let exp = 0; while (value % 10 === 0 && exp < 9) { value /= 10; exp++; } if (exp < 9) { - last = value % 10; + const last = value % 10; value = (value - last) / 10; return 1 + 10 * (9 * value + last - 1) + exp; } @@ -279,18 +218,18 @@ function compressValue(value) { */ function decompressValue(value) { - let exp, n, last; - if (value === 0) return 0; value--; - exp = value % 10; + let exp = value % 10; + value = (value - exp) / 10; + let n; if (exp < 9) { - last = value % 9; + const last = value % 9; value = (value - last) / 9; n = value * 10 + last + 1; } else { @@ -367,8 +306,7 @@ function compressKey(key) { */ function decompressKey(key) { - let format = key[0]; - let out; + const format = key[0]; assert(key.length === 33); @@ -387,7 +325,7 @@ function decompressKey(key) { } // Decompress the key. - out = secp256k1.publicKeyConvert(key, false); + const out = secp256k1.publicKeyConvert(key, false); // Reset the first byte so as not to // mutate the original buffer. @@ -396,24 +334,14 @@ function decompressKey(key) { return out; } +// Make eslint happy. +compressValue; +decompressValue; + /* * Expose */ -exports.compress = { - output: compressOutput, - coin: compressCoin, - size: sizeOutput, - script: compressScript, - value: compressValue, - key: compressKey -}; - -exports.decompress = { - output: decompressOutput, - coin: decompressCoin, - skip: skipOutput, - script: decompressScript, - value: decompressValue, - key: decompressKey -}; +exports.pack = compressOutput; +exports.unpack = decompressOutput; +exports.size = sizeOutput; diff --git a/lib/coins/undocoins.js b/lib/coins/undocoins.js index a87909502..1396609bc 100644 --- a/lib/coins/undocoins.js +++ b/lib/coins/undocoins.js @@ -9,12 +9,7 @@ const assert = require('assert'); const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); -const encoding = require('../utils/encoding'); -const Output = require('../primitives/output'); -const Coins = require('./coins'); -const compressor = require('./compress'); -const compress = compressor.compress; -const decompress = compressor.decompress; +const CoinEntry = require('../coins/coinentry'); /** * UndoCoins @@ -37,12 +32,11 @@ function UndoCoins() { /** * Push coin entry onto undo coin array. * @param {CoinEntry} + * @returns {Number} */ -UndoCoins.prototype.push = function push(entry) { - let undo = new UndoCoin(); - undo.entry = entry; - this.items.push(undo); +UndoCoins.prototype.push = function push(coin) { + return this.items.push(coin); }; /** @@ -55,7 +49,7 @@ UndoCoins.prototype.getSize = function getSize() { size += 4; - for (let coin of this.items) + for (const coin of this.items) size += coin.getSize(); return size; @@ -67,12 +61,12 @@ UndoCoins.prototype.getSize = function getSize() { */ UndoCoins.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeU32(this.items.length); - for (let coin of this.items) + for (const coin of this.items) coin.toWriter(bw); return bw.render(); @@ -86,11 +80,11 @@ UndoCoins.prototype.toRaw = function toRaw() { */ UndoCoins.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let count = br.readU32(); + const br = new BufferReader(data); + const count = br.readU32(); for (let i = 0; i < count; i++) - this.items.push(UndoCoin.fromReader(br)); + this.items.push(CoinEntry.fromReader(br)); return this; }; @@ -120,217 +114,27 @@ UndoCoins.prototype.isEmpty = function isEmpty() { */ UndoCoins.prototype.commit = function commit() { - let raw = this.toRaw(); + const raw = this.toRaw(); this.items.length = 0; return raw; }; -/** - * Retrieve the last undo coin. - * @returns {UndoCoin} - */ - -UndoCoins.prototype.top = function top() { - return this.items[this.items.length - 1]; -}; - /** * Re-apply undo coins to a view, effectively unspending them. * @param {CoinView} view - * @param {Outpoint} outpoint + * @param {Outpoint} prevout */ -UndoCoins.prototype.apply = function apply(view, outpoint) { - let undo = this.items.pop(); - let hash = outpoint.hash; - let index = outpoint.index; - let coins; +UndoCoins.prototype.apply = function apply(view, prevout) { + const undo = this.items.pop(); assert(undo); - if (undo.height !== -1) { - coins = new Coins(); - - assert(!view.map.has(hash)); - view.map.set(hash, coins); - - coins.hash = hash; - coins.coinbase = undo.coinbase; - coins.height = undo.height; - coins.version = undo.version; - } else { - coins = view.map.get(hash); - assert(coins); - } - - coins.addOutput(index, undo.toOutput()); - - assert(coins.has(index)); -}; - -/** - * UndoCoin - * @alias module:coins.UndoCoin - * @constructor - * @property {CoinEntry|null} entry - * @property {Output|null} output - * @property {Number} version - * @property {Number} height - * @property {Boolean} coinbase - */ - -function UndoCoin() { - this.entry = null; - this.output = null; - this.version = -1; - this.height = -1; - this.coinbase = false; -} - -/** - * Convert undo coin to an output. - * @returns {Output} - */ - -UndoCoin.prototype.toOutput = function toOutput() { - if (!this.output) { - assert(this.entry); - return this.entry.toOutput(); - } - return this.output; -}; - -/** - * Calculate undo coin size. - * @returns {Number} - */ - -UndoCoin.prototype.getSize = function getSize() { - let height = this.height; - let size = 0; - - if (height === -1) - height = 0; - - size += encoding.sizeVarint(height * 2 + (this.coinbase ? 1 : 0)); - - if (this.height !== -1) - size += encoding.sizeVarint(this.version); - - if (this.entry) { - // Cached from spend. - size += this.entry.getSize(); - } else { - size += compress.size(this.output); - } - - return size; -}; - -/** - * Write the undo coin to a buffer writer. - * @param {BufferWriter} bw - */ - -UndoCoin.prototype.toWriter = function toWriter(bw) { - let height = this.height; - - assert(height !== 0); - - if (height === -1) - height = 0; - - bw.writeVarint(height * 2 + (this.coinbase ? 1 : 0)); - - if (this.height !== -1) { - assert(this.version !== -1); - bw.writeVarint(this.version); - } - - if (this.entry) { - // Cached from spend. - this.entry.toWriter(bw); - } else { - compress.output(this.output, bw); - } - - return bw; -}; - -/** - * Serialize the undo coin. - * @returns {Buffer} - */ - -UndoCoin.prototype.toRaw = function toRaw() { - let size = this.getSize(); - return this.toWriter(new StaticWriter(size)).render(); -}; - -/** - * Inject properties from buffer reader. - * @private - * @param {BufferReader} br - * @returns {UndoCoin} - */ - -UndoCoin.prototype.fromReader = function fromReader(br) { - let code = br.readVarint(); - - this.output = new Output(); - - this.height = code / 2 | 0; - - if (this.height === 0) - this.height = -1; - - this.coinbase = (code & 1) !== 0; - - if (this.height !== -1) - this.version = br.readVarint(); - - decompress.output(this.output, br); - - return this; -}; - -/** - * Inject properties from serialized data. - * @private - * @param {Buffer} data - * @returns {UndoCoin} - */ - -UndoCoin.prototype.fromRaw = function fromRaw(data) { - return this.fromReader(new BufferReader(data)); -}; - -/** - * Instantiate undo coin from serialized data. - * @param {Buffer} data - * @returns {UndoCoin} - */ - -UndoCoin.fromReader = function fromReader(br) { - return new UndoCoin().fromReader(br); -}; - -/** - * Instantiate undo coin from serialized data. - * @param {Buffer} data - * @returns {UndoCoin} - */ - -UndoCoin.fromRaw = function fromRaw(data) { - return new UndoCoin().fromRaw(data); + view.addEntry(prevout, undo); }; /* * Expose */ -exports = UndoCoins; -exports.UndoCoins = UndoCoins; -exports.UndoCoin = UndoCoin; - -module.exports = exports; +module.exports = UndoCoins; diff --git a/lib/crypto/aead.js b/lib/crypto/aead.js index 3ebfef9bb..13a3a583d 100644 --- a/lib/crypto/aead.js +++ b/lib/crypto/aead.js @@ -36,7 +36,7 @@ function AEAD() { */ AEAD.prototype.init = function init(key, iv) { - let polyKey = Buffer.allocUnsafe(32); + const polyKey = Buffer.allocUnsafe(32); polyKey.fill(0); this.chacha20.init(key, iv); @@ -63,10 +63,10 @@ AEAD.prototype.init = function init(key, iv) { * @param {Buffer} aad */ -AEAD.prototype.aad = function _aad(aad) { +AEAD.prototype.aad = function aad(data) { assert(this.cipherLen === 0, 'Cannot update aad.'); - this.poly1305.update(aad); - this.aadLen += aad.length; + this.poly1305.update(data); + this.aadLen += data.length; }; /** @@ -122,7 +122,7 @@ AEAD.prototype.auth = function auth(data) { */ AEAD.prototype.finish = function finish() { - let len = Buffer.allocUnsafe(16); + const len = Buffer.allocUnsafe(16); let lo, hi; // The RFC says these are supposed to be @@ -154,14 +154,12 @@ AEAD.prototype.finish = function finish() { */ AEAD.prototype.pad16 = function pad16(size) { - let pad; - size %= 16; if (size === 0) return; - pad = Buffer.allocUnsafe(16 - size); + const pad = Buffer.allocUnsafe(16 - size); pad.fill(0); this.poly1305.update(pad); diff --git a/lib/crypto/aes-browser.js b/lib/crypto/aes-browser.js index 376f469dd..b0924ec66 100644 --- a/lib/crypto/aes-browser.js +++ b/lib/crypto/aes-browser.js @@ -19,66 +19,647 @@ const assert = require('assert'); const AES = exports; -/** - * An AES key object for encrypting - * and decrypting blocks. - * @constructor - * @ignore - * @param {Buffer} key - * @param {Number} bits - */ - -function AESKey(key, bits) { - if (!(this instanceof AESKey)) - return new AESKey(key, bits); - - this.rounds = null; - this.userKey = key; - this.bits = bits; - - switch (this.bits) { - case 128: - this.rounds = 10; - break; - case 192: - this.rounds = 12; - break; - case 256: - this.rounds = 14; - break; - default: - throw new Error('Bad key size.'); - } - - assert(Buffer.isBuffer(key)); - assert(key.length === this.bits / 8); - - this.decryptKey = null; - this.encryptKey = null; -} - -/** - * Destroy the object and zero the keys. +/* + * Tables */ -AESKey.prototype.destroy = function destroy() { - assert(this.userKey, 'Already destroyed.'); - - // User should zero this. - this.userKey = null; +const TE0 = [ + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, + 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, + 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, + 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, + 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, + 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, + 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, + 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, + 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, + 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, + 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, + 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, + 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, + 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, + 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, + 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, + 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, + 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, + 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, + 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, + 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, + 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, + 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, + 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, + 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, + 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, + 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, + 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, + 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, + 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, + 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, + 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, + 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, + 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, + 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, + 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, + 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, + 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, + 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, + 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, + 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, + 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, + 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, + 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, + 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, + 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, + 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +]; - if (this.decryptKey) { - for (let i = 0; i < this.decryptKey.length; i++) - this.decryptKey[i] = 0; - this.decryptKey = null; - } +const TE1 = [ + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, + 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, + 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, + 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, + 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, + 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, + 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, + 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, + 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, + 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, + 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, + 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, + 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, + 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, + 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, + 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, + 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, + 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, + 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, + 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, + 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, + 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, + 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, + 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, + 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, + 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, + 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, + 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, + 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, + 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, + 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, + 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, + 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 +]; - if (this.encryptKey) { - for (let i = 0; i < this.encryptKey.length; i++) - this.encryptKey[i] = 0; - this.encryptKey = null; - } -}; +const TE2 = [ + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, + 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, + 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, + 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, + 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, + 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, + 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, + 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, + 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, + 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, + 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, + 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, + 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, + 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, + 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, + 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, + 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, + 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, + 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, + 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, + 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, + 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, + 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, + 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, + 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, + 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, + 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, + 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, + 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, + 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, + 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, + 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, + 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 +]; + +const TE3 = [ + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, + 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, + 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, + 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, + 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, + 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, + 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, + 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, + 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, + 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, + 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, + 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, + 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, + 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, + 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, + 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, + 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, + 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, + 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, + 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, + 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, + 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, + 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, + 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, + 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, + 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, + 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, + 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, + 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, + 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, + 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, + 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, + 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c +]; + +const TD0 = [ + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, + 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, + 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, + 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, + 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, + 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, + 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, + 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, + 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, + 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, + 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, + 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, + 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, + 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, + 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, + 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, + 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, + 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, + 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, + 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, + 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, + 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, + 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, + 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, + 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, + 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, + 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, + 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, + 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, + 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, + 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, + 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, + 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, + 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, + 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, + 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, + 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, + 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, + 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, + 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, + 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, + 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, + 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, + 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, + 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, + 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, + 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +]; + +const TD1 = [ + 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, + 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, + 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, + 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, + 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, + 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, + 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, + 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, + 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, + 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, + 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, + 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, + 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, + 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, + 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, + 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, + 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, + 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, + 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, + 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, + 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, + 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, + 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, + 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, + 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, + 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, + 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, + 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, + 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, + 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, + 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, + 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, + 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, + 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, + 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, + 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, + 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, + 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, + 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, + 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, + 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, + 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, + 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, + 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, + 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, + 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, + 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, + 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, + 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, + 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, + 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, + 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, + 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, + 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, + 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, + 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, + 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, + 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, + 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, + 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, + 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, + 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, + 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, + 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 +]; + +const TD2 = [ + 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, + 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, + 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, + 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, + 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, + 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, + 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, + 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, + 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, + 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, + 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, + 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, + 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, + 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, + 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, + 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, + 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, + 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, + 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, + 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, + 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, + 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, + 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, + 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, + 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, + 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, + 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, + 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, + 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, + 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, + 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, + 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, + 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, + 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, + 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, + 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, + 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, + 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, + 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, + 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, + 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, + 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, + 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, + 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, + 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, + 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, + 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, + 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, + 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, + 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, + 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, + 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, + 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, + 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, + 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, + 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, + 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, + 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, + 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, + 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, + 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, + 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, + 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, + 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 +]; + +const TD3 = [ + 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, + 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, + 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, + 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, + 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, + 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, + 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, + 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, + 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, + 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, + 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, + 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, + 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, + 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, + 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, + 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, + 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, + 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, + 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, + 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, + 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, + 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, + 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, + 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, + 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, + 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, + 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, + 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, + 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, + 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, + 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, + 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, + 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, + 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, + 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, + 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, + 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, + 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, + 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, + 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, + 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, + 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, + 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, + 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, + 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, + 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, + 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, + 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, + 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, + 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, + 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, + 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, + 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, + 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, + 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, + 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, + 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, + 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, + 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, + 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, + 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, + 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, + 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, + 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 +]; + +const TD4 = [ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +]; + +const RCON = [ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1b000000, 0x36000000 +]; + +/** + * An AES key object for encrypting + * and decrypting blocks. + * @constructor + * @ignore + * @param {Buffer} key + * @param {Number} bits + */ + +function AESKey(key, bits) { + if (!(this instanceof AESKey)) + return new AESKey(key, bits); + + this.rounds = null; + this.userKey = key; + this.bits = bits; + + switch (this.bits) { + case 128: + this.rounds = 10; + break; + case 192: + this.rounds = 12; + break; + case 256: + this.rounds = 14; + break; + default: + throw new Error('Bad key size.'); + } + + assert(Buffer.isBuffer(key)); + assert(key.length === this.bits / 8); + + this.decryptKey = null; + this.encryptKey = null; +} + +/** + * Destroy the object and zero the keys. + */ + +AESKey.prototype.destroy = function destroy() { + assert(this.userKey, 'Already destroyed.'); + + // User should zero this. + this.userKey = null; + + if (this.decryptKey) { + for (let i = 0; i < this.decryptKey.length; i++) + this.decryptKey[i] = 0; + this.decryptKey = null; + } + + if (this.encryptKey) { + for (let i = 0; i < this.encryptKey.length; i++) + this.encryptKey[i] = 0; + this.encryptKey = null; + } +}; /** * Convert the user key into an encryption key. @@ -86,16 +667,14 @@ AESKey.prototype.destroy = function destroy() { */ AESKey.prototype.getEncryptKey = function getEncryptKey() { - let i = 0; - let key, kp; - assert(this.userKey, 'Cannot use key once it is destroyed.'); if (this.encryptKey) return this.encryptKey; - key = new Uint32Array(60); - kp = 0; + const key = new Uint32Array(60); + let kp = 0; + let i = 0; key[kp + 0] = readU32(this.userKey, 0); key[kp + 1] = readU32(this.userKey, 4); @@ -106,7 +685,7 @@ AESKey.prototype.getEncryptKey = function getEncryptKey() { if (this.bits === 128) { for (;;) { - let tmp = key[kp + 3]; + const tmp = key[kp + 3]; key[kp + 4] = key[kp + 0] ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) @@ -130,7 +709,7 @@ AESKey.prototype.getEncryptKey = function getEncryptKey() { if (this.bits === 192) { for (;;) { - let tmp = key[kp + 5]; + const tmp = key[kp + 5]; key[kp + 6] = key[kp + 0] ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) @@ -195,17 +774,15 @@ AESKey.prototype.getEncryptKey = function getEncryptKey() { */ AESKey.prototype.getDecryptKey = function getDecryptKey() { - let kp, enc, key; - assert(this.userKey, 'Cannot use key once it is destroyed.'); if (this.decryptKey) return this.decryptKey; // First, start with an encryption schedule. - enc = this.getEncryptKey(); - key = new Uint32Array(60); - kp = 0; + const enc = this.getEncryptKey(); + const key = new Uint32Array(60); + let kp = 0; for (let i = 0; i < enc.length; i++) key[i] = enc[i]; @@ -264,22 +841,21 @@ AESKey.prototype.getDecryptKey = function getDecryptKey() { */ AESKey.prototype.encryptBlock = function encryptBlock(input) { - let output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3; - assert(this.userKey, 'Cannot use key once it is destroyed.'); - key = this.getEncryptKey(); - kp = 0; + const key = this.getEncryptKey(); + let kp = 0; // Map byte array block to cipher // state and add initial round key. - s0 = readU32(input, 0) ^ key[0]; - s1 = readU32(input, 4) ^ key[1]; - s2 = readU32(input, 8) ^ key[2]; - s3 = readU32(input, 12) ^ key[3]; + let s0 = readU32(input, 0) ^ key[0]; + let s1 = readU32(input, 4) ^ key[1]; + let s2 = readU32(input, 8) ^ key[2]; + let s3 = readU32(input, 12) ^ key[3]; // Nr - 1 full rounds - r = this.rounds >>> 1; + let r = this.rounds >>> 1; + let t0, t1, t2, t3; for (;;) { t0 = TE0[(s0 >>> 24) & 0xff] @@ -353,7 +929,7 @@ AESKey.prototype.encryptBlock = function encryptBlock(input) { ^ (TE1[(t2 >>> 0) & 0xff] & 0x000000ff) ^ key[kp + 3]; - output = Buffer.allocUnsafe(16); + const output = Buffer.allocUnsafe(16); writeU32(output, s0, 0); writeU32(output, s1, 4); writeU32(output, s2, 8); @@ -369,22 +945,21 @@ AESKey.prototype.encryptBlock = function encryptBlock(input) { */ AESKey.prototype.decryptBlock = function decryptBlock(input) { - let output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3; - assert(this.userKey, 'Cannot use AESKey once it is destroyed.'); - key = this.getDecryptKey(); - kp = 0; + const key = this.getDecryptKey(); + let kp = 0; // Map byte array block to cipher // state and add initial round key. - s0 = readU32(input, 0) ^ key[kp + 0]; - s1 = readU32(input, 4) ^ key[kp + 1]; - s2 = readU32(input, 8) ^ key[kp + 2]; - s3 = readU32(input, 12) ^ key[kp + 3]; + let s0 = readU32(input, 0) ^ key[kp + 0]; + let s1 = readU32(input, 4) ^ key[kp + 1]; + let s2 = readU32(input, 8) ^ key[kp + 2]; + let s3 = readU32(input, 12) ^ key[kp + 3]; // Nr - 1 full rounds - r = this.rounds >>> 1; + let r = this.rounds >>> 1; + let t0, t1, t2, t3; for (;;) { t0 = TD0[(s0 >>> 24) & 0xff] @@ -458,7 +1033,7 @@ AESKey.prototype.decryptBlock = function decryptBlock(input) { ^ (TD4[(t0 >>> 0) & 0xff] << 0) ^ key[kp + 3]; - output = Buffer.allocUnsafe(16); + const output = Buffer.allocUnsafe(16); writeU32(output, s0, 0); writeU32(output, s1, 4); writeU32(output, s2, 8); @@ -496,16 +1071,15 @@ function AESCipher(key, iv, bits, mode) { */ AESCipher.prototype.update = function update(data) { - let blocks = []; - let trailing, len; + const blocks = []; if (this.waiting) { data = concat(this.waiting, data); this.waiting = null; } - trailing = data.length % 16; - len = data.length - trailing; + const trailing = data.length % 16; + const len = data.length - trailing; // Encrypt all blocks except for the last. for (let i = 0; i < len; i += 16) { @@ -535,8 +1109,8 @@ AESCipher.prototype.final = function final() { block = Buffer.allocUnsafe(16); block.fill(16); } else { - let left = 16 - this.waiting.length; - let pad = Buffer.allocUnsafe(left); + const left = 16 - this.waiting.length; + const pad = Buffer.allocUnsafe(left); pad.fill(left); block = concat(this.waiting, pad); } @@ -554,779 +1128,194 @@ AESCipher.prototype.final = function final() { }; /** - * AES decipher. - * @constructor - * @ignore - * @param {Buffer} key - * @param {Buffer} iv - * @param {Number} bits - * @param {String} mode - */ - -function AESDecipher(key, iv, bits, mode) { - if (!(this instanceof AESDecipher)) - return new AESDecipher(key, iv, mode); - - assert(mode === 'ecb' || mode === 'cbc', 'Unknown mode.'); - - this.key = new AESKey(key, bits); - this.mode = mode; - this.prev = iv; - this.waiting = null; - this.lastBlock = null; -} - -/** - * Decrypt blocks of data. - * @param {Buffer} data - */ - -AESDecipher.prototype.update = function update(data) { - let blocks = []; - let trailing, len; - - if (this.waiting) { - data = concat(this.waiting, data); - this.waiting = null; - } - - trailing = data.length % 16; - len = data.length - trailing; - - // Decrypt all blocks. - for (let i = 0; i < len; i += 16) { - let chunk = this.prev; - let block; - - this.prev = data.slice(i, i + 16); - - block = this.key.decryptBlock(this.prev); - - if (this.mode === 'cbc') - block = xor(block, chunk); - - blocks.push(block); - } - - if (trailing > 0) - this.waiting = data.slice(len); - - if (this.lastBlock) { - blocks.unshift(this.lastBlock); - this.lastBlock = null; - } - - // Keep a reference to the last - // block for the padding check. - this.lastBlock = blocks.pop(); - - return Buffer.concat(blocks); -}; - -/** - * Finalize the decipher. - * @returns {Buffer} - */ - -AESDecipher.prototype.final = function final() { - let b, n, block; - - this.key.destroy(); - - assert(!this.waiting, 'Bad decrypt (trailing bytes).'); - assert(this.lastBlock, 'Bad decrypt (no data).'); - - // Check padding on the last block. - block = this.lastBlock; - b = 16; - n = block[b - 1]; - - if (n === 0 || n > b) - throw new Error('Bad decrypt (padding).'); - - for (let i = 0; i < n; i++) { - if (block[--b] !== n) - throw new Error('Bad decrypt (padding).'); - } - - // Slice off the padding unless - // the entire block was padding. - if (n === 16) - return Buffer.alloc(0); - - block = block.slice(0, -n); - - return block; -}; - -/** - * Encrypt data with aes 256. - * @param {Buffer} data - * @param {Buffer} key - * @param {Buffer} iv - * @param {String} mode - * @returns {Buffer} - */ - -AES.encrypt = function encrypt(data, key, iv, bits, mode) { - let cipher = new AESCipher(key, iv, bits, mode); - return concat(cipher.update(data), cipher.final()); -}; - -/** - * Decrypt data with aes 256. - * @param {Buffer} data - * @param {Buffer} key - * @param {Buffer|null} iv - * @param {Number} bits - * @param {String} mode - * @returns {Buffer} - */ - -AES.decrypt = function decrypt(data, key, iv, bits, mode) { - let decipher = new AESDecipher(key, iv, bits, mode); - return concat(decipher.update(data), decipher.final()); -}; - -/** - * Encrypt data with aes 256 cbc. - * @param {Buffer} data - * @param {Buffer} key - * @param {Buffer} iv - * @returns {Buffer} - */ - -AES.encipher = function encipher(data, key, iv) { - assert(Buffer.isBuffer(data)); - assert(key.length === 32); - assert(iv.length === 16); - return AES.encrypt(data, key, iv, 256, 'cbc'); -}; - -/** - * Decrypt data with aes 256 cbc. - * @param {Buffer} data + * AES decipher. + * @constructor + * @ignore * @param {Buffer} key * @param {Buffer} iv - * @returns {Buffer} - */ - -AES.decipher = function decipher(data, key, iv) { - assert(Buffer.isBuffer(data)); - assert(key.length === 32); - assert(iv.length === 16); - return AES.decrypt(data, key, iv, 256, 'cbc'); -}; - -/* - * Helpers + * @param {Number} bits + * @param {String} mode */ -function xor(v1, v2) { - let out = Buffer.allocUnsafe(v1.length); - for (let i = 0; i < v1.length; i++) - out[i] = v1[i] ^ v2[i]; - return out; -} - -function readU32(data, i) { - return (data[i + 0] << 24) - ^ (data[i + 1] << 16) - ^ (data[i + 2] << 8) - ^ data[i + 3]; -} +function AESDecipher(key, iv, bits, mode) { + if (!(this instanceof AESDecipher)) + return new AESDecipher(key, iv, mode); -function writeU32(data, value, i) { - data[i + 0] = (value >>> 24) & 0xff; - data[i + 1] = (value >>> 16) & 0xff; - data[i + 2] = (value >>> 8) & 0xff; - data[i + 3] = value & 0xff; -} + assert(mode === 'ecb' || mode === 'cbc', 'Unknown mode.'); -function concat(a, b) { - let data = Buffer.allocUnsafe(a.length + b.length); - a.copy(data, 0); - b.copy(data, a.length); - return data; + this.key = new AESKey(key, bits); + this.mode = mode; + this.prev = iv; + this.waiting = null; + this.lastBlock = null; } -/* - * Tables +/** + * Decrypt blocks of data. + * @param {Buffer} data */ -const TE0 = [ - 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, - 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, - 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, - 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, - 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, - 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, - 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, - 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, - 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, - 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, - 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, - 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, - 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, - 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, - 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, - 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, - 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, - 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, - 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, - 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, - 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, - 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, - 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, - 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, - 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, - 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, - 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, - 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, - 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, - 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, - 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, - 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, - 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, - 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, - 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, - 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, - 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, - 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, - 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, - 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, - 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, - 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, - 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, - 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, - 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, - 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, - 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, - 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, - 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, - 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, - 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, - 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, - 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, - 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, - 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, - 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, - 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, - 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, - 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, - 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, - 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, - 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, - 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, - 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a -]; - -const TE1 = [ - 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, - 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, - 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, - 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, - 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, - 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, - 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, - 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, - 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, - 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, - 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, - 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, - 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, - 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, - 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, - 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, - 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, - 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, - 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, - 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, - 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, - 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, - 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, - 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, - 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, - 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, - 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, - 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, - 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, - 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, - 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, - 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, - 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, - 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, - 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, - 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, - 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, - 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, - 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, - 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, - 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, - 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, - 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, - 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, - 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, - 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, - 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, - 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, - 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, - 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, - 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, - 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, - 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, - 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, - 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, - 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, - 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, - 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, - 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, - 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, - 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, - 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, - 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, - 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 -]; - -const TE2 = [ - 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, - 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, - 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, - 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, - 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, - 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, - 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, - 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, - 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, - 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, - 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, - 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, - 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, - 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, - 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, - 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, - 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, - 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, - 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, - 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, - 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, - 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, - 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, - 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, - 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, - 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, - 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, - 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, - 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, - 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, - 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, - 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, - 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, - 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, - 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, - 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, - 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, - 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, - 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, - 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, - 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, - 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, - 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, - 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, - 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, - 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, - 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, - 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, - 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, - 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, - 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, - 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, - 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, - 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, - 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, - 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, - 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, - 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, - 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, - 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, - 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, - 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, - 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, - 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 -]; +AESDecipher.prototype.update = function update(data) { + const blocks = []; -const TE3 = [ - 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, - 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, - 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, - 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, - 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, - 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, - 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, - 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, - 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, - 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, - 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, - 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, - 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, - 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, - 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, - 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, - 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, - 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, - 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, - 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, - 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, - 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, - 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, - 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, - 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, - 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, - 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, - 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, - 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, - 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, - 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, - 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, - 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, - 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, - 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, - 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, - 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, - 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, - 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, - 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, - 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, - 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, - 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, - 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, - 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, - 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, - 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, - 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, - 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, - 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, - 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, - 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, - 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, - 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, - 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, - 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, - 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, - 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, - 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, - 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, - 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, - 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, - 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, - 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c -]; + if (this.waiting) { + data = concat(this.waiting, data); + this.waiting = null; + } -const TD0 = [ - 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, - 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, - 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, - 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, - 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, - 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, - 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, - 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, - 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, - 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, - 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, - 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, - 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, - 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, - 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, - 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, - 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, - 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, - 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, - 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, - 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, - 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, - 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, - 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, - 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, - 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, - 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, - 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, - 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, - 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, - 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, - 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, - 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, - 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, - 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, - 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, - 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, - 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, - 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, - 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, - 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, - 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, - 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, - 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, - 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, - 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, - 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, - 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, - 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, - 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, - 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, - 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, - 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, - 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, - 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, - 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, - 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, - 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, - 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, - 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, - 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, - 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, - 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, - 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 -]; + const trailing = data.length % 16; + const len = data.length - trailing; -const TD1 = [ - 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, - 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, - 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, - 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, - 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, - 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, - 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, - 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, - 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, - 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, - 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, - 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, - 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, - 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, - 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, - 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, - 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, - 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, - 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, - 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, - 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, - 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, - 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, - 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, - 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, - 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, - 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, - 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, - 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, - 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, - 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, - 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, - 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, - 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, - 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, - 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, - 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, - 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, - 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, - 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, - 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, - 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, - 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, - 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, - 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, - 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, - 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, - 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, - 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, - 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, - 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, - 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, - 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, - 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, - 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, - 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, - 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, - 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, - 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, - 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, - 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, - 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, - 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, - 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 -]; + // Decrypt all blocks. + for (let i = 0; i < len; i += 16) { + const chunk = this.prev; + + this.prev = data.slice(i, i + 16); + + let block = this.key.decryptBlock(this.prev); + + if (this.mode === 'cbc') + block = xor(block, chunk); + + blocks.push(block); + } + + if (trailing > 0) + this.waiting = data.slice(len); + + if (this.lastBlock) { + blocks.unshift(this.lastBlock); + this.lastBlock = null; + } + + // Keep a reference to the last + // block for the padding check. + this.lastBlock = blocks.pop(); + + return Buffer.concat(blocks); +}; + +/** + * Finalize the decipher. + * @returns {Buffer} + */ + +AESDecipher.prototype.final = function final() { + this.key.destroy(); + + assert(!this.waiting, 'Bad decrypt (trailing bytes).'); + assert(this.lastBlock, 'Bad decrypt (no data).'); + + // Check padding on the last block. + let block = this.lastBlock; + let b = 16; + const n = block[b - 1]; + + if (n === 0 || n > b) + throw new Error('Bad decrypt (padding).'); + + for (let i = 0; i < n; i++) { + if (block[--b] !== n) + throw new Error('Bad decrypt (padding).'); + } + + // Slice off the padding unless + // the entire block was padding. + if (n === 16) + return Buffer.alloc(0); + + block = block.slice(0, -n); -const TD2 = [ - 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, - 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, - 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, - 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, - 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, - 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, - 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, - 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, - 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, - 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, - 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, - 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, - 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, - 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, - 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, - 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, - 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, - 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, - 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, - 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, - 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, - 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, - 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, - 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, - 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, - 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, - 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, - 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, - 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, - 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, - 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, - 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, - 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, - 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, - 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, - 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, - 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, - 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, - 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, - 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, - 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, - 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, - 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, - 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, - 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, - 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, - 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, - 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, - 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, - 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, - 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, - 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, - 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, - 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, - 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, - 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, - 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, - 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, - 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, - 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, - 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, - 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, - 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, - 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 -]; + return block; +}; -const TD3 = [ - 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, - 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, - 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, - 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, - 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, - 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, - 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, - 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, - 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, - 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, - 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, - 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, - 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, - 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, - 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, - 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, - 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, - 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, - 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, - 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, - 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, - 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, - 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, - 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, - 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, - 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, - 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, - 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, - 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, - 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, - 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, - 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, - 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, - 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, - 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, - 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, - 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, - 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, - 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, - 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, - 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, - 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, - 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, - 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, - 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, - 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, - 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, - 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, - 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, - 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, - 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, - 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, - 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, - 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, - 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, - 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, - 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, - 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, - 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, - 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, - 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, - 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, - 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, - 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 -]; +/** + * Encrypt data with aes 256. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer} iv + * @param {String} mode + * @returns {Buffer} + */ -const TD4 = [ - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, - 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, - 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, - 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, - 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, - 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, - 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, - 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, - 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, - 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, - 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, - 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, - 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, - 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, - 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, - 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d -]; +AES.encrypt = function encrypt(data, key, iv, bits, mode) { + const cipher = new AESCipher(key, iv, bits, mode); + return concat(cipher.update(data), cipher.final()); +}; -const RCON = [ - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000 -]; +/** + * Decrypt data with aes 256. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer|null} iv + * @param {Number} bits + * @param {String} mode + * @returns {Buffer} + */ + +AES.decrypt = function decrypt(data, key, iv, bits, mode) { + const decipher = new AESDecipher(key, iv, bits, mode); + return concat(decipher.update(data), decipher.final()); +}; + +/** + * Encrypt data with aes 256 cbc. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer} iv + * @returns {Buffer} + */ + +AES.encipher = function encipher(data, key, iv) { + assert(Buffer.isBuffer(data)); + assert(key.length === 32); + assert(iv.length === 16); + return AES.encrypt(data, key, iv, 256, 'cbc'); +}; + +/** + * Decrypt data with aes 256 cbc. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer} iv + * @returns {Buffer} + */ + +AES.decipher = function decipher(data, key, iv) { + assert(Buffer.isBuffer(data)); + assert(key.length === 32); + assert(iv.length === 16); + return AES.decrypt(data, key, iv, 256, 'cbc'); +}; + +/* + * Helpers + */ + +function xor(v1, v2) { + const out = Buffer.allocUnsafe(v1.length); + for (let i = 0; i < v1.length; i++) + out[i] = v1[i] ^ v2[i]; + return out; +} + +function readU32(data, i) { + return (data[i + 0] << 24) + ^ (data[i + 1] << 16) + ^ (data[i + 2] << 8) + ^ data[i + 3]; +} + +function writeU32(data, value, i) { + data[i + 0] = (value >>> 24) & 0xff; + data[i + 1] = (value >>> 16) & 0xff; + data[i + 2] = (value >>> 8) & 0xff; + data[i + 3] = value & 0xff; +} + +function concat(a, b) { + const data = Buffer.allocUnsafe(a.length + b.length); + a.copy(data, 0); + b.copy(data, a.length); + return data; +} diff --git a/lib/crypto/aes.js b/lib/crypto/aes.js index 1bec17298..15618fcd4 100644 --- a/lib/crypto/aes.js +++ b/lib/crypto/aes.js @@ -22,8 +22,8 @@ const native = require('../native').binding; */ exports.encipher = function encipher(data, key, iv) { - let cipher = crypto.createCipheriv('aes-256-cbc', key, iv); - return Buffer.concat([cipher.update(data), cipher.final()]); + const ctx = crypto.createCipheriv('aes-256-cbc', key, iv); + return Buffer.concat([ctx.update(data), ctx.final()]); }; /** @@ -34,10 +34,10 @@ exports.encipher = function encipher(data, key, iv) { * @returns {Buffer} */ -exports.decipher = function _decipher(data, key, iv) { - let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); +exports.decipher = function decipher(data, key, iv) { + const ctx = crypto.createDecipheriv('aes-256-cbc', key, iv); try { - return Buffer.concat([decipher.update(data), decipher.final()]); + return Buffer.concat([ctx.update(data), ctx.final()]); } catch (e) { throw new Error('Bad key for decryption.'); } diff --git a/lib/crypto/ccmp.js b/lib/crypto/ccmp.js index 29193fb09..dfc4ced17 100644 --- a/lib/crypto/ccmp.js +++ b/lib/crypto/ccmp.js @@ -6,6 +6,8 @@ 'use strict'; +const assert = require('assert'); + /** * memcmp in constant time (can only return true or false). * This protects us against timing attacks when @@ -19,18 +21,13 @@ */ module.exports = function ccmp(a, b) { - let res; - - if (!Buffer.isBuffer(a)) - return false; - - if (!Buffer.isBuffer(b)) - return false; + assert(Buffer.isBuffer(a)); + assert(Buffer.isBuffer(b)); if (b.length === 0) return a.length === 0; - res = a.length ^ b.length; + let res = a.length ^ b.length; for (let i = 0; i < a.length; i++) res |= a[i] ^ b[i % b.length]; diff --git a/lib/crypto/chacha20.js b/lib/crypto/chacha20.js index c9e30e516..42e8db164 100644 --- a/lib/crypto/chacha20.js +++ b/lib/crypto/chacha20.js @@ -148,13 +148,11 @@ ChaCha20.prototype.encrypt = function encrypt(data) { */ ChaCha20.prototype.setCounter = function setCounter(counter) { - let lo, hi; - if (!counter) counter = 0; - lo = counter % 0x100000000; - hi = (counter - lo) / 0x100000000; + const lo = counter % 0x100000000; + const hi = (counter - lo) / 0x100000000; this.state[12] = lo; @@ -168,8 +166,8 @@ ChaCha20.prototype.setCounter = function setCounter(counter) { */ ChaCha20.prototype.getCounter = function getCounter() { - let lo = this.state[12]; - let hi = this.state[13]; + const lo = this.state[12]; + const hi = this.state[13]; if (this.ivSize === 64) return hi * 0x100000000 + lo; return lo; diff --git a/lib/crypto/digest-browser.js b/lib/crypto/digest-browser.js index 95a94e455..4f7f45576 100644 --- a/lib/crypto/digest-browser.js +++ b/lib/crypto/digest-browser.js @@ -13,7 +13,7 @@ const assert = require('assert'); const hashjs = require('hash.js'); -const sha256 = require('./sha256'); +const SHA256 = require('./sha256'); const POOL64 = Buffer.allocUnsafe(64); /** @@ -23,17 +23,15 @@ const POOL64 = Buffer.allocUnsafe(64); * @returns {Buffer} */ -exports.hash = function _hash(alg, data) { - let hash; - +exports.hash = function hash(alg, data) { if (alg === 'sha256') - return sha256.digest(data); + return SHA256.digest(data); - hash = hashjs[alg]; + const algo = hashjs[alg]; - assert(hash != null, 'Unknown algorithm.'); + assert(algo != null, 'Unknown algorithm.'); - return Buffer.from(hash().update(data).digest()); + return Buffer.from(algo().update(data).digest()); }; /** @@ -62,8 +60,8 @@ exports.sha1 = function sha1(data) { * @returns {Buffer} */ -exports.sha256 = function _sha256(data) { - return sha256.digest(data); +exports.sha256 = function sha256(data) { + return SHA256.digest(data); }; /** @@ -73,7 +71,7 @@ exports.sha256 = function _sha256(data) { */ exports.hash160 = function hash160(data) { - return exports.hash('ripemd160', sha256.digest(data)); + return exports.hash('ripemd160', SHA256.digest(data)); }; /** @@ -83,7 +81,7 @@ exports.hash160 = function hash160(data) { */ exports.hash256 = function hash256(data) { - return sha256.hash256(data); + return SHA256.hash256(data); }; /** @@ -94,7 +92,7 @@ exports.hash256 = function hash256(data) { */ exports.root256 = function root256(left, right) { - let data = POOL64; + const data = POOL64; assert(left.length === 32); assert(right.length === 32); @@ -113,13 +111,12 @@ exports.root256 = function root256(left, right) { * @returns {Buffer} HMAC */ -exports.hmac = function _hmac(alg, data, key) { - let hash = hashjs[alg]; - let hmac; +exports.hmac = function hmac(alg, data, key) { + const algo = hashjs[alg]; - assert(hash != null, 'Unknown algorithm.'); + assert(algo != null, 'Unknown algorithm.'); - hmac = hashjs.hmac(hash, key); + const ctx = hashjs.hmac(algo, key); - return Buffer.from(hmac.update(data).digest()); + return Buffer.from(ctx.update(data).digest()); }; diff --git a/lib/crypto/digest.js b/lib/crypto/digest.js index 9a23cb6ff..d65d72a5a 100644 --- a/lib/crypto/digest.js +++ b/lib/crypto/digest.js @@ -84,7 +84,7 @@ exports.hash256 = function hash256(data) { */ exports.root256 = function root256(left, right) { - let data = POOL64; + const data = POOL64; assert(left.length === 32); assert(right.length === 32); @@ -103,9 +103,9 @@ exports.root256 = function root256(left, right) { * @returns {Buffer} HMAC */ -exports.hmac = function _hmac(alg, data, key) { - let hmac = crypto.createHmac(alg, key); - return hmac.update(data).digest(); +exports.hmac = function hmac(alg, data, key) { + const ctx = crypto.createHmac(alg, key); + return ctx.update(data).digest(); }; if (native) { diff --git a/lib/crypto/ecdsa.js b/lib/crypto/ecdsa.js index 8c5540d89..4639156b0 100644 --- a/lib/crypto/ecdsa.js +++ b/lib/crypto/ecdsa.js @@ -25,16 +25,14 @@ const digest = require('./digest'); */ exports.verify = function verify(curve, alg, msg, sig, key) { - let ec, hash; - assert(typeof curve === 'string', 'No curve selected.'); assert(typeof alg === 'string', 'No algorithm selected.'); assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(sig)); assert(Buffer.isBuffer(key)); - ec = elliptic.ec(curve); - hash = digest.hash(alg, msg); + const ec = elliptic.ec(curve); + const hash = digest.hash(alg, msg); try { return ec.verify(hash, sig, key); @@ -54,17 +52,14 @@ exports.verify = function verify(curve, alg, msg, sig, key) { */ exports.sign = function sign(curve, alg, msg, key) { - let ec, hash, sig; - assert(typeof curve === 'string', 'No curve selected.'); assert(typeof alg === 'string', 'No algorithm selected.'); assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(key)); - ec = elliptic.ec(curve); - hash = digest.hash(alg, msg); - - sig = ec.sign(hash, key, { canonical: true }); + const ec = elliptic.ec(curve); + const hash = digest.hash(alg, msg); + const sig = ec.sign(hash, key, { canonical: true }); return Buffer.from(sig.toDER()); }; diff --git a/lib/crypto/hkdf.js b/lib/crypto/hkdf.js index 02de4e1a9..64f4c9df3 100644 --- a/lib/crypto/hkdf.js +++ b/lib/crypto/hkdf.js @@ -34,24 +34,24 @@ exports.extract = function extract(ikm, key, alg) { */ exports.expand = function expand(prk, info, len, alg) { - let size = digest.hash(alg, Buffer.alloc(0)).length; - let blocks = Math.ceil(len / size); - let okm, buf, out; + const size = digest.hash(alg, Buffer.alloc(0)).length; + const blocks = Math.ceil(len / size); if (blocks > 255) throw new Error('Too many blocks.'); - okm = Buffer.allocUnsafe(len); + const okm = Buffer.allocUnsafe(len); if (blocks === 0) return okm; - buf = Buffer.allocUnsafe(size + info.length + 1); + const buf = Buffer.allocUnsafe(size + info.length + 1); // First round: info.copy(buf, size); buf[buf.length - 1] = 1; - out = digest.hmac(alg, buf.slice(size), prk); + + let out = digest.hmac(alg, buf.slice(size), prk); out.copy(okm, 0); for (let i = 1; i < blocks; i++) { diff --git a/lib/crypto/hmac-drbg.js b/lib/crypto/hmac-drbg.js index 068e9679f..559807941 100644 --- a/lib/crypto/hmac-drbg.js +++ b/lib/crypto/hmac-drbg.js @@ -47,7 +47,7 @@ HmacDRBG.prototype.init = function init(entropy, nonce, pers) { }; HmacDRBG.prototype.reseed = function reseed(entropy, nonce, pers) { - let seed = POOL112; + const seed = POOL112; assert(Buffer.isBuffer(entropy)); assert(Buffer.isBuffer(nonce)); @@ -66,7 +66,7 @@ HmacDRBG.prototype.reseed = function reseed(entropy, nonce, pers) { }; HmacDRBG.prototype.iterate = function iterate() { - let data = POOL33; + const data = POOL33; this.V.copy(data, 0); data[HASH_SIZE] = 0x00; @@ -76,7 +76,7 @@ HmacDRBG.prototype.iterate = function iterate() { }; HmacDRBG.prototype.update = function update(seed) { - let data = POOL145; + const data = POOL145; assert(Buffer.isBuffer(seed)); assert(seed.length === HASH_SIZE * 2 + 48); @@ -95,12 +95,12 @@ HmacDRBG.prototype.update = function update(seed) { }; HmacDRBG.prototype.generate = function generate(len) { - let data = Buffer.allocUnsafe(len); - let pos = 0; - if (this.rounds > RESEED_INTERVAL) throw new Error('Reseed is required.'); + const data = Buffer.allocUnsafe(len); + let pos = 0; + while (pos < len) { this.V = digest.hmac(HASH_ALG, this.V, this.K); this.V.copy(data, pos); diff --git a/lib/crypto/merkle.js b/lib/crypto/merkle.js index 36ef202ea..1adeeca1e 100644 --- a/lib/crypto/merkle.js +++ b/lib/crypto/merkle.js @@ -21,7 +21,7 @@ const digest = require('./digest'); */ exports.createTree = function createTree(leaves) { - let nodes = leaves; + const nodes = leaves; let size = leaves.length; let malleated = false; let i = 0; @@ -33,17 +33,16 @@ exports.createTree = function createTree(leaves) { while (size > 1) { for (let j = 0; j < size; j += 2) { - let k = Math.min(j + 1, size - 1); - let left = nodes[i + j]; - let right = nodes[i + k]; - let hash; + const k = Math.min(j + 1, size - 1); + const left = nodes[i + j]; + const right = nodes[i + k]; if (k === j + 1 && k + 1 === size && left.equals(right)) { malleated = true; } - hash = digest.root256(left, right); + const hash = digest.root256(left, right); nodes.push(hash); } @@ -62,8 +61,8 @@ exports.createTree = function createTree(leaves) { */ exports.createRoot = function createRoot(leaves) { - let [nodes, malleated] = exports.createTree(leaves); - let root = nodes[nodes.length - 1]; + const [nodes, malleated] = exports.createTree(leaves); + const root = nodes[nodes.length - 1]; return [root, malleated]; }; @@ -76,12 +75,12 @@ exports.createRoot = function createRoot(leaves) { exports.createBranch = function createBranch(index, leaves) { let size = leaves.length; - let [nodes] = exports.createTree(leaves); - let branch = []; + const [nodes] = exports.createTree(leaves); + const branch = []; let i = 0; while (size > 1) { - let j = Math.min(index ^ 1, size - 1); + const j = Math.min(index ^ 1, size - 1); branch.push(nodes[i + j]); index >>>= 1; i += size; @@ -103,7 +102,7 @@ exports.createBranch = function createBranch(index, leaves) { exports.deriveRoot = function deriveRoot(hash, branch, index) { let root = hash; - for (let hash of branch) { + for (const hash of branch) { if (index & 1) root = digest.root256(hash, root); else diff --git a/lib/crypto/pbkdf2-browser.js b/lib/crypto/pbkdf2-browser.js index a2407f482..92b879cfb 100644 --- a/lib/crypto/pbkdf2-browser.js +++ b/lib/crypto/pbkdf2-browser.js @@ -26,19 +26,18 @@ const subtle = crypto.subtle || {}; */ exports.derive = function derive(key, salt, iter, len, alg) { - let size = digest.hash(alg, Buffer.alloc(0)).length; - let blocks = Math.ceil(len / size); - let out = Buffer.allocUnsafe(len); - let buf = Buffer.allocUnsafe(salt.length + 4); - let block = Buffer.allocUnsafe(size); + const size = digest.hash(alg, Buffer.alloc(0)).length; + const blocks = Math.ceil(len / size); + const out = Buffer.allocUnsafe(len); + const buf = Buffer.allocUnsafe(salt.length + 4); + const block = Buffer.allocUnsafe(size); let pos = 0; salt.copy(buf, 0); for (let i = 0; i < blocks; i++) { - let mac; buf.writeUInt32BE(i + 1, salt.length, true); - mac = digest.hmac(alg, buf, key); + let mac = digest.hmac(alg, buf, key); mac.copy(block, 0); for (let j = 1; j < iter; j++) { mac = digest.hmac(alg, mac, key); @@ -63,22 +62,21 @@ exports.derive = function derive(key, salt, iter, len, alg) { */ exports.deriveAsync = async function deriveAsync(key, salt, iter, len, alg) { - let algo = { name: 'PBKDF2' }; - let use = ['deriveBits']; - let options, imported, data; + const algo = { name: 'PBKDF2' }; + const use = ['deriveBits']; if (!subtle.importKey || !subtle.deriveBits) return exports.derive(key, salt, iter, len, alg); - options = { + const options = { name: 'PBKDF2', salt: salt, iterations: iter, hash: getHash(alg) }; - imported = await subtle.importKey('raw', key, algo, false, use); - data = await subtle.deriveBits(options, imported, len * 8); + const imported = await subtle.importKey('raw', key, algo, false, use); + const data = await subtle.deriveBits(options, imported, len * 8); return Buffer.from(data); }; diff --git a/lib/crypto/poly1305.js b/lib/crypto/poly1305.js index d6a3d6329..50ecdda94 100644 --- a/lib/crypto/poly1305.js +++ b/lib/crypto/poly1305.js @@ -10,7 +10,7 @@ const native = require('../native').binding; /** * Poly1305 (used for bip151) - * @alias module:crypto.Poly1305 + * @alias module:crypto/chachapoly.Poly1305 * @constructor * @see https://github.com/floodyberry/poly1305-donna * @see https://tools.ietf.org/html/rfc7539#section-2.5 @@ -35,14 +35,14 @@ function Poly1305() { Poly1305.prototype.init = function init(key) { // r &= 0xffffffc0ffffffc0ffffffc0fffffff - let t0 = key.readUInt16LE(0, true); - let t1 = key.readUInt16LE(2, true); - let t2 = key.readUInt16LE(4, true); - let t3 = key.readUInt16LE(6, true); - let t4 = key.readUInt16LE(8, true); - let t5 = key.readUInt16LE(10, true); - let t6 = key.readUInt16LE(12, true); - let t7 = key.readUInt16LE(14, true); + const t0 = key.readUInt16LE(0, true); + const t1 = key.readUInt16LE(2, true); + const t2 = key.readUInt16LE(4, true); + const t3 = key.readUInt16LE(6, true); + const t4 = key.readUInt16LE(8, true); + const t5 = key.readUInt16LE(10, true); + const t6 = key.readUInt16LE(12, true); + const t7 = key.readUInt16LE(14, true); this.r[0] = t0 & 0x1fff; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; @@ -75,20 +75,19 @@ Poly1305.prototype.init = function init(key) { */ Poly1305.prototype.blocks = function blocks(data, bytes, m) { - let hibit = this.fin ? 0 : (1 << 11); // 1 << 128 - let d = new Uint32Array(10); + const hibit = this.fin ? 0 : (1 << 11); // 1 << 128 + const d = new Uint32Array(10); while (bytes >= 16) { // h += m[i] - let t0 = data.readUInt16LE(m + 0, true); - let t1 = data.readUInt16LE(m + 2, true); - let t2 = data.readUInt16LE(m + 4, true); - let t3 = data.readUInt16LE(m + 6, true); - let t4 = data.readUInt16LE(m + 8, true); - let t5 = data.readUInt16LE(m + 10, true); - let t6 = data.readUInt16LE(m + 12, true); - let t7 = data.readUInt16LE(m + 14, true); - let c = 0; + const t0 = data.readUInt16LE(m + 0, true); + const t1 = data.readUInt16LE(m + 2, true); + const t2 = data.readUInt16LE(m + 4, true); + const t3 = data.readUInt16LE(m + 6, true); + const t4 = data.readUInt16LE(m + 8, true); + const t5 = data.readUInt16LE(m + 10, true); + const t6 = data.readUInt16LE(m + 12, true); + const t7 = data.readUInt16LE(m + 14, true); this.h[0] += t0 & 0x1fff; this.h[1] += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; @@ -102,14 +101,19 @@ Poly1305.prototype.blocks = function blocks(data, bytes, m) { this.h[9] += ((t7 >>> 5)) | hibit; // h *= r, (partial) h %= p + let c = 0; for (let i = 0; i < 10; i++) { d[i] = c; for (let j = 0; j < 10; j++) { + let a = this.h[j]; + if (j <= i) - d[i] += this.r[i - j]; + a *= this.r[i - j]; else - d[i] += 5 * this.r[i + 10 - j]; + a *= 5 * this.r[i + 10 - j]; + + d[i] += a; // Sum(h[i] * r[i] * 5) will overflow slightly // above 6 products with an unclamped r, so @@ -172,7 +176,7 @@ Poly1305.prototype.update = function update(data) { // process full blocks if (bytes >= 16) { - let want = bytes & ~(16 - 1); + const want = bytes & ~(16 - 1); this.blocks(data, want, m); m += want; bytes -= want; @@ -192,9 +196,8 @@ Poly1305.prototype.update = function update(data) { */ Poly1305.prototype.finish = function finish() { - let mac = Buffer.allocUnsafe(16); - let g = new Uint16Array(10); - let c, mask, f; + const mac = Buffer.allocUnsafe(16); + const g = new Uint16Array(10); // process the remaining block if (this.leftover) { @@ -207,7 +210,7 @@ Poly1305.prototype.finish = function finish() { } // fully carry h - c = this.h[1] >>> 13; + let c = this.h[1] >>> 13; this.h[1] &= 0x1fff; for (let i = 2; i < 10; i++) { this.h[i] += c; @@ -233,7 +236,7 @@ Poly1305.prototype.finish = function finish() { } // select h if h < p, or h + -p if h >= p - mask = (c ^ 1) - 1; + let mask = (c ^ 1) - 1; for (let i = 0; i < 10; i++) g[i] &= mask; mask = ~mask; @@ -252,7 +255,7 @@ Poly1305.prototype.finish = function finish() { this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5)) & 0xffff; // mac = (h + pad) % (2^128) - f = this.h[0] + this.pad[0]; + let f = this.h[0] + this.pad[0]; this.h[0] = f; for (let i = 1; i < 8; i++) { f = this.h[i] + this.pad[i] + (f >>> 16); @@ -283,7 +286,7 @@ Poly1305.prototype.finish = function finish() { */ Poly1305.auth = function auth(msg, key) { - let poly = new Poly1305(); + const poly = new Poly1305(); poly.init(key); poly.update(msg); return poly.finish(); diff --git a/lib/crypto/random-browser.js b/lib/crypto/random-browser.js index fbaf0092f..0f102b055 100644 --- a/lib/crypto/random-browser.js +++ b/lib/crypto/random-browser.js @@ -20,7 +20,7 @@ const crypto = global.crypto || global.msCrypto || {}; */ exports.randomBytes = function randomBytes(size) { - let data = new Uint8Array(size); + const data = new Uint8Array(size); crypto.getRandomValues(data); return Buffer.from(data.buffer); }; @@ -28,7 +28,7 @@ exports.randomBytes = function randomBytes(size) { if (!crypto.getRandomValues) { // Out of luck here. Use bad randomness for now. exports.randomBytes = function randomBytes(size) { - let data = Buffer.allocUnsafe(size); + const data = Buffer.allocUnsafe(size); for (let i = 0; i < data.length; i++) data[i] = Math.floor(Math.random() * 256); @@ -58,6 +58,6 @@ exports.randomInt = function randomInt() { */ exports.randomRange = function randomRange(min, max) { - let num = exports.randomInt(); + const num = exports.randomInt(); return Math.floor((num / 0x100000000) * (max - min) + min); }; diff --git a/lib/crypto/random.js b/lib/crypto/random.js index f2280a9ff..e98c29198 100644 --- a/lib/crypto/random.js +++ b/lib/crypto/random.js @@ -42,6 +42,6 @@ exports.randomInt = function randomInt() { */ exports.randomRange = function randomRange(min, max) { - let num = exports.randomInt(); + const num = exports.randomInt(); return Math.floor((num / 0x100000000) * (max - min) + min); }; diff --git a/lib/crypto/rsa-browser.js b/lib/crypto/rsa-browser.js index 897ec9b5e..6029fafc8 100644 --- a/lib/crypto/rsa-browser.js +++ b/lib/crypto/rsa-browser.js @@ -44,33 +44,31 @@ rsa.prefixes = { */ rsa.verify = function verify(alg, msg, sig, key) { - let prefix = rsa.prefixes[alg]; - let hash, len, pub; - let N, e, k, m, em, ok; - assert(typeof alg === 'string', 'No algorithm selected.'); assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(sig)); assert(Buffer.isBuffer(key)); + const prefix = rsa.prefixes[alg]; + if (!prefix) throw new Error('Unknown PKCS prefix.'); - hash = digest.hash(alg, msg); - len = prefix.length + hash.length; - pub = ASN1.parseRSAPublic(key); + const hash = digest.hash(alg, msg); + const len = prefix.length + hash.length; + const pub = ASN1.parseRSAPublic(key); - N = new BN(pub.modulus); - e = new BN(pub.publicExponent); - k = Math.ceil(N.bitLength() / 8); + const N = new BN(pub.modulus); + const e = new BN(pub.publicExponent); + const k = Math.ceil(N.bitLength() / 8); if (k < len + 11) throw new Error('Message too long.'); - m = rsa.encrypt(N, e, sig); - em = leftpad(m, k); + const m = rsa.encrypt(N, e, sig); + const em = leftpad(m, k); - ok = ceq(em[0], 0x00); + let ok = ceq(em[0], 0x00); ok &= ceq(em[1], 0x01); ok &= ccmp(em.slice(k - hash.length, k), hash); ok &= ccmp(em.slice(k - len, k - hash.length), prefix); @@ -91,29 +89,27 @@ rsa.verify = function verify(alg, msg, sig, key) { */ rsa.sign = function sign(alg, msg, key) { - let prefix = rsa.prefixes[alg]; - let hash, len, priv; - let N, D, k, em; - assert(typeof alg === 'string', 'No algorithm selected.'); assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(key)); + const prefix = rsa.prefixes[alg]; + if (!prefix) throw new Error('Unknown PKCS prefix.'); - hash = digest.hash(alg, msg); - len = prefix.length + hash.length; - priv = ASN1.parseRSAPrivate(key); + const hash = digest.hash(alg, msg); + const len = prefix.length + hash.length; + const priv = ASN1.parseRSAPrivate(key); - N = new BN(priv.modulus); - D = new BN(priv.privateExponent); - k = Math.ceil(N.bitLength() / 8); + const N = new BN(priv.modulus); + const D = new BN(priv.privateExponent); + const k = Math.ceil(N.bitLength() / 8); if (k < len + 11) throw new Error('Message too long.'); - em = Buffer.allocUnsafe(k); + const em = Buffer.allocUnsafe(k); em.fill(0); em[1] = 0x01; @@ -135,7 +131,7 @@ rsa.sign = function sign(alg, msg, key) { */ rsa.decrypt = function decrypt(N, D, m) { - let c = new BN(m); + const c = new BN(m); if (c.cmp(N) > 0) throw new Error('Cannot decrypt.'); @@ -144,7 +140,7 @@ rsa.decrypt = function decrypt(N, D, m) { .toRed(BN.red(N)) .redPow(D) .fromRed() - .toBuffer('be'); + .toArrayLike(Buffer, 'be'); }; /** @@ -160,7 +156,7 @@ rsa.encrypt = function encrypt(N, e, m) { .toRed(BN.red(N)) .redPow(e) .fromRed() - .toBuffer('be'); + .toArrayLike(Buffer, 'be'); }; /* @@ -169,12 +165,11 @@ rsa.encrypt = function encrypt(N, e, m) { function leftpad(input, size) { let n = input.length; - let out; if (n > size) n = size; - out = Buffer.allocUnsafe(size); + const out = Buffer.allocUnsafe(size); out.fill(0); input.copy(out, out.length - n); diff --git a/lib/crypto/rsa.js b/lib/crypto/rsa.js index 903049bb3..c8a3b57c2 100644 --- a/lib/crypto/rsa.js +++ b/lib/crypto/rsa.js @@ -24,17 +24,14 @@ const PEM = require('../utils/pem'); */ exports.verify = function verify(alg, msg, sig, key) { - let pem, name, ctx; - assert(typeof alg === 'string', 'No algorithm selected.'); assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(sig)); assert(Buffer.isBuffer(key)); - name = normalizeAlg('rsa', alg); - pem = PEM.encode(key, 'rsa', 'public key'); - - ctx = crypto.createVerify(name); + const name = normalizeAlg('rsa', alg); + const pem = PEM.encode(key, 'rsa', 'public key'); + const ctx = crypto.createVerify(name); try { ctx.update(msg); @@ -53,16 +50,14 @@ exports.verify = function verify(alg, msg, sig, key) { */ exports.sign = function sign(alg, msg, key) { - let pem, name, ctx; - assert(typeof alg === 'string', 'No algorithm selected.'); assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(key)); - name = normalizeAlg('rsa', alg); - pem = PEM.encode(key, 'rsa', 'private key'); + const name = normalizeAlg('rsa', alg); + const pem = PEM.encode(key, 'rsa', 'private key'); + const ctx = crypto.createSign(name); - ctx = crypto.createSign(name); ctx.update(msg); return ctx.sign(pem); diff --git a/lib/crypto/schnorr.js b/lib/crypto/schnorr.js index 74878277a..6aa21b0e4 100644 --- a/lib/crypto/schnorr.js +++ b/lib/crypto/schnorr.js @@ -28,9 +28,9 @@ const schnorr = exports; * @returns {Buffer} */ -schnorr.hash = function _hash(msg, r) { - let R = r.toBuffer('be', 32); - let B = POOL64; +schnorr.hash = function hash(msg, r) { + const R = r.toArrayLike(Buffer, 'be', 32); + const B = POOL64; R.copy(B, 0); msg.copy(B, 32); @@ -49,8 +49,6 @@ schnorr.hash = function _hash(msg, r) { */ schnorr.trySign = function trySign(msg, prv, k, pn) { - let r, h, s; - if (prv.cmpn(0) === 0) throw new Error('Bad private key.'); @@ -63,7 +61,7 @@ schnorr.trySign = function trySign(msg, prv, k, pn) { if (k.cmp(curve.n) >= 0) return null; - r = curve.g.mul(k); + let r = curve.g.mul(k); if (pn) r = r.add(pn); @@ -73,7 +71,7 @@ schnorr.trySign = function trySign(msg, prv, k, pn) { k = curve.n.sub(k); } - h = schnorr.hash(msg, r.getX()); + const h = schnorr.hash(msg, r.getX()); if (h.cmpn(0) === 0) return null; @@ -81,7 +79,7 @@ schnorr.trySign = function trySign(msg, prv, k, pn) { if (h.cmp(curve.n) >= 0) return null; - s = h.imul(prv); + let s = h.imul(prv); s = k.isub(s); s = s.umod(curve.n); @@ -100,16 +98,17 @@ schnorr.trySign = function trySign(msg, prv, k, pn) { */ schnorr.sign = function sign(msg, key, pubNonce) { - let prv = new BN(key); - let drbg = schnorr.drbg(msg, key, pubNonce); - let len = curve.n.byteLength(); - let k, pn, sig; + const prv = new BN(key); + const drbg = schnorr.drbg(msg, key, pubNonce); + const len = curve.n.byteLength(); + let pn; if (pubNonce) pn = curve.decodePoint(pubNonce); + let sig; while (!sig) { - k = new BN(drbg.generate(len)); + const k = new BN(drbg.generate(len)); sig = schnorr.trySign(msg, prv, k, pn); } @@ -125,9 +124,8 @@ schnorr.sign = function sign(msg, key, pubNonce) { */ schnorr.verify = function verify(msg, signature, key) { - let sig = new Signature(signature); - let h = schnorr.hash(msg, sig.r); - let k, l, r, rl; + const sig = new Signature(signature); + const h = schnorr.hash(msg, sig.r); if (h.cmp(curve.n) >= 0) throw new Error('Invalid hash.'); @@ -141,10 +139,10 @@ schnorr.verify = function verify(msg, signature, key) { if (sig.r.cmp(curve.p) > 0) throw new Error('Invalid R value.'); - k = curve.decodePoint(key); - l = k.mul(h); - r = curve.g.mul(sig.s); - rl = l.add(r); + const k = curve.decodePoint(key); + const l = k.mul(h); + const r = curve.g.mul(sig.s); + const rl = l.add(r); if (rl.y.isOdd()) throw new Error('Odd R value.'); @@ -160,9 +158,8 @@ schnorr.verify = function verify(msg, signature, key) { */ schnorr.recover = function recover(signature, msg) { - let sig = new Signature(signature); - let h = schnorr.hash(msg, sig.r); - let hinv, s, R, l, r, k, rl; + const sig = new Signature(signature); + const h = schnorr.hash(msg, sig.r); if (h.cmp(curve.n) >= 0) throw new Error('Invalid hash.'); @@ -176,24 +173,25 @@ schnorr.recover = function recover(signature, msg) { if (sig.r.cmp(curve.p) > 0) throw new Error('Invalid R value.'); - hinv = h.invm(curve.n); + let hinv = h.invm(curve.n); hinv = hinv.umod(curve.n); - s = sig.s; + let s = sig.s; s = curve.n.sub(s); s = s.umod(curve.n); s = s.imul(hinv); s = s.umod(curve.n); - R = curve.pointFromX(sig.r, false); - l = R.mul(hinv); - r = curve.g.mul(s); - k = l.add(r); + const R = curve.pointFromX(sig.r, false); + let l = R.mul(hinv); + let r = curve.g.mul(s); + const k = l.add(r); l = k.mul(h); r = curve.g.mul(sig.s); - rl = l.add(r); + + const rl = l.add(r); if (rl.y.isOdd()) throw new Error('Odd R value.'); @@ -215,7 +213,7 @@ schnorr.combineSigs = function combineSigs(sigs) { let r, last; for (let i = 0; i < sigs.length; i++) { - let sig = new Signature(sigs[i]); + const sig = new Signature(sigs[i]); if (sig.s.cmpn(0) === 0) throw new Error('Bad S value.'); @@ -248,18 +246,16 @@ schnorr.combineSigs = function combineSigs(sigs) { */ schnorr.combineKeys = function combineKeys(keys) { - let i, key, point; - if (keys.length === 0) throw new Error(); if (keys.length === 1) return keys[0]; - point = curve.decodePoint(keys[0]); + let point = curve.decodePoint(keys[0]); - for (i = 1; i < keys.length; i++) { - key = curve.decodePoint(keys[i]); + for (let i = 1; i < keys.length; i++) { + const key = curve.decodePoint(keys[i]); point = point.add(key); } @@ -276,10 +272,10 @@ schnorr.combineKeys = function combineKeys(keys) { */ schnorr.partialSign = function partialSign(msg, priv, privNonce, pubNonce) { - let prv = new BN(priv); - let k = new BN(privNonce); - let pn = curve.decodePoint(pubNonce); - let sig = schnorr.trySign(msg, prv, k, pn); + const prv = new BN(priv); + const k = new BN(privNonce); + const pn = curve.decodePoint(pubNonce); + const sig = schnorr.trySign(msg, prv, k, pn); if (!sig) throw new Error('Bad K value.'); @@ -303,7 +299,7 @@ schnorr.alg = Buffer.from('Schnorr+SHA256 ', 'ascii'); */ schnorr.drbg = function drbg(msg, priv, data) { - let pers = Buffer.allocUnsafe(48); + const pers = Buffer.allocUnsafe(48); pers.fill(0); @@ -326,10 +322,10 @@ schnorr.drbg = function drbg(msg, priv, data) { */ schnorr.generateNoncePair = function generateNoncePair(msg, priv, data) { - let drbg = schnorr.drbg(msg, priv, data); - let len = curve.n.byteLength(); - let k; + const drbg = schnorr.drbg(msg, priv, data); + const len = curve.n.byteLength(); + let k; for (;;) { k = new BN(drbg.generate(len)); diff --git a/lib/crypto/scrypt.js b/lib/crypto/scrypt.js index 2c3170675..b07dedc60 100644 --- a/lib/crypto/scrypt.js +++ b/lib/crypto/scrypt.js @@ -31,6 +31,8 @@ * SUCH DAMAGE. */ +/* eslint camelcase: "off" */ + 'use strict'; /** @@ -56,8 +58,6 @@ const native = require('../native').binding; */ function derive(passwd, salt, N, r, p, len) { - let B, V, XY; - if (r * p >= (1 << 30)) throw new Error('EFBIG'); @@ -67,10 +67,10 @@ function derive(passwd, salt, N, r, p, len) { if (N > 0xffffffff) throw new Error('EINVAL'); - XY = Buffer.allocUnsafe(256 * r); - V = Buffer.allocUnsafe(128 * r * N); + const XY = Buffer.allocUnsafe(256 * r); + const V = Buffer.allocUnsafe(128 * r * N); - B = pbkdf2.derive(passwd, salt, 1, p * 128 * r, 'sha256'); + const B = pbkdf2.derive(passwd, salt, 1, p * 128 * r, 'sha256'); for (let i = 0; i < p; i++) smix(B, i * 128 * r, r, N, V, XY); @@ -95,8 +95,6 @@ if (native) */ async function deriveAsync(passwd, salt, N, r, p, len) { - let B, V, XY; - if (r * p >= (1 << 30)) throw new Error('EFBIG'); @@ -106,10 +104,10 @@ async function deriveAsync(passwd, salt, N, r, p, len) { if (N > 0xffffffff) throw new Error('EINVAL'); - XY = Buffer.allocUnsafe(256 * r); - V = Buffer.allocUnsafe(128 * r * N); + const XY = Buffer.allocUnsafe(256 * r); + const V = Buffer.allocUnsafe(128 * r * N); - B = await pbkdf2.deriveAsync(passwd, salt, 1, p * 128 * r, 'sha256'); + const B = await pbkdf2.deriveAsync(passwd, salt, 1, p * 128 * r, 'sha256'); for (let i = 0; i < p; i++) await smixAsync(B, i * 128 * r, r, N, V, XY); @@ -125,8 +123,8 @@ if (native) */ function salsa20_8(B) { - let B32 = new Uint32Array(16); - let x = new Uint32Array(16); + const B32 = new Uint32Array(16); + const x = new Uint32Array(16); for (let i = 0; i < 16; i++) B32[i] = B.readUInt32LE(i * 4, true); @@ -188,7 +186,7 @@ function R(a, b) { } function blockmix_salsa8(B, Y, Yo, r) { - let X = Buffer.allocUnsafe(64); + const X = Buffer.allocUnsafe(64); blkcpy(X, B, 0, (2 * r - 1) * 64, 64); @@ -210,8 +208,8 @@ function integerify(B, r) { } function smix(B, Bo, r, N, V, XY) { - let X = XY; - let Y = XY; + const X = XY; + const Y = XY; blkcpy(X, B, 0, Bo, 128 * r); @@ -221,7 +219,7 @@ function smix(B, Bo, r, N, V, XY) { } for (let i = 0; i < N; i++) { - let j = integerify(X, r) & (N - 1); + const j = integerify(X, r) & (N - 1); blkxor(X, V, 0, j * (128 * r), 128 * r); blockmix_salsa8(X, Y, 128 * r, r); } @@ -230,8 +228,8 @@ function smix(B, Bo, r, N, V, XY) { } async function smixAsync(B, Bo, r, N, V, XY) { - let X = XY; - let Y = XY; + const X = XY; + const Y = XY; blkcpy(X, B, 0, Bo, 128 * r); @@ -242,7 +240,7 @@ async function smixAsync(B, Bo, r, N, V, XY) { } for (let i = 0; i < N; i++) { - let j = integerify(X, r) & (N - 1); + const j = integerify(X, r) & (N - 1); blkxor(X, V, 0, j * (128 * r), 128 * r); blockmix_salsa8(X, Y, 128 * r, r); await co.wait(); diff --git a/lib/crypto/secp256k1-browser.js b/lib/crypto/secp256k1-browser.js index 37936502f..be0a30205 100644 --- a/lib/crypto/secp256k1-browser.js +++ b/lib/crypto/secp256k1-browser.js @@ -34,8 +34,8 @@ ec.binding = false; */ ec.generatePrivateKey = function generatePrivateKey() { - let key = secp256k1.genKeyPair(); - return key.getPrivate().toBuffer('be', 32); + const key = secp256k1.genKeyPair(); + return key.getPrivate().toArrayLike(Buffer, 'be', 32); }; /** @@ -46,14 +46,12 @@ ec.generatePrivateKey = function generatePrivateKey() { */ ec.publicKeyCreate = function publicKeyCreate(priv, compress) { - let key; - assert(Buffer.isBuffer(priv)); if (compress == null) compress = true; - key = secp256k1.keyPair({ priv: priv }); + const key = secp256k1.keyPair({ priv: priv }); return Buffer.from(key.getPublic(compress, 'array')); }; @@ -65,7 +63,7 @@ ec.publicKeyCreate = function publicKeyCreate(priv, compress) { */ ec.publicKeyConvert = function publicKeyConvert(key, compress) { - let point = curve.decodePoint(key); + const point = curve.decodePoint(key); if (compress == null) compress = true; @@ -81,10 +79,10 @@ ec.publicKeyConvert = function publicKeyConvert(key, compress) { */ ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) { - let key = new BN(tweak) + const key = new BN(tweak) .add(new BN(privateKey)) .mod(curve.n) - .toBuffer('be', 32); + .toArrayLike(Buffer, 'be', 32); // Only a 1 in 2^127 chance of happening. if (!ec.privateKeyVerify(key)) @@ -101,14 +99,13 @@ ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) { */ ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compress) { - let key = curve.decodePoint(publicKey); - let point = curve.g.mul(new BN(tweak)).add(key); - let pub; + const key = curve.decodePoint(publicKey); + const point = curve.g.mul(new BN(tweak)).add(key); if (compress == null) compress = true; - pub = Buffer.from(point.encode('array', compress)); + const pub = Buffer.from(point.encode('array', compress)); if (!ec.publicKeyVerify(pub)) throw new Error('Public key is invalid.'); @@ -126,7 +123,7 @@ ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compress) { ec.ecdh = function ecdh(pub, priv) { priv = secp256k1.keyPair({ priv: priv }); pub = secp256k1.keyPair({ pub: pub }); - return priv.derive(pub.getPublic()).toBuffer('be', 32); + return priv.derive(pub.getPublic()).toArrayLike(Buffer, 'be', 32); }; /** @@ -139,18 +136,17 @@ ec.ecdh = function ecdh(pub, priv) { */ ec.recover = function recover(msg, sig, j, compress) { - let point; - if (!j) j = 0; if (compress == null) compress = true; + let point; try { point = secp256k1.recoverPubKey(msg, sig, j); } catch (e) { - return; + return null; } return Buffer.from(point.encode('array', compress)); @@ -195,7 +191,8 @@ ec.verify = function verify(msg, sig, key) { ec.publicKeyVerify = function publicKeyVerify(key) { try { - return secp256k1.keyPair({ pub: key }).validate(); + const pub = secp256k1.keyPair({ pub: key }); + return pub.validate(); } catch (e) { return false; } @@ -224,13 +221,11 @@ ec.privateKeyVerify = function privateKeyVerify(key) { */ ec.sign = function sign(msg, key) { - let sig; - assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(key)); // Sign message and ensure low S value - sig = secp256k1.sign(msg, key, { canonical: true }); + const sig = secp256k1.sign(msg, key, { canonical: true }); // Convert to DER return Buffer.from(sig.toDER()); @@ -238,20 +233,18 @@ ec.sign = function sign(msg, key) { /** * Convert DER signature to R/S. - * @param {Buffer} sig + * @param {Buffer} raw * @returns {Buffer} R/S-formatted signature. */ -ec.fromDER = function fromDER(sig) { - let out; +ec.fromDER = function fromDER(raw) { + assert(Buffer.isBuffer(raw)); - assert(Buffer.isBuffer(sig)); + const sig = new Signature(raw); + const out = Buffer.allocUnsafe(64); - sig = new Signature(sig); - out = Buffer.allocUnsafe(64); - - sig.r.toBuffer('be', 32).copy(out, 0); - sig.s.toBuffer('be', 32).copy(out, 32); + sig.r.toArrayLike(Buffer, 'be', 32).copy(out, 0); + sig.s.toArrayLike(Buffer, 'be', 32).copy(out, 32); return out; }; @@ -262,17 +255,15 @@ ec.fromDER = function fromDER(sig) { * @returns {Buffer} DER-formatted signature. */ -ec.toDER = function toDER(sig) { - let out; +ec.toDER = function toDER(raw) { + assert(Buffer.isBuffer(raw)); - assert(Buffer.isBuffer(sig)); - - out = new Signature({ - r: new BN(sig.slice(0, 32), 'be'), - s: new BN(sig.slice(32, 64), 'be') + const sig = new Signature({ + r: new BN(raw.slice(0, 32), 'be'), + s: new BN(raw.slice(32, 64), 'be') }); - return Buffer.from(out.toDER()); + return Buffer.from(sig.toDER()); }; /** @@ -281,9 +272,10 @@ ec.toDER = function toDER(sig) { * @returns {Boolean} */ -ec.isLowS = function isLowS(sig) { +ec.isLowS = function isLowS(raw) { + let sig; try { - sig = new Signature(sig); + sig = new Signature(raw); } catch (e) { return false; } @@ -305,48 +297,50 @@ ec.isLowS = function isLowS(sig) { function normalizeLength(sig) { let data = sig; - let p = { place: 0 }; - let len, rlen, slen; + let pos = 0; + let len; - if (data[p.place++] !== 0x30) + if (data[pos++] !== 0x30) return sig; - len = getLength(data, p); + [len, pos] = getLength(data, pos); - if (data.length > len + p.place) - data = data.slice(0, len + p.place); + if (data.length > len + pos) + data = data.slice(0, len + pos); - if (data[p.place++] !== 0x02) + if (data[pos++] !== 0x02) return sig; - rlen = getLength(data, p); - p.place += rlen; + // R length. + [len, pos] = getLength(data, pos); - if (data[p.place++] !== 0x02) + pos += len; + + if (data[pos++] !== 0x02) return sig; - slen = getLength(data, p); - if (data.length > slen + p.place) - data = data.slice(0, slen + p.place); + // S length. + [len, pos] = getLength(data, pos); + + if (data.length > len + pos) + data = data.slice(0, len + pos); return data; } -function getLength(buf, p) { - let initial = buf[p.place++]; - let len = initial & 0xf; - let off = p.place; - let val = 0; +function getLength(buf, pos) { + const initial = buf[pos++]; if (!(initial & 0x80)) - return initial; + return [initial, pos]; + + const len = initial & 0xf; + let val = 0; - for (let i = 0; i < len; i++, off++) { + for (let i = 0; i < len; i++) { val <<= 8; - val |= buf[off]; + val |= buf[pos++]; } - p.place = off; - - return val; + return [val, pos]; } diff --git a/lib/crypto/secp256k1-native.js b/lib/crypto/secp256k1-native.js index 10738a93e..139032a5f 100644 --- a/lib/crypto/secp256k1-native.js +++ b/lib/crypto/secp256k1-native.js @@ -105,7 +105,7 @@ ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compress) { */ ec.ecdh = function ecdh(pub, priv) { - let point = secp256k1.ecdhUnsafe(pub, priv, true); + const point = secp256k1.ecdhUnsafe(pub, priv, true); return point.slice(1, 33); }; @@ -127,13 +127,13 @@ ec.recover = function recover(msg, sig, j, compress) { try { sig = secp256k1.signatureImport(sig); } catch (e) { - return; + return null; } try { key = secp256k1.recover(msg, sig, j, compress); } catch (e) { - return; + return null; } return key; @@ -195,13 +195,11 @@ ec.privateKeyVerify = function privateKeyVerify(key) { */ ec.sign = function sign(msg, key) { - let sig; - assert(Buffer.isBuffer(msg)); assert(Buffer.isBuffer(key)); // Sign message - sig = secp256k1.sign(msg, key); + let sig = secp256k1.sign(msg, key); // Ensure low S value sig = secp256k1.signatureNormalize(sig.signature); @@ -239,10 +237,10 @@ ec.toDER = function toDER(sig) { */ ec.isLowS = function isLowS(sig) { - let rs, s; + let s; try { - rs = secp256k1.signatureImport(sig); + const rs = secp256k1.signatureImport(sig); s = rs.slice(32, 64); } catch (e) { return false; diff --git a/lib/crypto/secp256k1.js b/lib/crypto/secp256k1.js index 328133069..d2ee2f834 100644 --- a/lib/crypto/secp256k1.js +++ b/lib/crypto/secp256k1.js @@ -8,7 +8,7 @@ let native; -if (+process.env.BCOIN_NO_SECP256K1 !== 1) { +if (Number(process.env.BCOIN_NO_SECP256K1) !== 1) { try { native = require('secp256k1/bindings'); } catch (e) { diff --git a/lib/crypto/sha256.js b/lib/crypto/sha256.js index ae292dbd5..9a25ade1e 100644 --- a/lib/crypto/sha256.js +++ b/lib/crypto/sha256.js @@ -103,7 +103,7 @@ SHA256.prototype.finish = function finish() { * @param {Number} len */ -SHA256.prototype._update = function update(data, len) { +SHA256.prototype._update = function _update(data, len) { let size = this.bytes & 0x3f; let pos = 0; @@ -167,6 +167,7 @@ SHA256.prototype._finish = function _finish(out) { */ SHA256.prototype.transform = function transform(chunk, pos) { + const w = this.w; let a = this.s[0]; let b = this.s[1]; let c = this.s[2]; @@ -175,7 +176,6 @@ SHA256.prototype.transform = function transform(chunk, pos) { let f = this.s[5]; let g = this.s[6]; let h = this.s[7]; - let w = this.w; let i = 0; for (; i < 16; i++) @@ -185,13 +185,11 @@ SHA256.prototype.transform = function transform(chunk, pos) { w[i] = sigma1(w[i - 2]) + w[i - 7] + sigma0(w[i - 15]) + w[i - 16]; for (i = 0; i < 64; i++) { - let t1, t2; - - t1 = h + Sigma1(e); + let t1 = h + Sigma1(e); t1 += Ch(e, f, g); t1 += K[i] + w[i]; - t2 = Sigma0(a); + let t2 = Sigma0(a); t2 += Maj(a, b, c); h = g; @@ -248,7 +246,7 @@ function SHA256Hmac() { */ SHA256Hmac.prototype.init = function init(data) { - let key = BUFFER64; + const key = BUFFER64; if (data.length > 64) { this.inner.init(); @@ -363,7 +361,7 @@ function sha256(data) { */ function hash256(data) { - let out = Buffer.allocUnsafe(32); + const out = Buffer.allocUnsafe(32); ctx.init(); ctx.update(data); ctx._finish(out); diff --git a/lib/crypto/siphash.js b/lib/crypto/siphash.js index fb28b7803..08b5c4b31 100644 --- a/lib/crypto/siphash.js +++ b/lib/crypto/siphash.js @@ -24,27 +24,26 @@ const native = require('../native').binding; */ function siphash24(data, key, shift) { - let blocks = Math.floor(data.length / 8); - let c0 = U64(0x736f6d65, 0x70736575); - let c1 = U64(0x646f7261, 0x6e646f6d); - let c2 = U64(0x6c796765, 0x6e657261); - let c3 = U64(0x74656462, 0x79746573); - let f0 = U64(blocks << (shift - 32), 0); - let f1 = U64(0, 0xff); - let k0 = U64.fromRaw(key, 0); - let k1 = U64.fromRaw(key, 8); - let p = 0; - let v0, v1, v2, v3; + const blocks = Math.floor(data.length / 8); + const c0 = U64(0x736f6d65, 0x70736575); + const c1 = U64(0x646f7261, 0x6e646f6d); + const c2 = U64(0x6c796765, 0x6e657261); + const c3 = U64(0x74656462, 0x79746573); + const f0 = U64(blocks << (shift - 32), 0); + const f1 = U64(0, 0xff); + const k0 = U64.fromRaw(key, 0); + const k1 = U64.fromRaw(key, 8); // Init - v0 = c0.ixor(k0); - v1 = c1.ixor(k1); - v2 = c2.ixor(k0); - v3 = c3.ixor(k1); + const v0 = c0.ixor(k0); + const v1 = c1.ixor(k1); + const v2 = c2.ixor(k0); + const v3 = c3.ixor(k1); // Blocks + let p = 0; for (let i = 0; i < blocks; i++) { - let d = U64.fromRaw(data, p); + const d = U64.fromRaw(data, p); p += 8; v3.ixor(d); sipround(v0, v1, v2, v3); @@ -152,19 +151,18 @@ function U64(hi, lo) { } U64.prototype.iadd = function iadd(b) { - let a = this; - let hi, lo, as, bs, s, c; + const a = this; // Credit to @indutny for this method. - lo = (a.lo + b.lo) | 0; + const lo = (a.lo + b.lo) | 0; - s = lo >> 31; - as = a.lo >> 31; - bs = b.lo >> 31; + const s = lo >> 31; + const as = a.lo >> 31; + const bs = b.lo >> 31; - c = ((as & bs) | (~s & (as ^ bs))) & 1; + const c = ((as & bs) | (~s & (as ^ bs))) & 1; - hi = ((a.hi + b.hi) | 0) + c; + const hi = ((a.hi + b.hi) | 0) + c; a.hi = hi | 0; a.lo = lo; @@ -214,8 +212,8 @@ U64.prototype.irotl = function irotl(bits) { }; U64.fromRaw = function fromRaw(data, off) { - let lo = data.readUInt32LE(off, true); - let hi = data.readUInt32LE(off + 4, true); + const lo = data.readUInt32LE(off, true); + const hi = data.readUInt32LE(off + 4, true); return new U64(hi, lo); }; diff --git a/lib/db/ldb.js b/lib/db/ldb.js index 8f9f42277..fc0294e6a 100644 --- a/lib/db/ldb.js +++ b/lib/db/ldb.js @@ -19,9 +19,9 @@ const backends = require('./backends'); */ function LDB(options) { - let result = LDB.getBackend(options); - let backend = result.backend; - let location = result.location; + const result = LDB.getBackend(options); + const backend = result.backend; + const location = result.location; return new LowlevelUp(backend, location, options); } @@ -78,8 +78,8 @@ LDB.getName = function getName(db) { */ LDB.getBackend = function getBackend(options) { - let [name, ext] = LDB.getName(options.db); - let backend = backends.get(name); + const [name, ext] = LDB.getName(options.db); + const backend = backends.get(name); let location = options.location; if (typeof location !== 'string') { diff --git a/lib/db/level.js b/lib/db/level.js index 9e82b10bd..b033acd83 100644 --- a/lib/db/level.js +++ b/lib/db/level.js @@ -22,7 +22,7 @@ DB.prototype.get = function get(key, options, callback) { this.level.get(key, options, callback); }; -DB.prototype.put = function get(key, value, options, callback) { +DB.prototype.put = function put(key, value, options, callback) { if (this.bufferKeys && Buffer.isBuffer(key)) key = key.toString('hex'); this.level.put(key, value, options, callback); @@ -39,13 +39,15 @@ DB.prototype.batch = function batch(ops, options, callback) { return new Batch(this); if (this.bufferKeys) { - for (let op of ops) { + for (const op of ops) { if (Buffer.isBuffer(op.key)) op.key = op.key.toString('hex'); } } this.level.batch(ops, options, callback); + + return undefined; }; DB.prototype.iterator = function iterator(options) { @@ -142,8 +144,10 @@ Iterator.prototype.seek = function seek(key) { }; Iterator.prototype.end = function end(callback) { - if (this._end) - return callback(new Error('end() already called on iterator.')); + if (this._end) { + callback(new Error('end() already called on iterator.')); + return; + } this._end = true; this.iter.end(callback); }; diff --git a/lib/db/lowlevelup.js b/lib/db/lowlevelup.js index d1685f0ce..8e6e3cecb 100644 --- a/lib/db/lowlevelup.js +++ b/lib/db/lowlevelup.js @@ -58,8 +58,8 @@ function LowlevelUp(backend, location, options) { */ LowlevelUp.prototype.init = function init() { - let backend = this.backend; - let db = new backend(this.location); + const Backend = this.backend; + let db = new Backend(this.location); let binding = db; // Stay as close to the metal as possible. @@ -93,7 +93,7 @@ LowlevelUp.prototype.init = function init() { */ LowlevelUp.prototype.open = async function open() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._open(); } finally { @@ -108,7 +108,7 @@ LowlevelUp.prototype.open = async function open() { * @returns {Promise} */ -LowlevelUp.prototype._open = async function open() { +LowlevelUp.prototype._open = async function _open() { if (this.loaded) throw new Error('Database is already open.'); @@ -135,7 +135,7 @@ LowlevelUp.prototype._open = async function open() { */ LowlevelUp.prototype.close = async function close() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._close(); } finally { @@ -150,7 +150,7 @@ LowlevelUp.prototype.close = async function close() { * @returns {Promise} */ -LowlevelUp.prototype._close = async function close() { +LowlevelUp.prototype._close = async function _close() { if (!this.loaded) throw new Error('Database is already closed.'); @@ -271,7 +271,7 @@ LowlevelUp.prototype.get = function get(key) { this.binding.get(key, (err, result) => { if (err) { if (isNotFound(err)) { - resolve(); + resolve(null); return; } reject(err); @@ -429,7 +429,7 @@ LowlevelUp.prototype.compactRange = function compactRange(start, end) { */ LowlevelUp.prototype.has = async function has(key) { - let value = await this.get(key); + const value = await this.get(key); return value != null; }; @@ -441,10 +441,10 @@ LowlevelUp.prototype.has = async function has(key) { */ LowlevelUp.prototype.range = async function range(options) { - let items = []; - let parse = options.parse; + const items = []; + const parse = options.parse; - let iter = this.iterator({ + const iter = this.iterator({ gte: options.gte, lte: options.lte, keys: true, @@ -480,11 +480,11 @@ LowlevelUp.prototype.range = async function range(options) { * @returns {Promise} - Returns Array. */ -LowlevelUp.prototype.keys = async function _keys(options) { - let keys = []; - let parse = options.parse; +LowlevelUp.prototype.keys = async function keys(options) { + const items = []; + const parse = options.parse; - let iter = this.iterator({ + const iter = this.iterator({ gte: options.gte, lte: options.lte, keys: true, @@ -492,13 +492,12 @@ LowlevelUp.prototype.keys = async function _keys(options) { }); for (;;) { - let item = await iter.next(); - let key; + const item = await iter.next(); if (!item) break; - key = item.key; + let key = item.key; if (parse) { try { @@ -510,10 +509,10 @@ LowlevelUp.prototype.keys = async function _keys(options) { } if (key) - keys.push(key); + items.push(key); } - return keys; + return items; }; /** @@ -523,11 +522,11 @@ LowlevelUp.prototype.keys = async function _keys(options) { * @returns {Promise} - Returns Array. */ -LowlevelUp.prototype.values = async function _values(options) { - let values = []; - let parse = options.parse; +LowlevelUp.prototype.values = async function values(options) { + const items = []; + const parse = options.parse; - let iter = this.iterator({ + const iter = this.iterator({ gte: options.gte, lte: options.lte, keys: false, @@ -535,13 +534,12 @@ LowlevelUp.prototype.values = async function _values(options) { }); for (;;) { - let item = await iter.next(); - let value; + const item = await iter.next(); if (!item) break; - value = item.value; + let value = item.value; if (parse) { try { @@ -553,10 +551,10 @@ LowlevelUp.prototype.values = async function _values(options) { } if (value) - values.push(value); + items.push(value); } - return values; + return items; }; /** @@ -566,17 +564,16 @@ LowlevelUp.prototype.values = async function _values(options) { */ LowlevelUp.prototype.dump = async function dump() { - let records = {}; + const records = Object.create(null); - let items = await this.range({ + const items = await this.range({ gte: LOW, lte: HIGH }); - for (let i = 0; i < items.length; i++) { - let item = items[i]; - let key = item.key.toString('hex'); - let value = item.value.toString('hex'); + for (const item of items) { + const key = item.key.toString('hex'); + const value = item.value.toString('hex'); records[key] = value; } @@ -614,30 +611,29 @@ LowlevelUp.prototype.checkVersion = async function checkVersion(key, version) { */ LowlevelUp.prototype.clone = async function clone(path) { - let options = new LLUOptions(this.options); - let hwm = 256 << 20; - let total = 0; - let tmp, batch, iter; - if (!this.loaded) throw new Error('Database is closed.'); + const options = new LLUOptions(this.options); + const hwm = 256 << 20; + options.createIfMissing = true; options.errorIfExists = true; - tmp = new LowlevelUp(this.backend, path, options); + const tmp = new LowlevelUp(this.backend, path, options); await tmp.open(); - batch = tmp.batch(); + let batch = tmp.batch(); + let total = 0; - iter = this.iterator({ + const iter = this.iterator({ keys: true, values: true }); for (;;) { - let item = await iter.next(); + const item = await iter.next(); if (!item) break; diff --git a/lib/db/memdb.js b/lib/db/memdb.js index 73750a16e..4fc4dc53b 100644 --- a/lib/db/memdb.js +++ b/lib/db/memdb.js @@ -37,17 +37,15 @@ function MemDB(location) { */ MemDB.prototype.search = function search(key) { - let node; - if (typeof key === 'string') key = Buffer.from(key, 'utf8'); assert(Buffer.isBuffer(key), 'Key must be a Buffer.'); - node = this.tree.search(key); + const node = this.tree.search(key); if (!node) - return; + return undefined; return node.value; }; @@ -145,12 +143,10 @@ MemDB.prototype.close = function close(callback) { * Retrieve a record (leveldown method). * @param {Buffer|String} key * @param {Object?} options - * @param {Function} callback - Returns Bufer. + * @param {Function} callback - Returns Buffer. */ MemDB.prototype.get = function get(key, options, callback) { - let value; - if (!callback) { callback = options; options = null; @@ -159,10 +155,10 @@ MemDB.prototype.get = function get(key, options, callback) { if (!options) options = {}; - value = this.search(key); + let value = this.search(key); if (!value) { - let err = new Error('MEMDB_NOTFOUND: Key not found.'); + const err = new Error('MEMDB_NOTFOUND: Key not found.'); err.notFound = true; err.type = 'NotFoundError'; setImmediate(() => callback(err)); @@ -220,23 +216,21 @@ MemDB.prototype.del = function del(key, options, callback) { * @param {Function} callback */ -MemDB.prototype.batch = function _batch(ops, options, callback) { - let batch; - +MemDB.prototype.batch = function batch(ops, options, callback) { if (!callback) { callback = options; options = null; } - batch = new Batch(this, options); + const b = new Batch(this, options); if (ops) { - batch.ops = ops; - batch.write(callback); - return; + b.ops = ops; + b.write(callback); + return undefined; } - return batch; + return b; }; /** @@ -267,10 +261,10 @@ MemDB.prototype.getProperty = function getProperty(name) { */ MemDB.prototype.approximateSize = function approximateSize(start, end, callback) { - let items = this.range(start, end); + const items = this.range(start, end); let size = 0; - for (let item of items) { + for (const item of items) { size += item.key.length; size += item.value.length; } @@ -345,10 +339,10 @@ Batch.prototype.del = function del(key) { Batch.prototype.write = function write(callback) { if (this.written) { setImmediate(() => callback(new Error('Already written.'))); - return; + return this; } - for (let op of this.ops) { + for (const op of this.ops) { switch (op.type) { case 'put': this.db.insert(op.key, op.value); @@ -358,7 +352,7 @@ Batch.prototype.write = function write(callback) { break; default: setImmediate(() => callback(new Error('Bad op.'))); - return; + return this; } } @@ -419,8 +413,8 @@ function Iterator(db, options) { */ Iterator.prototype.init = function init() { - let snapshot = this.db.tree.snapshot(); - let iter = this.db.tree.iterator(snapshot); + const snapshot = this.db.tree.snapshot(); + const iter = this.db.tree.iterator(snapshot); if (this.options.reverse) { if (this.options.end) { @@ -453,15 +447,15 @@ Iterator.prototype.init = function init() { */ Iterator.prototype.next = function next(callback) { - let options = this.options; - let iter = this.iter; - let key, value, result; + const options = this.options; + const iter = this.iter; if (!this.iter) { setImmediate(() => callback(new Error('Cannot call next.'))); return; } + let result; if (options.reverse) { result = iter.prev(); @@ -505,8 +499,8 @@ Iterator.prototype.next = function next(callback) { this.total += 1; } - key = iter.key; - value = iter.value; + let key = iter.key; + let value = iter.value; if (!options.keys) key = DUMMY; diff --git a/lib/hd/common.js b/lib/hd/common.js index a8c9f180c..659a6f347 100644 --- a/lib/hd/common.js +++ b/lib/hd/common.js @@ -6,6 +6,7 @@ 'use strict'; +const assert = require('assert'); const LRU = require('../utils/lru'); const common = exports; @@ -17,14 +18,6 @@ const common = exports; common.HARDENED = 0x80000000; -/** - * Max index (u32max + 1). - * @const {Number} - * @default - */ - -common.MAX_INDEX = 0x100000000; - /** * Min entropy bits. * @const {Number} @@ -41,14 +34,6 @@ common.MIN_ENTROPY = 128; common.MAX_ENTROPY = 512; -/** - * Seed salt for key derivation ("Bitcoin seed"). - * @const {Buffer} - * @default - */ - -common.SEED_SALT = Buffer.from('Bitcoin seed', 'ascii'); - /** * LRU cache to avoid deriving keys twice. * @type {LRU} @@ -60,41 +45,54 @@ common.cache = new LRU(500); * Parse a derivation path and return an array of indexes. * @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki * @param {String} path - * @param {Number?} max - Max index. + * @param {Boolean} hard * @returns {Number[]} */ -common.parsePath = function parsePath(path, max) { - let parts = path.split('/'); - let root = parts.shift(); - let result = []; +common.parsePath = function parsePath(path, hard) { + assert(typeof path === 'string'); + assert(typeof hard === 'boolean'); + assert(path.length >= 1); + assert(path.length <= 3062); - if (max == null) - max = common.MAX_INDEX; + const parts = path.split('/'); + const root = parts[0]; if (root !== 'm' && root !== 'M' && root !== 'm\'' && root !== 'M\'') { - throw new Error('Bad path root.'); + throw new Error('Invalid path root.'); } - for (let index of parts) { - let hardened = index[index.length - 1] === '\''; + const result = []; + + for (let i = 1; i < parts.length; i++) { + let part = parts[i]; + + const hardened = part[part.length - 1] === '\''; if (hardened) - index = index.slice(0, -1); + part = part.slice(0, -1); - if (!/^\d+$/.test(index)) - throw new Error('Non-number path index.'); + if (part.length > 10) + throw new Error('Path index too large.'); - index = parseInt(index, 10); + if (!/^\d+$/.test(part)) + throw new Error('Path index is non-numeric.'); - if (hardened) - index += common.HARDENED; + let index = parseInt(part, 10); + + if ((index >>> 0) !== index) + throw new Error('Path index out of range.'); - if (!(index >= 0 && index < max)) - throw new Error('Index out of range.'); + if (hardened) { + index |= common.HARDENED; + index >>>= 0; + } + + if (!hard && (index & common.HARDENED)) + throw new Error('Path index cannot be hardened.'); result.push(index); } @@ -111,7 +109,7 @@ common.parsePath = function parsePath(path, max) { common.isMaster = function isMaster(key) { return key.depth === 0 && key.childIndex === 0 - && key.parentFingerPrint.readUInt32LE(0, true) === 0; + && key.parentFingerPrint === 0; }; /** @@ -121,20 +119,11 @@ common.isMaster = function isMaster(key) { * @returns {Boolean} */ -common.isBIP44 = function isBIP44(key, account) { +common.isAccount = function isAccount(key, account) { if (account != null) { - if (key.childIndex !== common.HARDENED + account) + const index = (common.HARDENED | account) >>> 0; + if (key.childIndex !== index) return false; } - return key.depth === 3 && key.childIndex >= common.HARDENED; -}; - -/** - * Test whether the key is a BIP45 purpose key. - * @param {HDPrivateKey|HDPublicKey} key - * @returns {Boolean} - */ - -common.isBIP45 = function isBIP45(key) { - return key.depth === 1 && key.childIndex === common.HARDENED + 45; + return key.depth === 3 && (key.childIndex & common.HARDENED) !== 0; }; diff --git a/lib/hd/mnemonic.js b/lib/hd/mnemonic.js index 5edd05380..4b14c9525 100644 --- a/lib/hd/mnemonic.js +++ b/lib/hd/mnemonic.js @@ -19,6 +19,12 @@ const wordlist = require('./wordlist'); const common = require('./common'); const nfkd = require('../utils/nfkd'); +/* + * Constants + */ + +const wordlistCache = Object.create(null); + /** * HD Mnemonic * @alias module:hd.Mnemonic @@ -77,7 +83,7 @@ Mnemonic.prototype.fromOptions = function fromOptions(options) { options = { phrase: options }; if (options.bits != null) { - assert(util.isNumber(options.bits)); + assert(util.isU16(options.bits)); assert(options.bits >= common.MIN_ENTROPY); assert(options.bits <= common.MAX_ENTROPY); assert(options.bits % 32 === 0); @@ -140,15 +146,13 @@ Mnemonic.prototype.destroy = function destroy() { */ Mnemonic.prototype.toSeed = function toSeed(passphrase) { - let phrase, passwd; - if (!passphrase) passphrase = this.passphrase; this.passphrase = passphrase; - phrase = nfkd(this.getPhrase()); - passwd = nfkd('mnemonic' + passphrase); + const phrase = nfkd(this.getPhrase()); + const passwd = nfkd('mnemonic' + passphrase); return pbkdf2.derive( Buffer.from(phrase, 'utf8'), @@ -176,40 +180,40 @@ Mnemonic.prototype.getEntropy = function getEntropy() { */ Mnemonic.prototype.getPhrase = function getPhrase() { - let phrase, wordlist, bits, ent, entropy; - if (this.phrase) return this.phrase; - phrase = []; - wordlist = Mnemonic.getWordlist(this.language); - - ent = this.getEntropy(); - bits = this.bits; - // Include the first `ENT / 32` bits // of the hash (the checksum). - bits += bits / 32; + const wbits = this.bits + (this.bits / 32); + + // Get entropy and checksum. + const entropy = this.getEntropy(); + const chk = digest.sha256(entropy); // Append the hash to the entropy to // make things easy when grabbing // the checksum bits. - entropy = Buffer.allocUnsafe(Math.ceil(bits / 8)); - ent.copy(entropy, 0); - digest.sha256(ent).copy(entropy, ent.length); + const size = Math.ceil(wbits / 8); + const data = Buffer.allocUnsafe(size); + entropy.copy(data, 0); + chk.copy(data, entropy.length); // Build the mnemonic by reading // 11 bit indexes from the entropy. - for (let i = 0; i < bits / 11; i++) { + const list = Mnemonic.getWordlist(this.language); + + let phrase = []; + for (let i = 0; i < wbits / 11; i++) { let index = 0; for (let j = 0; j < 11; j++) { - let pos = i * 11 + j; - let bit = pos % 8; - let oct = (pos - bit) / 8; + const pos = i * 11 + j; + const bit = pos % 8; + const oct = (pos - bit) / 8; index <<= 1; - index |= (entropy[oct] >>> (7 - bit)) & 1; + index |= (data[oct] >>> (7 - bit)) & 1; } - phrase.push(wordlist[index]); + phrase.push(list.words[index]); } // Japanese likes double-width spaces. @@ -230,52 +234,57 @@ Mnemonic.prototype.getPhrase = function getPhrase() { */ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) { - let words = phrase.split(/[ \u3000]+/); - let bits = words.length * 11; - let cbits = bits % 32; - let cbytes = Math.ceil(cbits / 8); - let lang = Mnemonic.getLanguage(words[0]); - let wordlist = Mnemonic.getWordlist(lang); - let ent, entropy, chk; + assert(typeof phrase === 'string'); + assert(phrase.length <= 1000); - bits -= cbits; + const words = phrase.trim().split(/[\s\u3000]+/); + const wbits = words.length * 11; + const cbits = wbits % 32; + + assert(cbits !== 0, 'Invalid checksum.'); + + const bits = wbits - cbits; assert(bits >= common.MIN_ENTROPY); assert(bits <= common.MAX_ENTROPY); assert(bits % 32 === 0); - assert(cbits !== 0, 'Invalid checksum.'); - ent = Buffer.allocUnsafe(Math.ceil((bits + cbits) / 8)); - ent.fill(0); + const size = Math.ceil(wbits / 8); + const data = Buffer.allocUnsafe(size); + data.fill(0); + + const lang = Mnemonic.getLanguage(words[0]); + const list = Mnemonic.getWordlist(lang); // Rebuild entropy bytes. for (let i = 0; i < words.length; i++) { - let word = words[i]; - let index = util.binarySearch(wordlist, word, util.strcmp); + const word = words[i]; + const index = list.map[word]; - if (index === -1) + if (index == null) throw new Error('Could not find word.'); for (let j = 0; j < 11; j++) { - let pos = i * 11 + j; - let bit = pos % 8; - let oct = (pos - bit) / 8; - let val = (index >>> (10 - j)) & 1; - ent[oct] |= val << (7 - bit); + const pos = i * 11 + j; + const bit = pos % 8; + const oct = (pos - bit) / 8; + const val = (index >>> (10 - j)) & 1; + data[oct] |= val << (7 - bit); } } - entropy = ent.slice(0, ent.length - cbytes); - ent = ent.slice(ent.length - cbytes); - chk = digest.sha256(entropy); + const cbytes = Math.ceil(cbits / 8); + const entropy = data.slice(0, data.length - cbytes); + const chk1 = data.slice(data.length - cbytes); + const chk2 = digest.sha256(entropy); // Verify checksum. for (let i = 0; i < cbits; i++) { - let bit = i % 8; - let oct = (i - bit) / 8; - let a = (ent[oct] >>> (7 - bit)) & 1; - let b = (chk[oct] >>> (7 - bit)) & 1; - if (a !== b) + const bit = i % 8; + const oct = (i - bit) / 8; + const b1 = (chk1[oct] >>> (7 - bit)) & 1; + const b2 = (chk2[oct] >>> (7 - bit)) & 1; + if (b1 !== b2) throw new Error('Invalid checksum.'); } @@ -342,11 +351,9 @@ Mnemonic.fromEntropy = function fromEntropy(entropy, lang) { */ Mnemonic.getLanguage = function getLanguage(word) { - let lang, wordlist; - - for (lang of Mnemonic.languages) { - wordlist = Mnemonic.getWordlist(lang); - if (util.binarySearch(wordlist, word, util.strcmp) !== -1) + for (const lang of Mnemonic.languages) { + const list = Mnemonic.getWordlist(lang); + if (list.map[word] != null) return lang; } @@ -355,12 +362,22 @@ Mnemonic.getLanguage = function getLanguage(word) { /** * Retrieve the wordlist for a language. - * @param {String} language - * @returns {String[]} + * @param {String} lang + * @returns {Object} */ -Mnemonic.getWordlist = function getWordlist(language) { - return wordlist.get(language); +Mnemonic.getWordlist = function getWordlist(lang) { + const cache = wordlistCache[lang]; + + if (cache) + return cache; + + const words = wordlist.get(lang); + const list = new WordList(words); + + wordlistCache[lang] = list; + + return list; }; /** @@ -385,7 +402,7 @@ Mnemonic.prototype.toJSON = function toJSON() { */ Mnemonic.prototype.fromJSON = function fromJSON(json) { - assert(util.isNumber(json.bits)); + assert(util.isU16(json.bits)); assert(typeof json.language === 'string'); assert(typeof json.entropy === 'string'); assert(typeof json.phrase === 'string'); @@ -434,7 +451,7 @@ Mnemonic.prototype.getSize = function getSize() { */ Mnemonic.prototype.toWriter = function toWriter(bw) { - let lang = Mnemonic.languages.indexOf(this.language); + const lang = Mnemonic.languages.indexOf(this.language); assert(lang !== -1); @@ -453,7 +470,7 @@ Mnemonic.prototype.toWriter = function toWriter(bw) { */ Mnemonic.prototype.toRaw = function toRaw(writer) { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -464,17 +481,21 @@ Mnemonic.prototype.toRaw = function toRaw(writer) { */ Mnemonic.prototype.fromReader = function fromReader(br) { - this.bits = br.readU16(); - this.language = Mnemonic.languages[br.readU8()]; - this.entropy = br.readBytes(this.bits / 8); + const bits = br.readU16(); + + assert(bits >= common.MIN_ENTROPY); + assert(bits <= common.MAX_ENTROPY); + assert(bits % 32 === 0); + + const language = Mnemonic.languages[br.readU8()]; + assert(language); + + this.bits = bits; + this.language = language; + this.entropy = br.readBytes(bits / 8); this.phrase = br.readVarString('utf8'); this.passphrase = br.readVarString('utf8'); - assert(this.language); - assert(this.bits >= common.MIN_ENTROPY); - assert(this.bits <= common.MAX_ENTROPY); - assert(this.bits % 32 === 0); - return this; }; @@ -538,6 +559,23 @@ Mnemonic.isMnemonic = function isMnemonic(obj) { && typeof obj.toSeed === 'function'; }; +/** + * Word List + * @constructor + * @ignore + * @param {Array} words + */ + +function WordList(words) { + this.words = words; + this.map = Object.create(null); + + for (let i = 0; i < words.length; i++) { + const word = words[i]; + this.map[word] = i; + } +} + /* * Expose */ diff --git a/lib/hd/private.js b/lib/hd/private.js index ccddb8848..3fce4a746 100644 --- a/lib/hd/private.js +++ b/lib/hd/private.js @@ -21,6 +21,12 @@ const common = require('./common'); const Mnemonic = require('./mnemonic'); const HDPublicKey = require('./public'); +/* + * Constants + */ + +const SEED_SALT = Buffer.from('Bitcoin seed', 'ascii'); + /** * HDPrivateKey * @alias module:hd.PrivateKey @@ -28,13 +34,13 @@ const HDPublicKey = require('./public'); * @param {Object|Base58String} options * @param {Base58String?} options.xkey - Serialized base58 key. * @param {Number?} options.depth - * @param {Buffer?} options.parentFingerPrint + * @param {Number?} options.parentFingerPrint * @param {Number?} options.childIndex * @param {Buffer?} options.chainCode * @param {Buffer?} options.privateKey * @property {Network} network * @property {Number} depth - * @property {Buffer} parentFingerPrint + * @property {Number} parentFingerPrint * @property {Number} childIndex * @property {Buffer} chainCode * @property {Buffer} privateKey @@ -46,13 +52,13 @@ function HDPrivateKey(options) { this.network = Network.primary; this.depth = 0; - this.parentFingerPrint = encoding.ZERO_U32; + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = encoding.ZERO_HASH; this.privateKey = encoding.ZERO_HASH; this.publicKey = encoding.ZERO_KEY; - this.fingerPrint = null; + this.fingerPrint = -1; this._xprivkey = null; @@ -70,10 +76,9 @@ function HDPrivateKey(options) { HDPrivateKey.prototype.fromOptions = function fromOptions(options) { assert(options, 'No options for HD private key.'); - assert(util.isNumber(options.depth)); - assert(options.depth >= 0 && options.depth <= 0xff); - assert(Buffer.isBuffer(options.parentFingerPrint)); - assert(util.isNumber(options.childIndex)); + assert(util.isU8(options.depth)); + assert(util.isU32(options.parentFingerPrint)); + assert(util.isU32(options.childIndex)); assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.privateKey)); @@ -150,16 +155,13 @@ HDPrivateKey.prototype.xpubkey = function xpubkey() { HDPrivateKey.prototype.destroy = function destroy(pub) { this.depth = 0; this.childIndex = 0; + this.parentFingerPrint = 0; - cleanse(this.parentFingerPrint); cleanse(this.chainCode); cleanse(this.privateKey); cleanse(this.publicKey); - if (this.fingerPrint) { - cleanse(this.fingerPrint); - this.fingerPrint = null; - } + this.fingerPrint = -1; if (this._hdPublicKey) { if (pub) @@ -172,34 +174,34 @@ HDPrivateKey.prototype.destroy = function destroy(pub) { /** * Derive a child key. - * @param {Number|String} - Child index or path. + * @param {Number} index - Derivation index. * @param {Boolean?} hardened - Whether the derivation should be hardened. * @returns {HDPrivateKey} */ HDPrivateKey.prototype.derive = function derive(index, hardened) { - let bw, id, data, hash, left, right, key, child; - assert(typeof index === 'number'); - if (hardened && index < common.HARDENED) - index += common.HARDENED; - - if (index < 0 || index >= common.MAX_INDEX) + if ((index >>> 0) !== index) throw new Error('Index out of range.'); if (this.depth >= 0xff) throw new Error('Depth too high.'); - id = this.getID(index); - child = common.cache.get(id); + if (hardened) { + index |= common.HARDENED; + index >>>= 0; + } - if (child) - return child; + const id = this.getID(index); + const cache = common.cache.get(id); - bw = new StaticWriter(37); + if (cache) + return cache; - if (index >= common.HARDENED) { + const bw = new StaticWriter(37); + + if (index & common.HARDENED) { bw.writeU8(0); bw.writeBytes(this.privateKey); bw.writeU32BE(index); @@ -208,22 +210,25 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { bw.writeU32BE(index); } - data = bw.render(); + const data = bw.render(); - hash = digest.hmac('sha512', data, this.chainCode); - left = hash.slice(0, 32); - right = hash.slice(32, 64); + const hash = digest.hmac('sha512', data, this.chainCode); + const left = hash.slice(0, 32); + const right = hash.slice(32, 64); + let key; try { key = secp256k1.privateKeyTweakAdd(this.privateKey, left); } catch (e) { return this.derive(index + 1); } - if (!this.fingerPrint) - this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); + if (this.fingerPrint === -1) { + const fp = digest.hash160(this.publicKey); + this.fingerPrint = fp.readUInt32BE(0, true); + } - child = new HDPrivateKey(); + const child = new HDPrivateKey(); child.network = this.network; child.depth = this.depth + 1; child.parentFingerPrint = this.fingerPrint; @@ -252,31 +257,22 @@ HDPrivateKey.prototype.getID = function getID(index) { /** * Derive a BIP44 account key. + * @param {Number} purpose * @param {Number} account - * @param {Boolean?} bip48 * @returns {HDPrivateKey} * @throws Error if key is not a master key. */ -HDPrivateKey.prototype.deriveBIP44 = function deriveBIP44(account, bip48) { - assert(util.isNumber(account), 'Account index must be a number.'); +HDPrivateKey.prototype.deriveAccount = function deriveAccount(purpose, account) { + assert(util.isU32(purpose), 'Purpose must be a number.'); + assert(util.isU32(account), 'Account index must be a number.'); assert(this.isMaster(), 'Cannot derive account index.'); return this - .derive(bip48 ? 48 : 44, true) + .derive(purpose, true) .derive(this.network.keyPrefix.coinType, true) .derive(account, true); }; -/** - * Derive a BIP45 purpose key. - * @returns {HDPrivateKey} - */ - -HDPrivateKey.prototype.deriveBIP45 = function deriveBIP45() { - assert(this.isMaster(), 'Cannot derive purpose 45.'); - return this.derive(45, true); -}; - /** * Test whether the key is a master key. * @returns {Boolean} @@ -292,17 +288,8 @@ HDPrivateKey.prototype.isMaster = function isMaster() { * @returns {Boolean} */ -HDPrivateKey.prototype.isBIP44 = function isBIP44(account) { - return common.isBIP44(this, account); -}; - -/** - * Test whether the key is a BIP45 purpose key. - * @returns {Boolean} - */ - -HDPrivateKey.prototype.isBIP45 = function isBIP45() { - return common.isBIP45(this); +HDPrivateKey.prototype.isAccount = function isAccount(account) { + return common.isAccount(this, account); }; /** @@ -313,15 +300,13 @@ HDPrivateKey.prototype.isBIP45 = function isBIP45() { */ HDPrivateKey.isBase58 = function isBase58(data, network) { - let prefix; - if (typeof data !== 'string') return false; if (data.length < 4) return false; - prefix = data.substring(0, 4); + const prefix = data.substring(0, 4); try { Network.fromPrivate58(prefix, network); @@ -339,15 +324,13 @@ HDPrivateKey.isBase58 = function isBase58(data, network) { */ HDPrivateKey.isRaw = function isRaw(data, network) { - let version; - if (!Buffer.isBuffer(data)) return false; if (data.length < 4) return false; - version = data.readUInt32BE(0, true); + const version = data.readUInt32BE(0, true); try { Network.fromPrivate(version, network); @@ -360,16 +343,12 @@ HDPrivateKey.isRaw = function isRaw(data, network) { /** * Test whether a string is a valid path. * @param {String} path - * @param {Boolean?} hardened * @returns {Boolean} */ HDPrivateKey.isValidPath = function isValidPath(path) { - if (typeof path !== 'string') - return false; - try { - common.parsePath(path, common.MAX_INDEX); + common.parsePath(path, true); return true; } catch (e) { return false; @@ -384,10 +363,11 @@ HDPrivateKey.isValidPath = function isValidPath(path) { */ HDPrivateKey.prototype.derivePath = function derivePath(path) { - let indexes = common.parsePath(path, common.MAX_INDEX); + const indexes = common.parsePath(path, true); + let key = this; - for (let index of indexes) + for (const index of indexes) key = key.derive(index); return key; @@ -399,13 +379,12 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) { * @returns {Boolean} */ -HDPrivateKey.prototype.equal = function equal(obj) { - if (!HDPrivateKey.isHDPrivateKey(obj)) - return false; +HDPrivateKey.prototype.equals = function equals(obj) { + assert(HDPrivateKey.isHDPrivateKey(obj)); return this.network === obj.network && this.depth === obj.depth - && this.parentFingerPrint.equals(obj.parentFingerPrint) + && this.parentFingerPrint === obj.parentFingerPrint && this.childIndex === obj.childIndex && this.chainCode.equals(obj.chainCode) && this.privateKey.equals(obj.privateKey); @@ -418,16 +397,14 @@ HDPrivateKey.prototype.equal = function equal(obj) { */ HDPrivateKey.prototype.compare = function compare(key) { - let cmp; - assert(HDPrivateKey.isHDPrivateKey(key)); - cmp = this.depth - key.depth; + let cmp = this.depth - key.depth; if (cmp !== 0) return cmp; - cmp = this.parentFingerPrint.compare(key.parentFingerPrint); + cmp = this.parentFingerPrint - key.parentFingerPrint; if (cmp !== 0) return cmp; @@ -458,18 +435,16 @@ HDPrivateKey.prototype.compare = function compare(key) { */ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) { - let hash, left, right; - assert(Buffer.isBuffer(seed)); - if (!(seed.length * 8 >= common.MIN_ENTROPY - && seed.length * 8 <= common.MAX_ENTROPY)) { + if (seed.length * 8 < common.MIN_ENTROPY + || seed.length * 8 > common.MAX_ENTROPY) { throw new Error('Entropy not in range.'); } - hash = digest.hmac('sha512', seed, common.SEED_SALT); - left = hash.slice(0, 32); - right = hash.slice(32, 64); + const hash = digest.hmac('sha512', seed, SEED_SALT); + const left = hash.slice(0, 32); + const right = hash.slice(32, 64); // Only a 1 in 2^127 chance of happening. if (!secp256k1.privateKeyVerify(left)) @@ -477,7 +452,7 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) { this.network = Network.get(network); this.depth = 0; - this.parentFingerPrint = Buffer.from([0, 0, 0, 0]); + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = right; this.privateKey = left; @@ -528,7 +503,7 @@ HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) { */ HDPrivateKey.prototype.fromPhrase = function fromPhrase(phrase, network) { - let mnemonic = Mnemonic.fromPhrase(phrase); + const mnemonic = Mnemonic.fromPhrase(phrase); this.fromMnemonic(mnemonic, network); return this; }; @@ -557,7 +532,7 @@ HDPrivateKey.prototype.fromKey = function fromKey(key, entropy, network) { assert(Buffer.isBuffer(entropy) && entropy.length === 32); this.network = Network.get(network); this.depth = 0; - this.parentFingerPrint = Buffer.from([0, 0, 0, 0]); + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = entropy; this.privateKey = key; @@ -584,8 +559,8 @@ HDPrivateKey.fromKey = function fromKey(key, entropy, network) { */ HDPrivateKey.generate = function generate(network) { - let key = secp256k1.generatePrivateKey(); - let entropy = random.randomBytes(32); + const key = secp256k1.generatePrivateKey(); + const entropy = random.randomBytes(32); return HDPrivateKey.fromKey(key, entropy, network); }; @@ -610,11 +585,11 @@ HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey, network) { */ HDPrivateKey.prototype.fromReader = function fromReader(br, network) { - let version = br.readU32BE(); + const version = br.readU32BE(); this.network = Network.fromPrivate(version, network); this.depth = br.readU8(); - this.parentFingerPrint = br.readBytes(4); + this.parentFingerPrint = br.readU32BE(); this.childIndex = br.readU32BE(); this.chainCode = br.readBytes(32); assert(br.readU8() === 0); @@ -670,7 +645,7 @@ HDPrivateKey.prototype.toWriter = function toWriter(bw, network) { bw.writeU32BE(network.keyPrefix.xprivkey); bw.writeU8(this.depth); - bw.writeBytes(this.parentFingerPrint); + bw.writeU32BE(this.parentFingerPrint); bw.writeU32BE(this.childIndex); bw.writeBytes(this.chainCode); bw.writeU8(0); diff --git a/lib/hd/public.js b/lib/hd/public.js index c9ea64909..b8f1fc845 100644 --- a/lib/hd/public.js +++ b/lib/hd/public.js @@ -25,13 +25,13 @@ const common = require('./common'); * @param {Object|Base58String} options * @param {Base58String?} options.xkey - Serialized base58 key. * @param {Number?} options.depth - * @param {Buffer?} options.parentFingerPrint + * @param {Number?} options.parentFingerPrint * @param {Number?} options.childIndex * @param {Buffer?} options.chainCode * @param {Buffer?} options.publicKey * @property {Network} network * @property {Number} depth - * @property {Buffer} parentFingerPrint + * @property {Number} parentFingerPrint * @property {Number} childIndex * @property {Buffer} chainCode * @property {Buffer} publicKey @@ -43,12 +43,12 @@ function HDPublicKey(options) { this.network = Network.primary; this.depth = 0; - this.parentFingerPrint = encoding.ZERO_U32; + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = encoding.ZERO_HASH; this.publicKey = encoding.ZERO_KEY; - this.fingerPrint = null; + this.fingerPrint = -1; this._xpubkey = null; @@ -64,10 +64,9 @@ function HDPublicKey(options) { HDPublicKey.prototype.fromOptions = function fromOptions(options) { assert(options, 'No options for HDPublicKey'); - assert(util.isNumber(options.depth)); - assert(options.depth >= 0 && options.depth <= 0xff); - assert(Buffer.isBuffer(options.parentFingerPrint)); - assert(util.isNumber(options.childIndex)); + assert(util.isU8(options.depth)); + assert(util.isU32(options.parentFingerPrint)); + assert(util.isU32(options.childIndex)); assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.publicKey)); @@ -129,22 +128,19 @@ HDPublicKey.prototype.xpubkey = function xpubkey() { HDPublicKey.prototype.destroy = function destroy() { this.depth = 0; this.childIndex = 0; + this.parentFingerPrint = 0; - cleanse(this.parentFingerPrint); cleanse(this.chainCode); cleanse(this.publicKey); - if (this.fingerPrint) { - cleanse(this.fingerPrint); - this.fingerPrint = null; - } + this.fingerPrint = -1; this._xpubkey = null; }; /** * Derive a child key. - * @param {Number|String} - Child index or path. + * @param {Number} index - Derivation index. * @param {Boolean?} hardened - Whether the derivation * should be hardened (throws if true). * @returns {HDPrivateKey} @@ -152,44 +148,47 @@ HDPublicKey.prototype.destroy = function destroy() { */ HDPublicKey.prototype.derive = function derive(index, hardened) { - let bw, id, data, hash, left, right, key, child; - assert(typeof index === 'number'); - if (index >= common.HARDENED || hardened) - throw new Error('Cannot derive hardened.'); - - if (index < 0) + if ((index >>> 0) !== index) throw new Error('Index out of range.'); + if ((index & common.HARDENED) || hardened) + throw new Error('Cannot derive hardened.'); + if (this.depth >= 0xff) throw new Error('Depth too high.'); - id = this.getID(index); - child = common.cache.get(id); + const id = this.getID(index); + const cache = common.cache.get(id); - if (child) - return child; + if (cache) + return cache; + + const bw = new StaticWriter(37); - bw = new StaticWriter(37); bw.writeBytes(this.publicKey); bw.writeU32BE(index); - data = bw.render(); - hash = digest.hmac('sha512', data, this.chainCode); - left = hash.slice(0, 32); - right = hash.slice(32, 64); + const data = bw.render(); + + const hash = digest.hmac('sha512', data, this.chainCode); + const left = hash.slice(0, 32); + const right = hash.slice(32, 64); + let key; try { key = secp256k1.publicKeyTweakAdd(this.publicKey, left, true); } catch (e) { return this.derive(index + 1); } - if (!this.fingerPrint) - this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); + if (this.fingerPrint === -1) { + const fp = digest.hash160(this.publicKey); + this.fingerPrint = fp.readUInt32BE(0, true); + } - child = new HDPublicKey(); + const child = new HDPublicKey(); child.network = this.network; child.depth = this.depth + 1; child.parentFingerPrint = this.fingerPrint; @@ -218,26 +217,16 @@ HDPublicKey.prototype.getID = function getID(index) { /** * Derive a BIP44 account key (does not derive, only ensures account key). * @method + * @param {Number} purpose * @param {Number} account - * @param {Boolean?} bip48 * @returns {HDPublicKey} * @throws Error if key is not already an account key. */ -HDPublicKey.prototype.deriveBIP44 = function deriveBIP44(account, bip48) { - assert(this.isBIP44(account), 'Cannot derive account index.'); - return this; -}; - -/** - * Derive a BIP45 purpose key (does not derive, only ensures account key). - * @method - * @returns {HDPublicKey} - * @throws Error if key is not already a purpose key. - */ - -HDPublicKey.prototype.deriveBIP45 = function deriveBIP45() { - assert(this.isBIP45(), 'Cannot derive purpose 45.'); +HDPublicKey.prototype.deriveAccount = function deriveAccount(purpose, account) { + assert(util.isU32(purpose)); + assert(util.isU32(account)); + assert(this.isAccount(account), 'Cannot derive account index.'); return this; }; @@ -258,18 +247,8 @@ HDPublicKey.prototype.isMaster = function isMaster() { * @returns {Boolean} */ -HDPublicKey.prototype.isBIP44 = function isBIP44(account) { - return common.isBIP44(this, account); -}; - -/** - * Test whether the key is a BIP45 purpose key. - * @method - * @returns {Boolean} - */ - -HDPublicKey.prototype.isBIP45 = function isBIP45() { - return common.isBIP45(this); +HDPublicKey.prototype.isAccount = function isAccount(account) { + return common.isAccount(this, account); }; /** @@ -280,11 +259,8 @@ HDPublicKey.prototype.isBIP45 = function isBIP45() { */ HDPublicKey.isValidPath = function isValidPath(path) { - if (typeof path !== 'string') - return false; - try { - common.parsePath(path, common.HARDENED); + common.parsePath(path, false); return true; } catch (e) { return false; @@ -300,10 +276,11 @@ HDPublicKey.isValidPath = function isValidPath(path) { */ HDPublicKey.prototype.derivePath = function derivePath(path) { - let indexes = common.parsePath(path, common.HARDENED); + const indexes = common.parsePath(path, false); + let key = this; - for (let index of indexes) + for (const index of indexes) key = key.derive(index); return key; @@ -315,13 +292,12 @@ HDPublicKey.prototype.derivePath = function derivePath(path) { * @returns {Boolean} */ -HDPublicKey.prototype.equal = function equal(obj) { - if (!HDPublicKey.isHDPublicKey(obj)) - return false; +HDPublicKey.prototype.equals = function equals(obj) { + assert(HDPublicKey.isHDPublicKey(obj)); return this.network === obj.network && this.depth === obj.depth - && this.parentFingerPrint.equals(obj.parentFingerPrint) + && this.parentFingerPrint === obj.parentFingerPrint && this.childIndex === obj.childIndex && this.chainCode.equals(obj.chainCode) && this.publicKey.equals(obj.publicKey); @@ -334,16 +310,14 @@ HDPublicKey.prototype.equal = function equal(obj) { */ HDPublicKey.prototype.compare = function compare(key) { - let cmp; - assert(HDPublicKey.isHDPublicKey(key)); - cmp = this.depth - key.depth; + let cmp = this.depth - key.depth; if (cmp !== 0) return cmp; - cmp = this.parentFingerPrint.compare(key.parentFingerPrint); + cmp = this.parentFingerPrint - key.parentFingerPrint; if (cmp !== 0) return cmp; @@ -409,15 +383,13 @@ HDPublicKey.fromJSON = function fromJSON(json, network) { */ HDPublicKey.isBase58 = function isBase58(data, network) { - let prefix; - if (typeof data !== 'string') return false; if (data.length < 4) return false; - prefix = data.substring(0, 4); + const prefix = data.substring(0, 4); try { Network.fromPublic58(prefix, network); @@ -435,15 +407,13 @@ HDPublicKey.isBase58 = function isBase58(data, network) { */ HDPublicKey.isRaw = function isRaw(data, network) { - let version; - if (!Buffer.isBuffer(data)) return false; if (data.length < 4) return false; - version = data.readUInt32BE(0, true); + const version = data.readUInt32BE(0, true); try { Network.fromPublic(version, network); @@ -474,11 +444,11 @@ HDPublicKey.prototype.fromBase58 = function fromBase58(xkey, network) { */ HDPublicKey.prototype.fromReader = function fromReader(br, network) { - let version = br.readU32BE(); + const version = br.readU32BE(); this.network = Network.fromPublic(version, network); this.depth = br.readU8(); - this.parentFingerPrint = br.readBytes(4); + this.parentFingerPrint = br.readU32BE(); this.childIndex = br.readU32BE(); this.chainCode = br.readBytes(32); this.publicKey = br.readBytes(33); @@ -523,7 +493,7 @@ HDPublicKey.prototype.toWriter = function toWriter(bw, network) { bw.writeU32BE(network.keyPrefix.xpubkey); bw.writeU8(this.depth); - bw.writeBytes(this.parentFingerPrint); + bw.writeU32BE(this.parentFingerPrint); bw.writeU32BE(this.childIndex); bw.writeBytes(this.chainCode); bw.writeBytes(this.publicKey); diff --git a/lib/http/base.js b/lib/http/base.js index 01ef851d3..107c78574 100644 --- a/lib/http/base.js +++ b/lib/http/base.js @@ -50,7 +50,7 @@ function HTTPBase(options) { this._init(); } -util.inherits(HTTPBase, AsyncObject); +Object.setPrototypeOf(HTTPBase.prototype, AsyncObject.prototype); /** * Initialize server. @@ -58,8 +58,8 @@ util.inherits(HTTPBase, AsyncObject); */ HTTPBase.prototype._init = function _init() { - let backend = this.config.getBackend(); - let options = this.config.toHTTP(); + const backend = this.config.getBackend(); + const options = this.config.toHTTP(); this.server = backend.createServer(options); @@ -97,8 +97,8 @@ HTTPBase.prototype._init = function _init() { HTTPBase.prototype._initRouter = function _initRouter() { this.server.on('request', async (hreq, hres) => { - let req = new Request(hreq, hres, hreq.url); - let res = new Response(hreq, hres); + const req = new Request(hreq, hres, hreq.url); + const res = new Response(hreq, hres); req.on('error', () => {}); @@ -121,8 +121,6 @@ HTTPBase.prototype._initRouter = function _initRouter() { */ HTTPBase.prototype.handleRequest = async function handleRequest(req, res) { - let routes; - if (await this.handleMounts(req, res)) return; @@ -131,13 +129,13 @@ HTTPBase.prototype.handleRequest = async function handleRequest(req, res) { if (await this.handleStack(req, res)) return; - routes = this.routes.getHandlers(req.method); + const routes = this.routes.getHandlers(req.method); if (!routes) throw new Error(`No routes found for method: ${req.method}.`); - for (let route of routes) { - let params = route.match(req.pathname); + for (const route of routes) { + const params = route.match(req.pathname); if (!params) continue; @@ -183,68 +181,95 @@ HTTPBase.prototype.cors = function cors() { */ HTTPBase.prototype.basicAuth = function basicAuth(options) { + assert(options, 'Basic auth requires options.'); + let user = options.username; let pass = options.password; let realm = options.realm; - if (user) { - if (typeof user === 'string') - user = Buffer.from(user, 'utf8'); - assert(Buffer.isBuffer(user)); - user = digest.hash256(user); + if (user != null) { + assert(typeof user === 'string'); + assert(user.length <= 255, 'Username too long.'); + assert(util.isAscii(user), 'Username must be ASCII.'); + user = digest.hash256(Buffer.from(user, 'ascii')); } - if (typeof pass === 'string') - pass = Buffer.from(pass, 'utf8'); - - assert(Buffer.isBuffer(pass)); - pass = digest.hash256(pass); + assert(typeof pass === 'string'); + assert(pass.length <= 255, 'Password too long.'); + assert(util.isAscii(pass), 'Password must be ASCII.'); + pass = digest.hash256(Buffer.from(pass, 'ascii')); if (!realm) realm = 'server'; assert(typeof realm === 'string'); - function fail(res) { + const fail = (res) => { res.setHeader('WWW-Authenticate', `Basic realm="${realm}"`); res.setStatus(401); res.end(); - } + }; return async (req, res) => { - let auth = req.headers['authorization']; - let parts, username, password, hash; + const hdr = req.headers['authorization']; - if (!auth) - return fail(res); + if (!hdr) { + fail(res); + return; + } - parts = auth.split(' '); + if (hdr.length > 674) { + fail(res); + return; + } - if (parts.length !== 2) - return fail(res); + const parts = hdr.split(' '); - if (parts[0] !== 'Basic') - return fail(res); + if (parts.length !== 2) { + fail(res); + return; + } + + const [type, b64] = parts; + + if (type !== 'Basic') { + fail(res); + return; + } - auth = Buffer.from(parts[1], 'base64').toString('utf8'); - parts = auth.split(':'); + const auth = Buffer.from(b64, 'base64').toString('ascii'); + const items = auth.split(':'); - username = parts.shift(); - password = parts.join(':'); + const username = items.shift(); + const password = items.join(':'); if (user) { - hash = Buffer.from(username, 'utf8'); - hash = digest.hash256(hash); + if (username.length > 255) { + fail(res); + return; + } + + const raw = Buffer.from(username, 'ascii'); + const hash = digest.hash256(raw); + + if (!ccmp(hash, user)) { + fail(res); + return; + } + } - if (!ccmp(hash, user)) - return fail(res); + if (password.length > 255) { + fail(res); + return; } - hash = Buffer.from(password, 'utf8'); - hash = digest.hash256(hash); + const raw = Buffer.from(password, 'ascii'); + const hash = digest.hash256(raw); - if (!ccmp(hash, pass)) - return fail(res); + if (!ccmp(hash, pass)) { + fail(res); + return; + } req.username = username; }; @@ -257,7 +282,7 @@ HTTPBase.prototype.basicAuth = function basicAuth(options) { */ HTTPBase.prototype.bodyParser = function bodyParser(options) { - let opt = new BodyParserOptions(options); + const opt = new BodyParserOptions(options); return async (req, res) => { if (req.hasBody) @@ -284,29 +309,32 @@ HTTPBase.prototype.bodyParser = function bodyParser(options) { HTTPBase.prototype.parseBody = async function parseBody(req, options) { let body = Object.create(null); - let type = req.contentType; - let data; if (req.method === 'GET') return body; - data = await this.readBody(req, 'utf8', options); - - if (!data) - return body; + let type = req.contentType; if (options.contentType) type = options.contentType; + if (type === 'bin') + return body; + + const data = await this.readBody(req, 'utf8', options); + + if (!data) + return body; + switch (type) { case 'json': body = JSON.parse(data); + if (!body || typeof body !== 'object' || Array.isArray(body)) + throw new Error('JSON body must be an object.'); break; case 'form': body = parsePairs(data, options.keyLimit); break; - default: - break; } return body; @@ -337,18 +365,13 @@ HTTPBase.prototype.readBody = function readBody(req, enc, options) { */ HTTPBase.prototype._readBody = function _readBody(req, enc, options, resolve, reject) { - let decode = new StringDecoder(enc); + const decode = new StringDecoder(enc); let hasData = false; let total = 0; let body = ''; - let timer = setTimeout(() => { - timer = null; - cleanup(); - reject(new Error('Request body timed out.')); - }, options.timeout); - - let cleanup = () => { + const cleanup = () => { + /* eslint-disable */ req.removeListener('data', onData); req.removeListener('error', onError); req.removeListener('end', onEnd); @@ -357,9 +380,10 @@ HTTPBase.prototype._readBody = function _readBody(req, enc, options, resolve, re timer = null; clearTimeout(timer); } + /* eslint-enable */ }; - let onData = (data) => { + const onData = (data) => { total += data.length; hasData = true; @@ -371,12 +395,12 @@ HTTPBase.prototype._readBody = function _readBody(req, enc, options, resolve, re body += decode.write(data); }; - let onError = (err) => { + const onError = (err) => { cleanup(); reject(err); }; - let onEnd = () => { + const onEnd = () => { cleanup(); if (hasData) { @@ -387,6 +411,12 @@ HTTPBase.prototype._readBody = function _readBody(req, enc, options, resolve, re resolve(null); }; + let timer = setTimeout(() => { + timer = null; + cleanup(); + reject(new Error('Request body timed out.')); + }, options.timeout); + req.on('data', onData); req.on('error', onError); req.on('end', onEnd); @@ -400,8 +430,6 @@ HTTPBase.prototype._readBody = function _readBody(req, enc, options, resolve, re HTTPBase.prototype.jsonRPC = function jsonRPC(rpc) { return async (req, res) => { - let json; - if (req.method !== 'POST') return; @@ -411,7 +439,7 @@ HTTPBase.prototype.jsonRPC = function jsonRPC(rpc) { if (typeof req.body.method !== 'string') return; - json = await rpc.call(req.body, req.query); + let json = await rpc.call(req.body, req.query); json = JSON.stringify(json); json += '\n'; @@ -433,8 +461,8 @@ HTTPBase.prototype.jsonRPC = function jsonRPC(rpc) { HTTPBase.prototype.handleMounts = async function handleMounts(req, res) { let url = req.url; - for (let route of this.mounts) { - let server = route.handler; + for (const route of this.mounts) { + const server = route.handler; if (!route.hasPrefix(req.pathname)) continue; @@ -461,7 +489,7 @@ HTTPBase.prototype.handleMounts = async function handleMounts(req, res) { */ HTTPBase.prototype.handleStack = async function handleStack(req, res) { - for (let route of this.stack) { + for (const route of this.stack) { if (!route.hasPrefix(req.pathname)) continue; @@ -481,7 +509,7 @@ HTTPBase.prototype.handleStack = async function handleStack(req, res) { */ HTTPBase.prototype.handleHooks = async function handleHooks(req, res) { - for (let route of this.hooks) { + for (const route of this.hooks) { if (!route.hasPrefix(req.pathname)) continue; @@ -498,11 +526,10 @@ HTTPBase.prototype.handleHooks = async function handleHooks(req, res) { */ HTTPBase.prototype._initSockets = function _initSockets() { - let IOServer; - if (!this.config.sockets) return; + let IOServer; try { IOServer = require('socket.io'); } catch (e) { @@ -532,7 +559,7 @@ HTTPBase.prototype._initSockets = function _initSockets() { */ HTTPBase.prototype.to = function to(name, ...args) { - let list = this.channels.get(name); + const list = this.channels.get(name); if (!list) return; @@ -540,7 +567,7 @@ HTTPBase.prototype.to = function to(name, ...args) { assert(list.size > 0); for (let item = list.head; item; item = item.next) { - let socket = item.value; + const socket = item.value; socket.emit(...args); } }; @@ -553,7 +580,7 @@ HTTPBase.prototype.to = function to(name, ...args) { */ HTTPBase.prototype.all = function all() { - let list = this.sockets; + const list = this.sockets; for (let socket = list.head; socket; socket = socket.next) socket.emit.apply(socket, arguments); @@ -566,7 +593,7 @@ HTTPBase.prototype.all = function all() { */ HTTPBase.prototype.addSocket = function addSocket(ws) { - let socket = new WebSocket(ws, this); + const socket = new WebSocket(ws, this); socket.on('error', (err) => { this.emit('error', err); @@ -586,7 +613,7 @@ HTTPBase.prototype.addSocket = function addSocket(ws) { this.sockets.push(socket); - for (let route of this.mounts) + for (const route of this.mounts) route.handler.addSocket(ws); this.emit('socket', socket); @@ -599,7 +626,7 @@ HTTPBase.prototype.addSocket = function addSocket(ws) { */ HTTPBase.prototype.removeSocket = function removeSocket(socket) { - for (let key of socket.channels.keys()) + for (const key of socket.channels.keys()) this.leaveChannel(socket, key); assert(this.sockets.remove(socket)); @@ -613,12 +640,13 @@ HTTPBase.prototype.removeSocket = function removeSocket(socket) { */ HTTPBase.prototype.joinChannel = function joinChannel(socket, name) { - let list = this.channels.get(name); let item = socket.channels.get(name); if (item) return; + let list = this.channels.get(name); + if (!list) { list = new List(); this.channels.set(name, list); @@ -638,12 +666,13 @@ HTTPBase.prototype.joinChannel = function joinChannel(socket, name) { */ HTTPBase.prototype.leaveChannel = function leaveChannel(socket, name) { - let list = this.channels.get(name); - let item = socket.channels.get(name); + const item = socket.channels.get(name); if (!item) return; + const list = this.channels.get(name); + assert(list); assert(list.remove(item)); @@ -660,10 +689,10 @@ HTTPBase.prototype.leaveChannel = function leaveChannel(socket, name) { */ HTTPBase.prototype.channel = function channel(name) { - let list = this.channels.get(name); + const list = this.channels.get(name); if (!list) - return; + return null; assert(list.size > 0); @@ -676,7 +705,7 @@ HTTPBase.prototype.channel = function channel(name) { * @returns {Promise} */ -HTTPBase.prototype._open = function open() { +HTTPBase.prototype._open = function _open() { return this.listen(this.config.port, this.config.host); }; @@ -686,7 +715,7 @@ HTTPBase.prototype._open = function open() { * @returns {Promise} */ -HTTPBase.prototype._close = function close() { +HTTPBase.prototype._close = function _close() { return new Promise((resolve, reject) => { if (this.io) { this.server.once('close', resolve); @@ -813,7 +842,7 @@ HTTPBase.prototype.listen = function listen(port, host) { return new Promise((resolve, reject) => { this.server.once('error', reject); this.server.listen(port, host, () => { - let addr = this.address(); + const addr = this.address(); this.emit('listening', addr); @@ -865,8 +894,7 @@ HTTPBaseOptions.prototype.fromOptions = function fromOptions(options) { } if (options.port != null) { - assert(typeof options.port === 'number', 'Port must be a number.'); - assert(options.port > 0 && options.port <= 0xffff); + assert(util.isU16(options.port), 'Port must be a number.'); this.port = options.port; } @@ -1062,7 +1090,7 @@ function Route(ctx, path, handler) { Route.prototype.compile = function compile() { let path = this.path; - let map = this.map; + const map = this.map; if (this.compiled) return; @@ -1085,23 +1113,21 @@ Route.prototype.compile = function compile() { this.regex = new RegExp('^' + path + '$'); }; -Route.prototype.match = function _match(pathname) { - let match, params; - +Route.prototype.match = function match(pathname) { this.compile(); assert(this.regex); - match = this.regex.exec(pathname); + const matches = this.regex.exec(pathname); - if (!match) - return; + if (!matches) + return null; - params = Object.create(null); + const params = Object.create(null); - for (let i = 1; i < match.length; i++) { - let item = match[i]; - let key = this.map[i - 1]; + for (let i = 1; i < matches.length; i++) { + const item = matches[i]; + const key = this.map[i - 1]; if (key) params[key] = item; @@ -1142,7 +1168,7 @@ function Routes() { Routes.prototype.getHandlers = function getHandlers(method) { if (!method) - return; + return null; method = method.toUpperCase(); @@ -1156,7 +1182,7 @@ Routes.prototype.getHandlers = function getHandlers(method) { case 'DELETE': return this.del; default: - return; + return null; } }; @@ -1194,7 +1220,7 @@ function Request(req, res, url) { this.init(req, res, url); } -util.inherits(Request, EventEmitter); +Object.setPrototypeOf(Request.prototype, EventEmitter.prototype); Request.prototype.init = function init(req, res, url) { assert(req); @@ -1229,11 +1255,10 @@ Request.prototype.init = function init(req, res, url) { }; Request.prototype.parse = function parse(url) { - let uri = URL.parse(url); + const uri = URL.parse(url); let pathname = uri.pathname; let query = Object.create(null); let trailing = false; - let path, parts; if (pathname) { pathname = pathname.replace(/\/{2,}/g, '/'); @@ -1260,12 +1285,12 @@ Request.prototype.parse = function parse(url) { if (pathname.length > 1) assert(pathname[pathname.length - 1] !== '/'); - path = pathname; + let path = pathname; if (path[0] === '/') path = path.substring(1); - parts = path.split('/'); + let parts = path.split('/'); if (parts.length === 1) { if (parts[0].length === 0) @@ -1295,7 +1320,7 @@ Request.prototype.parse = function parse(url) { }; Request.prototype.rewrite = function rewrite(url) { - let req = new Request(); + const req = new Request(); req.init(this.req, this.res, url); req.body = this.body; req.hasBody = this.hasBody; @@ -1346,7 +1371,7 @@ function Response(req, res) { this.init(req, res); } -util.inherits(Response, EventEmitter); +Object.setPrototypeOf(Response.prototype, EventEmitter.prototype); Response.prototype.init = function init(req, res) { assert(req); @@ -1417,13 +1442,6 @@ Response.prototype.error = function error(code, err) { code: err.code } }); - - try { - this.req.destroy(); - this.req.socket.destroy(); - } catch (e) { - ; - } }; Response.prototype.redirect = function redirect(code, url) { @@ -1468,8 +1486,8 @@ Response.prototype.send = function send(code, msg, type) { this.setType(type); if (typeof msg === 'string') { - let len = Buffer.byteLength(msg, 'utf8'); - this.setHeader('Content-Length', len + ''); + const len = Buffer.byteLength(msg, 'utf8'); + this.setHeader('Content-Length', len.toString(10)); try { this.write(msg, 'utf8'); this.end(); @@ -1480,7 +1498,7 @@ Response.prototype.send = function send(code, msg, type) { } if (Buffer.isBuffer(msg)) { - this.setHeader('Content-Length', msg.length + ''); + this.setHeader('Content-Length', msg.length.toString(10)); try { this.write(msg); this.end(); @@ -1509,7 +1527,7 @@ function WebSocket(socket, ctx) { this.context = ctx; this.socket = socket; this.remoteAddress = socket.conn.remoteAddress; - this.hooks = {}; + this.hooks = Object.create(null); this.channels = new Map(); this.auth = false; this.filter = null; @@ -1519,14 +1537,14 @@ function WebSocket(socket, ctx) { this.init(); } -util.inherits(WebSocket, EventEmitter); +Object.setPrototypeOf(WebSocket.prototype, EventEmitter.prototype); WebSocket.prototype.init = function init() { - let socket = this.socket; - let onevent = socket.onevent.bind(socket); + const socket = this.socket; + const onevent = socket.onevent.bind(socket); socket.onevent = (packet) => { - let result = onevent(packet); + const result = onevent(packet); this.onevent(packet); return result; }; @@ -1541,15 +1559,16 @@ WebSocket.prototype.init = function init() { }; WebSocket.prototype.onevent = async function onevent(packet) { - let args = (packet.data || []).slice(); - let type = args.shift() || ''; - let ack, result; + const args = (packet.data || []).slice(); + const type = args.shift() || ''; + let ack; if (typeof args[args.length - 1] === 'function') ack = args.pop(); else ack = this.socket.ack(packet.id); + let result; try { result = await this.fire(type, args); } catch (e) { @@ -1573,10 +1592,10 @@ WebSocket.prototype.hook = function hook(type, handler) { }; WebSocket.prototype.fire = async function fire(type, args) { - let handler = this.hooks[type]; + const handler = this.hooks[type]; if (!handler) - return; + return undefined; return await handler.call(this.context, args); }; @@ -1590,7 +1609,7 @@ WebSocket.prototype.leave = function leave(name) { }; WebSocket.prototype.dispatch = function dispatch() { - let emit = EventEmitter.prototype.emit; + const emit = EventEmitter.prototype.emit; return emit.apply(this, arguments); }; @@ -1599,7 +1618,7 @@ WebSocket.prototype.emit = function emit() { }; WebSocket.prototype.call = function call(...args) { - let socket = this.socket; + const socket = this.socket; return new Promise((resolve, reject) => { args.push(co.wrap(resolve, reject)); socket.emit(...args); @@ -1615,18 +1634,18 @@ WebSocket.prototype.destroy = function destroy() { */ function parsePairs(str, limit) { - let parts = str.split('&'); - let data = Object.create(null); + const parts = str.split('&'); + const data = Object.create(null); if (parts.length > limit) return data; assert(!limit || parts.length <= limit, 'Too many keys in querystring.'); - for (let pair of parts) { - let index = pair.indexOf('='); - let key, value; + for (const pair of parts) { + const index = pair.indexOf('='); + let key, value; if (index === -1) { key = pair; value = ''; diff --git a/lib/http/client.js b/lib/http/client.js index 98921be55..b9e1ac2a2 100644 --- a/lib/http/client.js +++ b/lib/http/client.js @@ -7,10 +7,10 @@ 'use strict'; +const assert = require('assert'); const Network = require('../protocol/network'); const AsyncObject = require('../utils/asyncobject'); const RPCClient = require('./rpcclient'); -const util = require('../utils/util'); const request = require('./request'); /** @@ -43,7 +43,7 @@ function HTTPClient(options) { this.rpc = new RPCClient(options); } -util.inherits(HTTPClient, AsyncObject); +Object.setPrototypeOf(HTTPClient.prototype, AsyncObject.prototype); /** * Open the client, wait for socket to connect. @@ -115,7 +115,7 @@ HTTPClient.prototype._open = async function _open() { * @returns {Promise} */ -HTTPClient.prototype._close = function close() { +HTTPClient.prototype._close = function _close() { if (!this.socket) return Promise.resolve(); @@ -195,20 +195,19 @@ HTTPClient.prototype.onDisconnect = function onDisconnect() { */ HTTPClient.prototype._request = async function _request(method, endpoint, json) { - let query, network, res; - if (this.token) { if (!json) json = {}; json.token = this.token; } + let query; if (json && method === 'get') { query = json; json = null; } - res = await request({ + const res = await request({ method: method, uri: this.uri + endpoint, pool: true, @@ -221,7 +220,7 @@ HTTPClient.prototype._request = async function _request(method, endpoint, json) }); if (res.statusCode === 404) - return; + return null; if (res.statusCode === 401) throw new Error('Unauthorized (bad API key).'); @@ -235,7 +234,7 @@ HTTPClient.prototype._request = async function _request(method, endpoint, json) if (!res.body) throw new Error('Bad response (no body).'); - network = res.headers['x-bcoin-network']; + const network = res.headers['x-bcoin-network']; if (network && network !== this.network.type) throw new Error('Bad response (wrong network).'); @@ -320,7 +319,18 @@ HTTPClient.prototype.getInfo = function getInfo() { */ HTTPClient.prototype.getCoinsByAddress = function getCoinsByAddress(address) { - return this._post('/coin/address', { address }); + return this._get(`/coin/address/${address}`); +}; + +/** + * Get coins that pertain to addresses from the mempool or chain database. + * Takes into account spent coins in the mempool. + * @param {String[]} addresses + * @returns {Promise} - Returns {@link Coin}[]. + */ + +HTTPClient.prototype.getCoinsByAddresses = function getCoinsByAddresses(addresses) { + return this._post('/coin/address', { addresses }); }; /** @@ -343,7 +353,18 @@ HTTPClient.prototype.getCoin = function getCoin(hash, index) { */ HTTPClient.prototype.getTXByAddress = function getTXByAddress(address) { - return this._post('/tx/address', { address }); + return this._get(`/tx/address/${address}`); +}; + +/** + * Retrieve transactions pertaining to + * addresses from the mempool or chain database. + * @param {String[]} addresses + * @returns {Promise} - Returns {@link TX}[]. + */ + +HTTPClient.prototype.getTXByAddresses = function getTXByAddresses(addresses) { + return this._post('/tx/address', { addresses }); }; /** @@ -457,22 +478,6 @@ HTTPClient.prototype.leave = function leave(id) { }); }; -/** - * Listen for events on all wallets. - */ - -HTTPClient.prototype.all = function all(token) { - return this.join('!all', token); -}; - -/** - * Unlisten for events on all wallets. - */ - -HTTPClient.prototype.none = function none() { - return this.leave('!all'); -}; - /** * Get list of all wallet IDs. * @returns {Promise} @@ -489,6 +494,7 @@ HTTPClient.prototype.getWallets = function getWallets() { */ HTTPClient.prototype.createWallet = function createWallet(options) { + assert(options.id, 'Must pass an id parameter'); return this._put(`/wallet/${options.id}`, options); }; @@ -565,7 +571,7 @@ HTTPClient.prototype.getLast = function getLast(id, account, limit) { */ HTTPClient.prototype.getRange = function getRange(id, account, options) { - let body = { + const body = { account: account, start: options.start, end: options.end , @@ -632,7 +638,7 @@ HTTPClient.prototype.getWalletCoin = function getWalletCoin(id, account, hash, i */ HTTPClient.prototype.send = function send(id, options) { - let body = Object.assign({}, options); + const body = Object.assign({}, options); if (!body.outputs) body.outputs = []; @@ -655,7 +661,7 @@ HTTPClient.prototype.send = function send(id, options) { */ HTTPClient.prototype.retoken = async function retoken(id, passphrase) { - let body = await this._post(`/wallet/${id}/retoken`, { passphrase }); + const body = await this._post(`/wallet/${id}/retoken`, { passphrase }); return body.token; }; @@ -667,7 +673,7 @@ HTTPClient.prototype.retoken = async function retoken(id, passphrase) { */ HTTPClient.prototype.setPassphrase = function setPassphrase(id, old, new_) { - let body = { old: old, passphrase: new_ }; + const body = { old: old, passphrase: new_ }; return this._post(`/wallet/${id}/passphrase`, body); }; @@ -679,7 +685,7 @@ HTTPClient.prototype.setPassphrase = function setPassphrase(id, old, new_) { */ HTTPClient.prototype.createTX = function createTX(id, options) { - let body = Object.assign({}, options); + const body = Object.assign({}, options); if (!body.outputs) body.outputs = []; @@ -704,7 +710,7 @@ HTTPClient.prototype.createTX = function createTX(id, options) { */ HTTPClient.prototype.sign = function sign(id, tx, options) { - let body = Object.assign({}, options); + const body = Object.assign({}, options); body.tx = toHex(tx); return this._post(`/wallet/${id}/sign`, body); }; @@ -753,7 +759,7 @@ HTTPClient.prototype.getWIF = function getWIF(id, address, passphrase) { */ HTTPClient.prototype.addSharedKey = function addSharedKey(id, account, key) { - let body = { account: account, accountKey: key }; + const body = { account: account, accountKey: key }; return this._put(`/wallet/${id}/shared-key`, body); }; @@ -767,7 +773,7 @@ HTTPClient.prototype.addSharedKey = function addSharedKey(id, account, key) { */ HTTPClient.prototype.removeSharedKey = function removeSharedKey(id, account, key) { - let body = { account: account, accountKey: key }; + const body = { account: account, accountKey: key }; return this._del(`/wallet/${id}/shared-key`, body); }; @@ -780,7 +786,7 @@ HTTPClient.prototype.removeSharedKey = function removeSharedKey(id, account, key */ HTTPClient.prototype.importPrivate = function importPrivate(id, account, key) { - let body = { account: account, privateKey: key }; + const body = { account: account, privateKey: key }; return this._post(`/wallet/${id}/import`, body); }; @@ -793,7 +799,7 @@ HTTPClient.prototype.importPrivate = function importPrivate(id, account, key) { */ HTTPClient.prototype.importPublic = function importPublic(id, account, key) { - let body = { account: account, publicKey: key }; + const body = { account: account, publicKey: key }; return this._post(`/wallet/${id}/import`, body); }; @@ -974,7 +980,7 @@ HTTPClient.prototype.createNested = function createNested(id, options) { function toHex(obj) { if (!obj) - return; + return null; if (obj.toRaw) obj = obj.toRaw(); diff --git a/lib/http/request.js b/lib/http/request.js index 8c7d9d47e..76b35509c 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -77,7 +77,7 @@ RequestOptions.prototype.setURI = function setURI(uri) { this.port = uri.port || (this.ssl ? 443 : 80); if (uri.auth) { - let parts = uri.auth.split(':'); + const parts = uri.auth.split(':'); this.auth = { username: parts[0] || '', password: parts[1] || '' @@ -202,16 +202,16 @@ RequestOptions.prototype.isExpected = function isExpected(type) { return this.expect === type; }; -RequestOptions.prototype.isOverflow = function isOverflow(length) { - if (!length) +RequestOptions.prototype.isOverflow = function isOverflow(hdr) { + if (!hdr) return false; if (!this.buffer) return false; - length = parseInt(length, 10); + const length = parseInt(hdr, 10); - if (length !== length) + if (!isFinite(length)) return true; return length > this.limit; @@ -223,12 +223,10 @@ RequestOptions.prototype.getBackend = function getBackend() { }; RequestOptions.prototype.getHeaders = function getHeaders() { - let headers; - if (this.headers) return this.headers; - headers = {}; + const headers = Object.create(null); headers['User-Agent'] = this.agent; @@ -236,11 +234,11 @@ RequestOptions.prototype.getHeaders = function getHeaders() { headers['Content-Type'] = getType(this.type); if (this.body) - headers['Content-Length'] = this.body.length + ''; + headers['Content-Length'] = this.body.length.toString(10); if (this.auth) { - let auth = `${this.auth.username}:${this.auth.password}`; - let data = Buffer.from(auth, 'utf8'); + const auth = `${this.auth.username}:${this.auth.password}`; + const data = Buffer.from(auth, 'utf8'); headers['Authorization'] = `Basic ${data.toString('base64')}`; } @@ -295,9 +293,10 @@ function Request(options) { this.total = 0; this.decoder = null; this.body = null; + this.buffer = null; } -Request.prototype.__proto__ = Stream.prototype; +Object.setPrototypeOf(Request.prototype, Stream.prototype); Request.prototype.startTimeout = function startTimeout() { if (!this.options.timeout) @@ -360,8 +359,8 @@ Request.prototype.destroy = function destroy() { }; Request.prototype.start = function start() { - let backend = this.options.getBackend(); - let options = this.options.toHTTP(); + const backend = this.options.getBackend(); + const options = this.options.toHTTP(); this.startTimeout(); @@ -397,27 +396,58 @@ Request.prototype.finish = function finish(err) { this.cleanup(); - if (this.options.buffer && this.body) { + if (this.options.buffer) { + assert(this.buffer != null); switch (this.type) { - case 'bin': - this.body = Buffer.concat(this.body); + case 'bin': { + this.body = Buffer.concat(this.buffer); + this.buffer = null; break; - case 'json': + } + case 'json': { + const buffer = this.buffer.trim(); + + this.buffer = null; + + if (buffer.length === 0) + break; + + let body; try { - this.body = JSON.parse(this.body); + body = JSON.parse(buffer); } catch (e) { this.emit('error', e); return; } + + if (!body || typeof body !== 'object') { + this.emit('error', new Error('JSON body is a non-object.')); + return; + } + + this.body = body; + break; - case 'form': + } + case 'form': { + const buffer = this.buffer; + + this.buffer = null; + try { - this.body = qs.parse(this.body); + this.body = qs.parse(buffer); } catch (e) { this.emit('error', e); return; } + + break; + } + default: { + this.body = this.buffer; + this.buffer = null; break; + } } } @@ -426,9 +456,7 @@ Request.prototype.finish = function finish(err) { }; Request.prototype._onResponse = function _onResponse(response) { - let type = response.headers['content-type']; - let length = response.headers['content-length']; - let location = response.headers['location']; + const location = response.headers['location']; if (location) { if (++this.redirects > this.options.maxRedirects) { @@ -442,13 +470,16 @@ Request.prototype._onResponse = function _onResponse(response) { return; } - type = parseType(type); + const contentType = response.headers['content-type']; + const type = parseType(contentType); if (!this.options.isExpected(type)) { this.finish(new Error('Wrong content-type for response.')); return; } + const length = response.headers['content-length']; + if (this.options.isOverflow(length)) { this.finish(new Error('Response exceeded limit.')); return; @@ -470,9 +501,9 @@ Request.prototype._onResponse = function _onResponse(response) { if (this.options.buffer) { if (this.type !== 'bin') { this.decoder = new StringDecoder('utf8'); - this.body = ''; + this.buffer = ''; } else { - this.body = []; + this.buffer = []; } } }; @@ -489,11 +520,13 @@ Request.prototype._onData = function _onData(data) { return; } } + if (this.decoder) { - this.body += this.decoder.write(data); + this.buffer += this.decoder.write(data); return; } - this.body.push(data); + + this.buffer.push(data); } }; @@ -531,20 +564,20 @@ function request(options) { options.buffer = true; return new Promise((resolve, reject) => { - let stream = new Request(options); + const req = new Request(options); - stream.on('error', err => reject(err)); - stream.on('end', () => resolve(stream)); + req.on('error', err => reject(err)); + req.on('end', () => resolve(req)); - stream.start(); - stream.end(); + req.start(); + req.end(); }); } -request.stream = function _stream(options) { - let stream = new Request(options); - stream.start(); - return stream; +request.stream = function stream(options) { + const req = new Request(options); + req.start(); + return req; }; /* diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 3f9d582c7..d0ab49974 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -24,6 +24,7 @@ const KeyRing = require('../primitives/keyring'); const MerkleBlock = require('../primitives/merkleblock'); const MTX = require('../primitives/mtx'); const Network = require('../protocol/network'); +const Outpoint = require('../primitives/outpoint'); const Output = require('../primitives/output'); const TX = require('../primitives/tx'); const IP = require('../utils/ip'); @@ -74,7 +75,7 @@ function RPC(node) { this.init(); } -util.inherits(RPC, RPCBase); +Object.setPrototypeOf(RPC.prototype, RPCBase.prototype); RPC.prototype.init = function init() { this.add('stop', this.stop); @@ -184,13 +185,11 @@ RPC.prototype.getInfo = async function getInfo(args, help) { }; }; -RPC.prototype.help = async function _help(args, help) { - let json; - +RPC.prototype.help = async function help(args, _help) { if (args.length === 0) return 'Select a command.'; - json = { + const json = { method: args[0], params: [] }; @@ -202,7 +201,11 @@ RPC.prototype.stop = async function stop(args, help) { if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'stop'); - this.node.close().catch(() => {}); + this.node.close().catch((err) => { + setImmediate(() => { + throw err; + }); + }); return 'Stopping.'; }; @@ -212,13 +215,13 @@ RPC.prototype.stop = async function stop(args, help) { */ RPC.prototype.getNetworkInfo = async function getNetworkInfo(args, help) { - let hosts = this.pool.hosts; - let locals = []; - if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'getnetworkinfo'); - for (let local of hosts.local.values()) { + const hosts = this.pool.hosts; + const locals = []; + + for (const local of hosts.local.values()) { locals.push({ address: local.addr.host, port: local.addr.port, @@ -244,23 +247,23 @@ RPC.prototype.getNetworkInfo = async function getNetworkInfo(args, help) { }; RPC.prototype.addNode = async function addNode(args, help) { - let valid = new Validator([args]); - let node = valid.str(0, ''); - let cmd = valid.str(1, ''); - if (help || args.length !== 2) throw new RPCError(errs.MISC_ERROR, 'addnode "node" "add|remove|onetry"'); + const valid = new Validator([args]); + const node = valid.str(0, ''); + const cmd = valid.str(1, ''); + switch (cmd) { case 'add': { this.pool.hosts.addNode(node); ; // fall through } case 'onetry': { - let addr = parseNetAddress(node, this.network); + const addr = parseNetAddress(node, this.network); if (!this.pool.peers.get(addr.hostname)) { - let peer = this.pool.createOutbound(addr); + const peer = this.pool.createOutbound(addr); this.pool.peers.add(peer); } @@ -276,15 +279,14 @@ RPC.prototype.addNode = async function addNode(args, help) { }; RPC.prototype.disconnectNode = async function disconnectNode(args, help) { - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let peer; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'disconnectnode "node"'); - addr = parseIP(addr, this.network); - peer = this.pool.peers.get(addr.hostname); + const valid = new Validator([args]); + const str = valid.str(0, ''); + + const addr = parseIP(str, this.network); + const peer = this.pool.peers.get(addr.hostname); if (peer) peer.destroy(); @@ -293,21 +295,20 @@ RPC.prototype.disconnectNode = async function disconnectNode(args, help) { }; RPC.prototype.getAddedNodeInfo = async function getAddedNodeInfo(args, help) { - let hosts = this.pool.hosts; - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let result = []; - let target; - if (help || args.length > 1) throw new RPCError(errs.MISC_ERROR, 'getaddednodeinfo ( "node" )'); + const hosts = this.pool.hosts; + const valid = new Validator([args]); + const addr = valid.str(0, ''); + + let target; if (args.length === 1) target = parseIP(addr, this.network); - for (let node of hosts.nodes) { - let peer; + const result = []; + for (const node of hosts.nodes) { if (target) { if (node.host !== target.host) continue; @@ -316,7 +317,7 @@ RPC.prototype.getAddedNodeInfo = async function getAddedNodeInfo(args, help) { continue; } - peer = this.pool.peers.get(node.hostname); + const peer = this.pool.peers.get(node.hostname); if (!peer || !peer.connected) { result.push({ @@ -376,21 +377,21 @@ RPC.prototype.getNetTotals = async function getNetTotals(args, help) { }; RPC.prototype.getPeerInfo = async function getPeerInfo(args, help) { - let peers = []; - if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'getpeerinfo'); + const peers = []; + for (let peer = this.pool.peers.head(); peer; peer = peer.next) { let offset = this.network.time.known.get(peer.hostname()); - let hashes = []; + const hashes = []; if (offset == null) offset = 0; - for (let hash in peer.blockMap.keys()) { - hash = util.revHex(hash); - hashes.push(hash); + for (const hash in peer.blockMap.keys()) { + const str = util.revHex(hash); + hashes.push(str); } peers.push({ @@ -405,7 +406,7 @@ RPC.prototype.getPeerInfo = async function getPeerInfo(args, help) { lastrecv: peer.lastRecv / 1000 | 0, bytessent: peer.socket.bytesWritten, bytesrecv: peer.socket.bytesRead, - conntime: peer.ts !== 0 ? (util.ms() - peer.ts) / 1000 | 0 : 0, + conntime: peer.time !== 0 ? (util.ms() - peer.time) / 1000 | 0 : 0, timeoffset: offset, pingtime: peer.lastPong !== -1 ? (peer.lastPong - peer.lastPing) / 1000 @@ -437,9 +438,9 @@ RPC.prototype.ping = async function ping(args, help) { }; RPC.prototype.setBan = async function setBan(args, help) { - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let action = valid.str(1, ''); + const valid = new Validator([args]); + const str = valid.str(0, ''); + const action = valid.str(1, ''); if (help || args.length < 2 @@ -448,7 +449,7 @@ RPC.prototype.setBan = async function setBan(args, help) { 'setban "ip(/netmask)" "add|remove" (bantime) (absolute)'); } - addr = parseNetAddress(addr, this.network); + const addr = parseNetAddress(str, this.network); switch (action) { case 'add': @@ -463,12 +464,12 @@ RPC.prototype.setBan = async function setBan(args, help) { }; RPC.prototype.listBanned = async function listBanned(args, help) { - let banned = []; - if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'listbanned'); - for (let [host, time] of this.pool.hosts.banned) { + const banned = []; + + for (const [host, time] of this.pool.hosts.banned) { banned.push({ address: host, banned_until: time + this.pool.options.banTime, @@ -529,24 +530,23 @@ RPC.prototype.getBlockCount = async function getBlockCount(args, help) { }; RPC.prototype.getBlock = async function getBlock(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let verbose = valid.bool(1, true); - let details = valid.bool(2, false); - let entry, block; - if (help || args.length < 1 || args.length > 3) throw new RPCError(errs.MISC_ERROR, 'getblock "hash" ( verbose )'); + const valid = new Validator([args]); + const hash = valid.hash(0); + const verbose = valid.bool(1, true); + const details = valid.bool(2, false); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.'); - entry = await this.chain.db.getEntry(hash); + const entry = await this.chain.db.getEntry(hash); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Block not found'); - block = await this.chain.db.getBlock(entry.hash); + const block = await this.chain.db.getBlock(entry.hash); if (!block) { if (this.chain.options.spv) @@ -565,26 +565,25 @@ RPC.prototype.getBlock = async function getBlock(args, help) { }; RPC.prototype.getBlockByHeight = async function getBlockByHeight(args, help) { - let valid = new Validator([args]); - let height = valid.u32(0, -1); - let verbose = valid.bool(1, true); - let details = valid.bool(2, false); - let entry, block; - if (help || args.length < 1 || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'getblockbyheight "height" ( verbose )'); } + const valid = new Validator([args]); + const height = valid.u32(0, -1); + const verbose = valid.bool(1, true); + const details = valid.bool(2, false); + if (height === -1) throw new RPCError(errs.TYPE_ERROR, 'Invalid block height.'); - entry = await this.chain.db.getEntry(height); + const entry = await this.chain.db.getEntry(height); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Block not found'); - block = await this.chain.db.getBlock(entry.hash); + const block = await this.chain.db.getBlock(entry.hash); if (!block) { if (this.chain.options.spv) @@ -603,17 +602,16 @@ RPC.prototype.getBlockByHeight = async function getBlockByHeight(args, help) { }; RPC.prototype.getBlockHash = async function getBlockHash(args, help) { - let valid = new Validator([args]); - let height = valid.u32(0); - let hash; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'getblockhash index'); + const valid = new Validator([args]); + const height = valid.u32(0); + if (height == null || height > this.chain.height) throw new RPCError(errs.INVALID_PARAMETER, 'Block height out of range.'); - hash = await this.chain.db.getHash(height); + const hash = await this.chain.db.getHash(height); if (!hash) throw new RPCError(errs.MISC_ERROR, 'Not found.'); @@ -622,18 +620,17 @@ RPC.prototype.getBlockHash = async function getBlockHash(args, help) { }; RPC.prototype.getBlockHeader = async function getBlockHeader(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let verbose = valid.bool(1, true); - let entry; - if (help || args.length < 1 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'getblockheader "hash" ( verbose )'); + const valid = new Validator([args]); + const hash = valid.hash(0); + const verbose = valid.bool(1, true); + if (!hash) throw new RPCError(errs.MISC_ERROR, 'Invalid block hash.'); - entry = await this.chain.db.getEntry(hash); + const entry = await this.chain.db.getEntry(hash); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Block not found'); @@ -645,22 +642,19 @@ RPC.prototype.getBlockHeader = async function getBlockHeader(args, help) { }; RPC.prototype.getChainTips = async function getChainTips(args, help) { - let tips, result; - if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'getchaintips'); - tips = await this.chain.db.getTips(); - result = []; + const tips = await this.chain.db.getTips(); + const result = []; - for (let hash of tips) { - let entry = await this.chain.db.getEntry(hash); - let fork, main; + for (const hash of tips) { + const entry = await this.chain.db.getEntry(hash); assert(entry); - fork = await this.findFork(entry); - main = await entry.isMainChain(); + const fork = await this.findFork(entry); + const main = await entry.isMainChain(); result.push({ height: entry.height, @@ -697,33 +691,32 @@ RPC.prototype.getMempoolInfo = async function getMempoolInfo(args, help) { }; RPC.prototype.getMempoolAncestors = async function getMempoolAncestors(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let verbose = valid.bool(1, false); - let out = []; - let entries, entry; - if (help || args.length < 1 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'getmempoolancestors txid (verbose)'); + const valid = new Validator([args]); + const hash = valid.hash(0); + const verbose = valid.bool(1, false); + if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); - entry = this.mempool.getEntry(hash); + const entry = this.mempool.getEntry(hash); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Transaction not in mempool.'); - entries = this.mempool.getAncestors(entry); + const entries = this.mempool.getAncestors(entry); + const out = []; if (verbose) { - for (let entry of entries) + for (const entry of entries) out.push(this.entryToJSON(entry)); } else { - for (let entry of entries) + for (const entry of entries) out.push(entry.txid()); } @@ -731,33 +724,32 @@ RPC.prototype.getMempoolAncestors = async function getMempoolAncestors(args, hel }; RPC.prototype.getMempoolDescendants = async function getMempoolDescendants(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let verbose = valid.bool(1, false); - let out = []; - let entries, entry; - if (help || args.length < 1 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'getmempooldescendants txid (verbose)'); + const valid = new Validator([args]); + const hash = valid.hash(0); + const verbose = valid.bool(1, false); + if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); - entry = this.mempool.getEntry(hash); + const entry = this.mempool.getEntry(hash); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Transaction not in mempool.'); - entries = this.mempool.getDescendants(entry); + const entries = this.mempool.getDescendants(entry); + const out = []; if (verbose) { - for (let entry of entries) + for (const entry of entries) out.push(this.entryToJSON(entry)); } else { - for (let entry of entries) + for (const entry of entries) out.push(entry.txid()); } @@ -765,20 +757,19 @@ RPC.prototype.getMempoolDescendants = async function getMempoolDescendants(args, }; RPC.prototype.getMempoolEntry = async function getMempoolEntry(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let entry; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'getmempoolentry txid'); + const valid = new Validator([args]); + const hash = valid.hash(0); + if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); - entry = this.mempool.getEntry(hash); + const entry = this.mempool.getEntry(hash); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Transaction not in mempool.'); @@ -787,39 +778,38 @@ RPC.prototype.getMempoolEntry = async function getMempoolEntry(args, help) { }; RPC.prototype.getRawMempool = async function getRawMempool(args, help) { - let valid = new Validator([args]); - let verbose = valid.bool(0, false); - let out = {}; - let hashes; - if (help || args.length > 1) throw new RPCError(errs.MISC_ERROR, 'getrawmempool ( verbose )'); + const valid = new Validator([args]); + const verbose = valid.bool(0, false); + if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); if (verbose) { - for (let entry of this.mempool.map.values()) + const out = {}; + + for (const entry of this.mempool.map.values()) out[entry.txid()] = this.entryToJSON(entry); return out; } - hashes = this.mempool.getSnapshot(); + const hashes = this.mempool.getSnapshot(); return hashes.map(util.revHex); }; RPC.prototype.getTXOut = async function getTXOut(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let index = valid.u32(1); - let mempool = valid.bool(2, true); - let coin; - if (help || args.length < 2 || args.length > 3) throw new RPCError(errs.MISC_ERROR, 'gettxout "txid" n ( includemempool )'); + const valid = new Validator([args]); + const hash = valid.hash(0); + const index = valid.u32(1); + const mempool = valid.bool(2, true); + if (this.chain.options.spv) throw new RPCError(errs.MISC_ERROR, 'Cannot get coins in SPV mode.'); @@ -829,6 +819,7 @@ RPC.prototype.getTXOut = async function getTXOut(args, help) { if (!hash || index == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid outpoint.'); + let coin; if (mempool) { if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); @@ -852,17 +843,15 @@ RPC.prototype.getTXOut = async function getTXOut(args, help) { }; RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) { - let valid = new Validator([args]); - let txids = valid.array(0); - let hash = valid.hash(1); - let uniq = {}; - let block, last; - if (help || (args.length !== 1 && args.length !== 2)) { throw new RPCError(errs.MISC_ERROR, 'gettxoutproof ["txid",...] ( blockhash )'); } + const valid = new Validator([args]); + const txids = valid.array(0); + const hash = valid.hash(1); + if (this.chain.options.spv) throw new RPCError(errs.MISC_ERROR, 'Cannot get coins in SPV mode.'); @@ -872,74 +861,80 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) { if (!txids || txids.length === 0) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid TXIDs.'); - valid = new Validator([txids]); + const items = new Validator([txids]); + const set = new Set(); + const hashes = []; + + let last = null; for (let i = 0; i < txids.length; i++) { - let txid = valid.hash(i); + const hash = items.hash(i); - if (!txid) + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); - if (uniq[txid]) + if (set.has(hash)) throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate txid.'); - uniq[txid] = true; - txids[i] = txid; - last = txid; + set.add(hash); + hashes.push(hash); + + last = hash; } + let block = null; + if (hash) { block = await this.chain.db.getBlock(hash); } else if (this.chain.options.indexTX) { - let tx = await this.chain.db.getMeta(last); - if (!tx) - return; - block = await this.chain.db.getBlock(tx.block); + const tx = await this.chain.db.getMeta(last); + if (tx) + block = await this.chain.db.getBlock(tx.block); } else { - let coins = await this.chain.db.getCoins(last); - if (!coins) - return; - block = await this.chain.db.getBlock(coins.height); + const coin = await this.chain.db.getCoin(last, 0); + if (coin) + block = await this.chain.db.getBlock(coin.height); } if (!block) throw new RPCError(errs.MISC_ERROR, 'Block not found.'); - for (let txid of txids) { - if (!block.hasTX(txid)) { + for (const hash of hashes) { + if (!block.hasTX(hash)) { throw new RPCError(errs.VERIFY_ERROR, 'Block does not contain all txids.'); } } - block = MerkleBlock.fromHashes(block, txids); + block = MerkleBlock.fromHashes(block, hashes); return block.toRaw().toString('hex'); }; RPC.prototype.verifyTXOutProof = async function verifyTXOutProof(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let out = []; - let block, entry; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'verifytxoutproof "proof"'); + const valid = new Validator([args]); + const data = valid.buf(0); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid hex string.'); - block = MerkleBlock.fromRaw(data); + const block = MerkleBlock.fromRaw(data); if (!block.verify()) - return out; + return []; - entry = await this.chain.db.getEntry(block.hash('hex')); + const entry = await this.chain.db.getEntry(block.hash('hex')); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Block not found in chain.'); - for (let hash of block.tree.matches) + const tree = block.getTree(); + const out = []; + + for (const hash of tree.matches) out.push(util.revHex(hash)); return out; @@ -984,13 +979,13 @@ RPC.prototype.pruneBlockchain = async function pruneBlockchain(args, help) { }; RPC.prototype.verifyChain = async function verifyChain(args, help) { - let valid = new Validator([args]); - let level = valid.u32(0); - let blocks = valid.u32(1); - if (help || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'verifychain ( checklevel numblocks )'); + const valid = new Validator([args]); + const level = valid.u32(0); + const blocks = valid.u32(1); + if (level == null || blocks == null) throw new RPCError(errs.TYPE_ERROR, 'Missing parameters.'); @@ -1008,7 +1003,7 @@ RPC.prototype.verifyChain = async function verifyChain(args, help) { */ RPC.prototype.submitWork = async function submitWork(data) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._submitWork(data); } finally { @@ -1017,9 +1012,7 @@ RPC.prototype.submitWork = async function submitWork(data) { }; RPC.prototype._submitWork = async function _submitWork(data) { - let attempt = this.attempt; - let header, nonce, ts, nonces; - let n1, n2, proof, block, entry; + const attempt = this.attempt; if (!attempt) return false; @@ -1027,10 +1020,10 @@ RPC.prototype._submitWork = async function _submitWork(data) { if (data.length !== 128) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid work size.'); - header = Headers.fromAbbr(data); + const raw = data.slice(0, 80); + swap32(raw); - data = data.slice(0, 80); - data = swap32(data); + const header = Headers.fromHead(raw); if (header.prevBlock !== attempt.prevBlock || header.bits !== attempt.bits) { @@ -1040,23 +1033,23 @@ RPC.prototype._submitWork = async function _submitWork(data) { if (!header.verify()) return false; - nonces = this.merkleMap.get(header.merkleRoot); + const nonces = this.merkleMap.get(header.merkleRoot); if (!nonces) return false; - n1 = nonces.nonce1; - n2 = nonces.nonce2; - nonce = header.nonce; - ts = header.ts; + const [n1, n2] = nonces; + const nonce = header.nonce; + const time = header.time; - proof = attempt.getProof(n1, n2, ts, nonce); + const proof = attempt.getProof(n1, n2, time, nonce); if (!proof.verify(attempt.target)) return false; - block = attempt.commit(proof); + const block = attempt.commit(proof); + let entry; try { entry = await this.chain.add(block); } catch (err) { @@ -1078,7 +1071,7 @@ RPC.prototype._submitWork = async function _submitWork(data) { }; RPC.prototype.createWork = async function createWork(data) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._createWork(data); } finally { @@ -1087,24 +1080,23 @@ RPC.prototype.createWork = async function createWork(data) { }; RPC.prototype._createWork = async function _createWork() { - let attempt = await this.updateWork(); - let n1 = this.nonce1; - let n2 = this.nonce2; - let ts = attempt.ts; - let data, root, head; + const attempt = await this.updateWork(); + const n1 = this.nonce1; + const n2 = this.nonce2; + const time = attempt.time; - data = Buffer.allocUnsafe(128); + const data = Buffer.allocUnsafe(128); data.fill(0); - root = attempt.getRoot(n1, n2); - head = attempt.getHeader(root, ts, 0); + const root = attempt.getRoot(n1, n2); + const head = attempt.getHeader(root, time, 0); head.copy(data, 0); data[80] = 0x80; data.writeUInt32BE(80 * 8, data.length - 4, true); - data = swap32(data); + swap32(data); return { data: data.toString('hex'), @@ -1119,13 +1111,13 @@ RPC.prototype.getWorkLongpoll = async function getWorkLongpoll(args, help) { }; RPC.prototype.getWork = async function getWork(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - if (args.length > 1) throw new RPCError(errs.MISC_ERROR, 'getwork ( "data" )'); if (args.length === 1) { + const valid = new Validator([args]); + const data = valid.buf(0); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid work data.'); @@ -1136,49 +1128,40 @@ RPC.prototype.getWork = async function getWork(args, help) { }; RPC.prototype.submitBlock = async function submitBlock(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let block; - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'submitblock "hexdata" ( "jsonparametersobject" )'); } - block = Block.fromRaw(data); + const valid = new Validator([args]); + const data = valid.buf(0); + + const block = Block.fromRaw(data); return await this.addBlock(block); }; RPC.prototype.getBlockTemplate = async function getBlockTemplate(args, help) { - let validator = new Validator([args]); - let options = validator.obj(0, {}); - let valid = new Validator([options]); - let mode = valid.str('mode', 'template'); - let lpid = valid.str('longpollid'); - let data = valid.buf('data'); - let rules = valid.array('rules'); - let capabilities = valid.array('capabilities'); - let maxVersion = valid.u32('maxversion', -1); - let coinbase = false; - let txnCap = false; - let valueCap = false; - if (help || args.length > 1) { throw new RPCError(errs.MISC_ERROR, 'getblocktemplate ( "jsonrequestobject" )'); } + const validator = new Validator([args]); + const options = validator.obj(0, {}); + const valid = new Validator([options]); + const mode = valid.str('mode', 'template'); + if (mode !== 'template' && mode !== 'proposal') throw new RPCError(errs.INVALID_PARAMETER, 'Invalid mode.'); if (mode === 'proposal') { - let block; + const data = valid.buf('data'); if (!data) throw new RPCError(errs.TYPE_ERROR, 'Missing data parameter.'); - block = Block.fromRaw(data); + const block = Block.fromRaw(data); if (block.prevBlock !== this.chain.tip.hash) return 'inconclusive-not-best-prevblk'; @@ -1194,11 +1177,20 @@ RPC.prototype.getBlockTemplate = async function getBlockTemplate(args, help) { return null; } + let maxVersion = valid.u32('maxversion', -1); + let rules = valid.array('rules'); + if (rules) maxVersion = -1; + const capabilities = valid.array('capabilities'); + let coinbase = false; + if (capabilities) { - for (let capability of capabilities) { + let txnCap = false; + let valueCap = false; + + for (const capability of capabilities) { if (typeof capability !== 'string') throw new RPCError(errs.TYPE_ERROR, 'Invalid capability.'); @@ -1244,6 +1236,8 @@ RPC.prototype.getBlockTemplate = async function getBlockTemplate(args, help) { } } + const lpid = valid.str('longpollid'); + if (lpid) await this.handleLongpoll(lpid); @@ -1254,7 +1248,7 @@ RPC.prototype.getBlockTemplate = async function getBlockTemplate(args, help) { }; RPC.prototype.createTemplate = async function createTemplate(maxVersion, coinbase, rules) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._createTemplate(maxVersion, coinbase, rules); } finally { @@ -1263,15 +1257,11 @@ RPC.prototype.createTemplate = async function createTemplate(maxVersion, coinbas }; RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinbase, rules) { - let attempt = await this.getTemplate(); - let version = attempt.version; - let scale = attempt.witness ? 1 : consensus.WITNESS_SCALE_FACTOR; - let mutable = ['time', 'transactions', 'prevblock']; - let txs = []; - let index = {}; - let vbavailable = {}; - let vbrules = []; - let json; + const attempt = await this.getTemplate(); + const scale = attempt.witness ? 1 : consensus.WITNESS_SCALE_FACTOR; + + // Default mutable fields. + const mutable = ['time', 'transactions', 'prevblock']; // The miner doesn't support // versionbits. Force them to @@ -1290,20 +1280,22 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb } // Build an index of every transaction. + const index = new Map(); for (let i = 0; i < attempt.items.length; i++) { - let entry = attempt.items[i]; - index[entry.hash] = i + 1; + const entry = attempt.items[i]; + index.set(entry.hash, i + 1); } // Calculate dependencies for each transaction. + const txs = []; for (let i = 0; i < attempt.items.length; i++) { - let entry = attempt.items[i]; - let tx = entry.tx; - let deps = []; + const entry = attempt.items[i]; + const tx = entry.tx; + const deps = []; for (let j = 0; j < tx.inputs.length; j++) { - let input = tx.inputs[j]; - let dep = index[input.prevout.hash]; + const input = tx.inputs[j]; + const dep = index.get(input.prevout.hash); if (dep == null) continue; @@ -1334,8 +1326,12 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb rules.push('segwit'); // Calculate version based on given rules. - for (let deploy of this.network.deploys) { - let state = await this.chain.getState(this.chain.tip, deploy); + let version = attempt.version; + const vbavailable = {}; + const vbrules = []; + + for (const deploy of this.network.deploys) { + const state = await this.chain.getState(this.chain.tip, deploy); let name = deploy.name; switch (state) { @@ -1371,7 +1367,7 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb version >>>= 0; - json = { + const json = { capabilities: ['proposal'], mutable: mutable, version: version, @@ -1383,10 +1379,10 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb target: util.revHex(attempt.target.toString('hex')), bits: util.hex32(attempt.bits), noncerange: '00000000ffffffff', - curtime: attempt.ts, + curtime: attempt.time, mintime: attempt.mtp + 1, - maxtime: attempt.ts + 7200, - expires: attempt.ts + 7200, + maxtime: attempt.time + 7200, + expires: attempt.time + 7200, sigoplimit: consensus.MAX_BLOCK_SIGOPS_COST / scale | 0, sizelimit: consensus.MAX_BLOCK_SIZE, weightlimit: undefined, @@ -1411,25 +1407,25 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb // The client wants a coinbasetxn // instead of a coinbasevalue. if (coinbase) { - let tx = attempt.toCoinbase(); + const tx = attempt.toCoinbase(); + const input = tx.inputs[0]; // Pop off the nonces. - tx.inputs[0].script.code.pop(); - tx.inputs[0].script.compile(); + input.script.pop(); + input.script.compile(); if (attempt.witness) { // We don't include the commitment // output (see bip145). - let output = tx.outputs.pop(); + const output = tx.outputs.pop(); assert(output.script.isCommitment()); // Also not including the witness nonce. - tx.inputs[0].witness.length = 0; - tx.inputs[0].witness.compile(); - - tx.refresh(); + input.witness.clear(); } + tx.refresh(); + json.coinbasetxn = { data: tx.toRaw().toString('hex'), txid: tx.txid(), @@ -1450,22 +1446,22 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb }; RPC.prototype.getMiningInfo = async function getMiningInfo(args, help) { - let attempt = this.attempt; + if (help || args.length !== 0) + throw new RPCError(errs.MISC_ERROR, 'getmininginfo'); + + const attempt = this.attempt; + let size = 0; let weight = 0; let txs = 0; let diff = 0; - let item; - - if (help || args.length !== 0) - throw new RPCError(errs.MISC_ERROR, 'getmininginfo'); if (attempt) { weight = attempt.weight; txs = attempt.items.length + 1; diff = attempt.getDifficulty(); size = 1000; - for (item of attempt.items) + for (const item of attempt.items) size += item.tx.getBaseSize(); } @@ -1488,28 +1484,27 @@ RPC.prototype.getMiningInfo = async function getMiningInfo(args, help) { }; RPC.prototype.getNetworkHashPS = async function getNetworkHashPS(args, help) { - let valid = new Validator([args]); - let lookup = valid.u32(0, 120); - let height = valid.u32(1); - if (help || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'getnetworkhashps ( blocks height )'); + const valid = new Validator([args]); + const lookup = valid.u32(0, 120); + const height = valid.u32(1); + return await this.getHashRate(lookup, height); }; RPC.prototype.prioritiseTransaction = async function prioritiseTransaction(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let pri = valid.num(1); - let fee = valid.i64(2); - let entry; - if (help || args.length !== 3) { throw new RPCError(errs.MISC_ERROR, 'prioritisetransaction '); } + const valid = new Validator([args]); + const hash = valid.hash(0); + const pri = valid.i64(1); + const fee = valid.i64(2); + if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); @@ -1519,7 +1514,7 @@ RPC.prototype.prioritiseTransaction = async function prioritiseTransaction(args, if (pri == null || fee == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid fee or priority.'); - entry = this.mempool.getEntry(hash); + const entry = this.mempool.getEntry(hash); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Transaction not in mempool.'); @@ -1530,20 +1525,19 @@ RPC.prototype.prioritiseTransaction = async function prioritiseTransaction(args, }; RPC.prototype.verifyBlock = async function verifyBlock(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let block; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'verifyblock "block-hex"'); + const valid = new Validator([args]); + const data = valid.buf(0); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid block hex.'); if (this.chain.options.spv) throw new RPCError(errs.MISC_ERROR, 'Cannot verify block in SPV mode.'); - block = Block.fromRaw(data); + const block = Block.fromRaw(data); try { await this.chain.verifyBlock(block); @@ -1567,13 +1561,13 @@ RPC.prototype.getGenerate = async function getGenerate(args, help) { }; RPC.prototype.setGenerate = async function setGenerate(args, help) { - let valid = new Validator([args]); - let mine = valid.bool(0, false); - let limit = valid.u32(1, 0); - if (help || args.length < 1 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'setgenerate mine ( proclimit )'); + const valid = new Validator([args]); + const mine = valid.bool(0, false); + const limit = valid.u32(1, 0); + if (mine && this.miner.addresses.length === 0) { throw new RPCError(errs.MISC_ERROR, 'No addresses available for coinbase.'); @@ -1593,13 +1587,13 @@ RPC.prototype.setGenerate = async function setGenerate(args, help) { }; RPC.prototype.generate = async function generate(args, help) { - let valid = new Validator([args]); - let blocks = valid.u32(0, 1); - let tries = valid.u32(1); - if (help || args.length < 1 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'generate numblocks ( maxtries )'); + const valid = new Validator([args]); + const blocks = valid.u32(0, 1); + const tries = valid.u32(1); + if (this.miner.addresses.length === 0) { throw new RPCError(errs.MISC_ERROR, 'No addresses available for coinbase.'); @@ -1608,18 +1602,18 @@ RPC.prototype.generate = async function generate(args, help) { return await this.mineBlocks(blocks, null, tries); }; -RPC.prototype.generateToAddress = async function _generateToAddress(args, help) { - let valid = new Validator([args]); - let blocks = valid.u32(0, 1); - let addr = valid.str(1, ''); - let tries = valid.u32(2); - +RPC.prototype.generateToAddress = async function generateToAddress(args, help) { if (help || args.length < 2 || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'generatetoaddress numblocks address ( maxtries )'); } - addr = parseAddress(addr, this.network); + const valid = new Validator([args]); + const blocks = valid.u32(0, 1); + const str = valid.str(1, ''); + const tries = valid.u32(2); + + const addr = parseAddress(str, this.network); return await this.mineBlocks(blocks, addr, tries); }; @@ -1629,12 +1623,6 @@ RPC.prototype.generateToAddress = async function _generateToAddress(args, help) */ RPC.prototype.createRawTransaction = async function createRawTransaction(args, help) { - let valid = new Validator([args]); - let inputs = valid.array(0); - let sendTo = valid.obj(1); - let locktime = valid.u32(2); - let tx, keys, addrs; - if (help || args.length < 2 || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'createrawtransaction' @@ -1643,20 +1631,25 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h + ' ( locktime )'); } + const valid = new Validator([args]); + const inputs = valid.array(0); + const sendTo = valid.obj(1); + const locktime = valid.u32(2); + if (!inputs || !sendTo) { throw new RPCError(errs.TYPE_ERROR, 'Invalid parameters (inputs and sendTo).'); } - tx = new MTX(); + const tx = new MTX(); if (locktime != null) tx.locktime = locktime; - for (let input of tx.inputs) { - let valid = new Validator([input]); - let hash = valid.hash('txid'); - let index = valid.u32('vout'); + for (const obj of tx.inputs) { + const valid = new Validator([obj]); + const hash = valid.hash('txid'); + const index = valid.u32('vout'); let sequence = valid.u32('sequence', 0xffffffff); if (tx.locktime) @@ -1665,7 +1658,7 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h if (!hash || index == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid outpoint.'); - input = new Input(); + const input = new Input(); input.prevout.hash = hash; input.prevout.index = index; input.sequence = sequence; @@ -1673,21 +1666,17 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h tx.inputs.push(input); } - keys = Object.keys(sendTo); - valid = new Validator([sendTo]); - addrs = {}; - - for (let key of keys) { - let addr, b58, value, output; + const sends = new Validator([sendTo]); + const uniq = new Set(); + for (const key of Object.keys(sendTo)) { if (key === 'data') { - let value = valid.buf(key); - let output; + const value = sends.buf(key); if (!value) throw new RPCError(errs.TYPE_ERROR, 'Invalid nulldata..'); - output = new Output(); + const output = new Output(); output.value = 0; output.script.fromNulldata(value); tx.outputs.push(output); @@ -1695,20 +1684,20 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h continue; } - addr = parseAddress(key, this.network); - b58 = addr.toString(this.network); + const addr = parseAddress(key, this.network); + const b58 = addr.toString(this.network); - if (addrs[b58]) + if (uniq.has(b58)) throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address'); - addrs[b58] = true; + uniq.add(b58); - value = valid.btc(key); + const value = sends.ufixed(key, 8); if (value == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid output value.'); - output = new Output(); + const output = new Output(); output.value = value; output.script.fromAddress(addr); @@ -1719,88 +1708,85 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h }; RPC.prototype.decodeRawTransaction = async function decodeRawTransaction(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let tx; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'decoderawtransaction "hexstring"'); + const valid = new Validator([args]); + const data = valid.buf(0); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid hex string.'); - tx = TX.fromRaw(data); + const tx = TX.fromRaw(data); return this.txToJSON(tx); }; RPC.prototype.decodeScript = async function decodeScript(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let script, addr; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'decodescript "hex"'); - script = new Script(); + const valid = new Validator([args]); + const data = valid.buf(0); + + let script = new Script(); if (data) script = Script.fromRaw(data); - addr = Address.fromScripthash(script.hash160()); + const addr = Address.fromScripthash(script.hash160()); - script = this.scriptToJSON(script); - script.p2sh = addr.toString(this.network); + const json = this.scriptToJSON(script); + json.p2sh = addr.toString(this.network); - return script; + return json; }; RPC.prototype.getRawTransaction = async function getRawTransaction(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - let verbose = valid.bool(1, false); - let json, meta, tx, entry; - if (help || args.length < 1 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'getrawtransaction "txid" ( verbose )'); + const valid = new Validator([args]); + const hash = valid.hash(0); + const verbose = valid.bool(1, false); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); - meta = await this.node.getMeta(hash); + const meta = await this.node.getMeta(hash); if (!meta) - throw new RPCError(errs.MISC_ERROR, 'Transaction not found.'); + throw new RPCError(errs.INVALID_ADDRESS_OR_KEY, 'Transaction not found.'); - tx = meta.tx; + const tx = meta.tx; if (!verbose) return tx.toRaw().toString('hex'); + let entry; if (meta.block) entry = await this.chain.db.getEntry(meta.block); - json = this.txToJSON(tx, entry); - json.time = meta.ps; + const json = this.txToJSON(tx, entry); + json.time = meta.mtime; json.hex = tx.toRaw().toString('hex'); return json; }; RPC.prototype.sendRawTransaction = async function sendRawTransaction(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let tx; - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'sendrawtransaction "hexstring" ( allowhighfees )'); } + const valid = new Validator([args]); + const data = valid.buf(0); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid hex string.'); - tx = TX.fromRaw(data); + const tx = TX.fromRaw(data); this.node.relay(tx); @@ -1808,16 +1794,6 @@ RPC.prototype.sendRawTransaction = async function sendRawTransaction(args, help) }; RPC.prototype.signRawTransaction = async function signRawTransaction(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let prevout = valid.array(1); - let secrets = valid.array(2); - let sighash = valid.str(3); - let type = Script.hashType.ALL; - let keys = []; - let map = {}; - let tx; - if (help || args.length < 1 || args.length > 4) { throw new RPCError(errs.MISC_ERROR, 'signrawtransaction' @@ -1827,66 +1803,71 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help) + ' sighashtype )'); } + const valid = new Validator([args]); + const data = valid.buf(0); + const prevout = valid.array(1); + const secrets = valid.array(2); + const sighash = valid.str(3); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid hex string.'); if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); - tx = MTX.fromRaw(data); + const tx = MTX.fromRaw(data); tx.view = await this.mempool.getSpentView(tx); + const map = new Map(); + const keys = []; + if (secrets) { - let valid = new Validator([secrets]); + const valid = new Validator([secrets]); for (let i = 0; i < secrets.length; i++) { - let secret = valid.str(i, ''); - let key = parseSecret(secret, this.network); - map[key.getPublicKey('hex')] = key; + const secret = valid.str(i, ''); + const key = parseSecret(secret, this.network); + map.set(key.getPublicKey('hex'), key); keys.push(key); } } if (prevout) { - for (let prev of prevout) { - let valid = new Validator([prev]); - let hash = valid.hash('txid'); - let index = valid.u32('index'); - let script = valid.buf('scriptPubKey'); - let value = valid.btc('amount'); - let redeem = valid.buf('redeemScript'); - let coin; - - if (!hash || index == null || !script || value == null) + for (const prev of prevout) { + const valid = new Validator([prev]); + const hash = valid.hash('txid'); + const index = valid.u32('index'); + const scriptRaw = valid.buf('scriptPubKey'); + const value = valid.ufixed('amount', 8); + const redeemRaw = valid.buf('redeemScript'); + + if (!hash || index == null || !scriptRaw || value == null) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid UTXO.'); - script = Script.fromRaw(script); + const outpoint = new Outpoint(hash, index); - coin = new Output(); - coin.script = script; - coin.value = value; + const script = Script.fromRaw(scriptRaw); + const coin = Output.fromScript(script, value); - tx.view.addOutput(hash, index, coin); + tx.view.addOutput(outpoint, coin); - if (keys.length === 0 || !redeem) + if (keys.length === 0 || !redeemRaw) continue; if (!script.isScripthash() && !script.isWitnessScripthash()) continue; - if (!redeem) { + if (!redeemRaw) { throw new RPCError(errs.INVALID_PARAMETER, 'P2SH requires redeem script.'); } - redeem = Script.fromRaw(redeem); - - for (let op of redeem.code) { - let key; + const redeem = Script.fromRaw(redeemRaw); + for (const op of redeem.code) { if (!op.data) continue; - key = map[op.data.toString('hex')]; + const key = map.get(op.data.toString('hex')); if (key) { key.script = redeem; @@ -1898,14 +1879,16 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help) } } + let type = Script.hashType.ALL; if (sighash) { - let parts = sighash.split('|'); - let type = Script.hashType[parts[0]]; + const parts = sighash.split('|'); - if (type == null) + if (parts.length < 1 || parts.length > 2) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid sighash type.'); - if (parts.length > 2) + type = Script.hashType[parts[0]]; + + if (type == null) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid sighash type.'); if (parts.length === 2) { @@ -1928,22 +1911,21 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help) */ RPC.prototype.createMultisig = async function createMultisig(args, help) { - let valid = new Validator([args]); - let keys = valid.array(1, []); - let m = valid.u32(0, 0); - let n = keys.length; - let script, addr; - if (help || args.length < 2 || args.length > 2) throw new RPCError(errs.MISC_ERROR, 'createmultisig nrequired ["key",...]'); + const valid = new Validator([args]); + const keys = valid.array(1, []); + const m = valid.u32(0, 0); + const n = keys.length; + if (m < 1 || n < m || n > 16) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid m and n values.'); - valid = new Validator([keys]); + const items = new Validator([keys]); for (let i = 0; i < keys.length; i++) { - let key = valid.buf(i); + const key = items.buf(i); if (!key) throw new RPCError(errs.TYPE_ERROR, 'Invalid key.'); @@ -1954,12 +1936,12 @@ RPC.prototype.createMultisig = async function createMultisig(args, help) { keys[i] = key; } - script = Script.fromMultisig(m, n, keys); + const script = Script.fromMultisig(m, n, keys); if (script.getSize() > consensus.MAX_SCRIPT_PUSH) throw new RPCError(errs.VERIFY_ERROR, 'Redeem script exceeds size limit.'); - addr = script.getAddress(); + const addr = script.getAddress(); return { address: addr.toString(this.network), @@ -1968,19 +1950,18 @@ RPC.prototype.createMultisig = async function createMultisig(args, help) { }; RPC.prototype.createWitnessAddress = async function createWitnessAddress(args, help) { - let valid = new Validator([args]); - let raw = valid.buf(0); - let script, program, addr; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'createwitnessaddress "script"'); + const valid = new Validator([args]); + const raw = valid.buf(0); + if (!raw) throw new RPCError(errs.TYPE_ERROR, 'Invalid script hex.'); - script = Script.fromRaw(raw); - program = script.forWitness(); - addr = program.getAddress(); + const script = Script.fromRaw(raw); + const program = script.forWitness(); + const addr = program.getAddress(); return { address: addr.toString(this.network), @@ -1989,22 +1970,22 @@ RPC.prototype.createWitnessAddress = async function createWitnessAddress(args, h }; RPC.prototype.validateAddress = async function validateAddress(args, help) { - let valid = new Validator([args]); - let b58 = valid.str(0, ''); - let addr, script; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'validateaddress "bitcoinaddress"'); + const valid = new Validator([args]); + const str = valid.str(0, ''); + + let addr; try { - addr = Address.fromString(b58, this.network); + addr = Address.fromString(str, this.network); } catch (e) { return { isvalid: false }; } - script = Script.fromAddress(addr); + const script = Script.fromAddress(addr); return { isvalid: true, @@ -2016,70 +1997,60 @@ RPC.prototype.validateAddress = async function validateAddress(args, help) { }; RPC.prototype.verifyMessage = async function verifyMessage(args, help) { - let valid = new Validator([args]); - let b58 = valid.str(0, ''); - let sig = valid.buf(1, null, 'base64'); - let msg = valid.str(2); - let addr, key; - if (help || args.length !== 3) { throw new RPCError(errs.MISC_ERROR, 'verifymessage "bitcoinaddress" "signature" "message"'); } - if (!sig || !msg) - throw new RPCError(errs.TYPE_ERROR, 'Invalid parameters.'); + const valid = new Validator([args]); + const b58 = valid.str(0, ''); + const sig = valid.buf(1, null, 'base64'); + const str = valid.str(2); - addr = parseAddress(b58, this.network); + if (!sig || !str) + throw new RPCError(errs.TYPE_ERROR, 'Invalid parameters.'); - msg = Buffer.from(MAGIC_STRING + msg, 'utf8'); - msg = digest.hash256(msg); + const addr = parseAddress(b58, this.network); + const msg = Buffer.from(MAGIC_STRING + str, 'utf8'); + const hash = digest.hash256(msg); - key = secp256k1.recover(msg, sig, 0, true); + const key = secp256k1.recover(hash, sig, 0, true); if (!key) return false; - key = digest.hash160(key); - - return ccmp(key, addr.hash); + return ccmp(digest.hash160(key), addr.hash); }; RPC.prototype.signMessageWithPrivkey = async function signMessageWithPrivkey(args, help) { - let valid = new Validator([args]); - let key = valid.str(0, ''); - let msg = valid.str(1, ''); - let sig; - if (help || args.length !== 2) { throw new RPCError(errs.MISC_ERROR, 'signmessagewithprivkey "privkey" "message"'); } - key = parseSecret(key, this.network); - msg = Buffer.from(MAGIC_STRING + msg, 'utf8'); - msg = digest.hash256(msg); + const valid = new Validator([args]); + const wif = valid.str(0, ''); + const str = valid.str(1, ''); - sig = key.sign(msg); + const key = parseSecret(wif, this.network); + const msg = Buffer.from(MAGIC_STRING + str, 'utf8'); + const hash = digest.hash256(msg); + const sig = key.sign(hash); return sig.toString('base64'); }; RPC.prototype.estimateFee = async function estimateFee(args, help) { - let valid = new Validator([args]); - let blocks = valid.u32(0, 1); - let fee; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'estimatefee nblocks'); + const valid = new Validator([args]); + const blocks = valid.u32(0, 1); + if (!this.fees) throw new RPCError(errs.MISC_ERROR, 'Fee estimation not available.'); - if (blocks < 1) - blocks = 1; - - fee = this.fees.estimateFee(blocks, false); + const fee = this.fees.estimateFee(blocks, false); if (fee === 0) return -1; @@ -2088,36 +2059,29 @@ RPC.prototype.estimateFee = async function estimateFee(args, help) { }; RPC.prototype.estimatePriority = async function estimatePriority(args, help) { - let valid = new Validator([args]); - let blocks = valid.u32(0, 1); - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'estimatepriority nblocks'); + const valid = new Validator([args]); + const blocks = valid.u32(0, 1); + if (!this.fees) throw new RPCError(errs.MISC_ERROR, 'Priority estimation not available.'); - if (blocks < 1) - blocks = 1; - return this.fees.estimatePriority(blocks, false); }; RPC.prototype.estimateSmartFee = async function estimateSmartFee(args, help) { - let valid = new Validator([args]); - let blocks = valid.u32(0, 1); - let fee; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'estimatesmartfee nblocks'); + const valid = new Validator([args]); + const blocks = valid.u32(0, 1); + if (!this.fees) throw new RPCError(errs.MISC_ERROR, 'Fee estimation not available.'); - if (blocks < 1) - blocks = 1; - - fee = this.fees.estimateFee(blocks, true); + let fee = this.fees.estimateFee(blocks, true); if (fee === 0) fee = -1; @@ -2131,20 +2095,16 @@ RPC.prototype.estimateSmartFee = async function estimateSmartFee(args, help) { }; RPC.prototype.estimateSmartPriority = async function estimateSmartPriority(args, help) { - let valid = new Validator([args]); - let blocks = valid.u32(0, 1); - let pri; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'estimatesmartpriority nblocks'); + const valid = new Validator([args]); + const blocks = valid.u32(0, 1); + if (!this.fees) throw new RPCError(errs.MISC_ERROR, 'Priority estimation not available.'); - if (blocks < 1) - blocks = 1; - - pri = this.fees.estimatePriority(blocks, true); + const pri = this.fees.estimatePriority(blocks, true); return { priority: pri, @@ -2153,12 +2113,12 @@ RPC.prototype.estimateSmartPriority = async function estimateSmartPriority(args, }; RPC.prototype.invalidateBlock = async function invalidateBlock(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'invalidateblock "hash"'); + const valid = new Validator([args]); + const hash = valid.hash(0); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.'); @@ -2168,12 +2128,12 @@ RPC.prototype.invalidateBlock = async function invalidateBlock(args, help) { }; RPC.prototype.reconsiderBlock = async function reconsiderBlock(args, help) { - let valid = new Validator([args]); - let hash = valid.hash(0); - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'reconsiderblock "hash"'); + const valid = new Validator([args]); + const hash = valid.hash(0); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.'); @@ -2183,19 +2143,18 @@ RPC.prototype.reconsiderBlock = async function reconsiderBlock(args, help) { }; RPC.prototype.setMockTime = async function setMockTime(args, help) { - let valid = new Validator([args]); - let ts = valid.u32(0); - let delta; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'setmocktime timestamp'); - if (ts == null) + const valid = new Validator([args]); + const time = valid.u32(0); + + if (time == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid timestamp.'); this.network.time.offset = 0; - delta = this.network.now() - ts; + const delta = this.network.now() - time; this.network.time.offset = -delta; @@ -2210,12 +2169,12 @@ RPC.prototype.getMemoryInfo = async function getMemoryInfo(args, help) { }; RPC.prototype.setLogLevel = async function setLogLevel(args, help) { - let valid = new Validator([args]); - let level = valid.str(0, ''); - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'setloglevel "level"'); + const valid = new Validator([args]); + const level = valid.str(0, ''); + this.logger.setLevel(level); return null; @@ -2226,20 +2185,18 @@ RPC.prototype.setLogLevel = async function setLogLevel(args, help) { */ RPC.prototype.handleLongpoll = async function handleLongpoll(lpid) { - let watched, lastTX; - if (lpid.length !== 74) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid longpoll ID.'); - watched = lpid.slice(0, 64); - lastTX = +lpid.slice(64, 74); + const watched = lpid.slice(0, 64); + const lastTX = parseInt(lpid.slice(64, 74), 10); - if (!util.isHex(watched) || !util.isNumber(lastTX) || lastTX < 0) + if (!util.isHex(watched) || !util.isU32(lastTX)) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid longpoll ID.'); - watched = util.revHex(watched); + const hash = util.revHex(watched); - if (this.chain.tip.hash !== watched) + if (this.chain.tip.hash !== hash) return; await this.longpoll(); @@ -2252,7 +2209,7 @@ RPC.prototype.longpoll = function longpoll() { }; RPC.prototype.refreshBlock = function refreshBlock() { - let pollers = this.pollers; + const pollers = this.pollers; this.attempt = null; this.lastActivity = 0; @@ -2261,7 +2218,7 @@ RPC.prototype.refreshBlock = function refreshBlock() { this.nonce2 = 0; this.pollers = []; - for (let job of pollers) + for (const job of pollers) job.resolve(); }; @@ -2291,10 +2248,10 @@ RPC.prototype.bindChain = function bindChain() { }; RPC.prototype.getTemplate = async function getTemplate() { - let attempt = this.attempt; - this.bindChain(); + let attempt = this.attempt; + if (attempt) { this.miner.updateTime(attempt); } else { @@ -2307,11 +2264,10 @@ RPC.prototype.getTemplate = async function getTemplate() { }; RPC.prototype.updateWork = async function updateWork() { - let attempt = this.attempt; - let root, n1, n2; - this.bindChain(); + let attempt = this.attempt; + if (attempt) { if (attempt.address.isNull()) { throw new RPCError(errs.MISC_ERROR, @@ -2325,13 +2281,13 @@ RPC.prototype.updateWork = async function updateWork() { this.nonce1++; } - n1 = this.nonce1; - n2 = this.nonce2; + const n1 = this.nonce1; + const n2 = this.nonce2; - root = attempt.getRoot(n1, n2); - root = root.toString('hex'); + const root = attempt.getRoot(n1, n2); + const hash = root.toString('hex'); - this.merkleMap.set(root, new Nonces(n1, n2)); + this.merkleMap.set(hash, [n1, n2]); return attempt; } @@ -2343,22 +2299,22 @@ RPC.prototype.updateWork = async function updateWork() { attempt = await this.miner.createBlock(); - n1 = this.nonce1; - n2 = this.nonce2; + const n1 = this.nonce1; + const n2 = this.nonce2; - root = attempt.getRoot(n1, n2); - root = root.toString('hex'); + const root = attempt.getRoot(n1, n2); + const hash = root.toString('hex'); this.attempt = attempt; this.lastActivity = util.now(); - this.merkleMap.set(root, new Nonces(n1, n2)); + this.merkleMap.set(hash, [n1, n2]); return attempt; }; RPC.prototype.addBlock = async function addBlock(block) { - let unlock1 = await this.locker.lock(); - let unlock2 = await this.chain.locker.lock(); + const unlock1 = await this.locker.lock(); + const unlock2 = await this.chain.locker.lock(); try { return await this._addBlock(block); } finally { @@ -2368,25 +2324,24 @@ RPC.prototype.addBlock = async function addBlock(block) { }; RPC.prototype._addBlock = async function _addBlock(block) { - let entry, prev; - this.logger.info('Handling submitted block: %s.', block.rhash()); - prev = await this.chain.db.getEntry(block.prevBlock); + const prev = await this.chain.db.getEntry(block.prevBlock); if (prev) { - let state = await this.chain.getDeployments(block.ts, prev); + const state = await this.chain.getDeployments(block.time, prev); // Fix eloipool bug (witness nonce is not present). if (state.hasWitness() && block.getCommitmentHash()) { - let tx = block.txs[0]; + const tx = block.txs[0]; + const input = tx.inputs[0]; if (!tx.hasWitness()) { this.logger.warning('Submitted block had no witness nonce.'); this.logger.debug(tx); // Recreate witness nonce (all zeroes). - tx.inputs[0].witness.set(0, encoding.ZERO_HASH); - tx.inputs[0].witness.compile(); + input.witness.push(encoding.ZERO_HASH); + input.witness.compile(); tx.refresh(); block.refresh(); @@ -2394,6 +2349,7 @@ RPC.prototype._addBlock = async function _addBlock(block) { } } + let entry; try { entry = await this.chain._add(block); } catch (err) { @@ -2427,11 +2383,11 @@ RPC.prototype.getSoftforks = function getSoftforks() { }; RPC.prototype.getBIP9Softforks = async function getBIP9Softforks() { - let tip = this.chain.tip; - let forks = {}; + const tip = this.chain.tip; + const forks = {}; - for (let deployment of this.network.deploys) { - let state = await this.chain.getState(tip, deployment); + for (const deployment of this.network.deploys) { + const state = await this.chain.getState(tip, deployment); let status; switch (state) { @@ -2468,7 +2424,6 @@ RPC.prototype.getBIP9Softforks = async function getBIP9Softforks() { RPC.prototype.getHashRate = async function getHashRate(lookup, height) { let tip = this.chain.tip; - let minTime, maxTime, workDiff, timeDiff, ps, entry; if (height != null) tip = await this.chain.db.getEntry(height); @@ -2476,38 +2431,41 @@ RPC.prototype.getHashRate = async function getHashRate(lookup, height) { if (!tip) return 0; - if (lookup <= 0) + assert(typeof lookup === 'number'); + assert(lookup >= 0); + + if (lookup === 0) lookup = tip.height % this.network.pow.retargetInterval + 1; if (lookup > tip.height) lookup = tip.height; - minTime = tip.ts; - maxTime = minTime; - entry = tip; + let min = tip.time; + let max = min; + let entry = tip; for (let i = 0; i < lookup; i++) { - let entry = await entry.getPrevious(); + entry = await entry.getPrevious(); if (!entry) throw new RPCError(errs.DATABASE_ERROR, 'Not found.'); - minTime = Math.min(entry.ts, minTime); - maxTime = Math.max(entry.ts, maxTime); + min = Math.min(entry.time, min); + max = Math.max(entry.time, max); } - if (minTime === maxTime) + const diff = max - min; + + if (diff === 0) return 0; - workDiff = tip.chainwork.sub(entry.chainwork); - timeDiff = maxTime - minTime; - ps = +workDiff.toString(10) / timeDiff; + const work = tip.chainwork.sub(entry.chainwork); - return ps; + return Number(work.toString()) / diff; }; RPC.prototype.mineBlocks = async function mineBlocks(blocks, addr, tries) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._mineBlocks(blocks, addr, tries); } finally { @@ -2516,12 +2474,13 @@ RPC.prototype.mineBlocks = async function mineBlocks(blocks, addr, tries) { }; RPC.prototype._mineBlocks = async function _mineBlocks(blocks, addr, tries) { - let hashes = []; + const hashes = []; for (let i = 0; i < blocks; i++) { - let block = await this.miner.mineBlock(null, addr); - hashes.push(block.rhash()); - assert(await this.chain.add(block)); + const block = await this.miner.mineBlock(null, addr); + const entry = await this.chain.add(block); + assert(entry); + hashes.push(entry.rhash()); } return hashes; @@ -2538,21 +2497,21 @@ RPC.prototype.findFork = async function findFork(entry) { RPC.prototype.txToJSON = function txToJSON(tx, entry) { let height = -1; - let conf = 0; let time = 0; let hash = null; - let vin = []; - let vout = []; + let conf = 0; if (entry) { height = entry.height; - time = entry.ts; + time = entry.time; hash = entry.rhash(); conf = this.chain.height - height + 1; } - for (let input of tx.inputs) { - let json = { + const vin = []; + + for (const input of tx.inputs) { + const json = { coinbase: undefined, txid: undefined, scriptSig: undefined, @@ -2580,8 +2539,10 @@ RPC.prototype.txToJSON = function txToJSON(tx, entry) { vin.push(json); } + const vout = []; + for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; + const output = tx.outputs[i]; vout.push({ value: Amount.btc(output.value, true), n: i, @@ -2607,11 +2568,9 @@ RPC.prototype.txToJSON = function txToJSON(tx, entry) { }; RPC.prototype.scriptToJSON = function scriptToJSON(script, hex) { - let type = script.getType(); - let addr = script.getAddress(); - let out; + const type = script.getType(); - out = { + const json = { asm: script.toASM(), hex: undefined, type: Script.typesByVal[type], @@ -2621,22 +2580,26 @@ RPC.prototype.scriptToJSON = function scriptToJSON(script, hex) { }; if (hex) - out.hex = script.toJSON(); + json.hex = script.toJSON(); + + const [m] = script.getMultisig(); - if (script.isMultisig()) - out.reqSigs = script.getSmall(0); + if (m !== -1) + json.reqSigs = m; + + const addr = script.getAddress(); if (addr) { - addr = addr.toString(this.network); - out.addresses.push(addr); + const str = addr.toString(this.network); + json.addresses.push(str); } - return out; + return json; }; RPC.prototype.headerToJSON = async function headerToJSON(entry) { - let mtp = await entry.getMedianTime(); - let next = await this.chain.db.getNextHash(entry.hash); + const mtp = await entry.getMedianTime(); + const next = await this.chain.db.getNextHash(entry.hash); return { hash: entry.rhash(), @@ -2645,7 +2608,7 @@ RPC.prototype.headerToJSON = async function headerToJSON(entry) { version: entry.version, versionHex: util.hex32(entry.version), merkleroot: util.revHex(entry.merkleRoot), - time: entry.ts, + time: entry.time, mediantime: mtp, bits: entry.bits, difficulty: toDifficulty(entry.bits), @@ -2658,13 +2621,13 @@ RPC.prototype.headerToJSON = async function headerToJSON(entry) { }; RPC.prototype.blockToJSON = async function blockToJSON(entry, block, details) { - let mtp = await entry.getMedianTime(); - let next = await this.chain.db.getNextHash(entry.hash); - let txs = []; + const mtp = await entry.getMedianTime(); + const next = await this.chain.db.getNextHash(entry.hash); + const txs = []; - for (let tx of block.txs) { + for (const tx of block.txs) { if (details) { - let json = this.txToJSON(tx, entry); + const json = this.txToJSON(tx, entry); txs.push(json); continue; } @@ -2683,7 +2646,7 @@ RPC.prototype.blockToJSON = async function blockToJSON(entry, block, details) { merkleroot: util.revHex(entry.merkleRoot), coinbase: block.txs[0].inputs[0].script.toJSON(), tx: txs, - time: entry.ts, + time: entry.time, mediantime: mtp, bits: entry.bits, difficulty: toDifficulty(entry.bits), @@ -2700,7 +2663,7 @@ RPC.prototype.entryToJSON = function entryToJSON(entry) { size: entry.size, fee: Amount.btc(entry.deltaFee, true), modifiedfee: 0, - time: entry.ts, + time: entry.time, height: entry.height, startingpriority: entry.priority, currentpriority: entry.getPriority(this.chain.height), @@ -2720,7 +2683,7 @@ RPC.prototype.entryToJSON = function entryToJSON(entry) { function swap32(data) { for (let i = 0; i < data.length; i += 4) { - let field = data.readUInt32LE(i, true); + const field = data.readUInt32LE(i, true); data.writeUInt32BE(field, i, true); } return data; @@ -2736,11 +2699,6 @@ function toDeployment(id, version, status) { }; } -function Nonces(n1, n2) { - this.nonce1 = n1; - this.nonce2 = n2; -} - function parseAddress(raw, network) { try { return Address.fromString(raw, network); diff --git a/lib/http/rpcbase.js b/lib/http/rpcbase.js index ead171b91..038c15504 100644 --- a/lib/http/rpcbase.js +++ b/lib/http/rpcbase.js @@ -8,7 +8,6 @@ const assert = require('assert'); const EventEmitter = require('events'); -const util = require('../utils/util'); const Lock = require('../utils/lock'); const Logger = require('../node/logger'); @@ -25,12 +24,12 @@ function RPCBase() { EventEmitter.call(this); this.logger = Logger.global; - this.calls = {}; + this.calls = Object.create(null); this.mounts = []; this.locker = new Lock(); } -util.inherits(RPCBase, EventEmitter); +Object.setPrototypeOf(RPCBase.prototype, EventEmitter.prototype); /** * RPC errors. @@ -111,9 +110,7 @@ RPCBase.prototype.call = async function call(body, query) { array = false; } - for (let cmd of cmds) { - let result; - + for (const cmd of cmds) { if (!cmd || typeof cmd !== 'object') { out.push({ result: null, @@ -183,6 +180,7 @@ RPCBase.prototype.call = async function call(body, query) { cmd.method = 'getworklp'; } + let result; try { result = await this.execute(cmd); } catch (err) { @@ -245,10 +243,10 @@ RPCBase.prototype.call = async function call(body, query) { */ RPCBase.prototype.execute = async function execute(json, help) { - let func = this.calls[json.method]; + const func = this.calls[json.method]; if (!func) { - for (let mount of this.mounts) { + for (const mount of this.mounts) { if (mount.calls[json.method]) return await mount.execute(json, help); } @@ -313,7 +311,7 @@ function RPCError(code, msg) { Error.captureStackTrace(this, RPCError); } -util.inherits(RPCError, Error); +Object.setPrototypeOf(RPCError.prototype, Error.prototype); /* * Expose diff --git a/lib/http/rpcclient.js b/lib/http/rpcclient.js index 9abc8f742..c8a498bd9 100644 --- a/lib/http/rpcclient.js +++ b/lib/http/rpcclient.js @@ -8,7 +8,6 @@ const Network = require('../protocol/network'); const request = require('./request'); -const util = require('../utils/util'); /** * Bcoin RPC client. @@ -45,7 +44,7 @@ function RPCClient(options) { */ RPCClient.prototype.execute = async function execute(method, params) { - let res = await request({ + const res = await request({ method: 'POST', uri: this.uri, pool: true, @@ -86,14 +85,14 @@ function RPCError(msg, code) { Error.call(this); this.type = 'RPCError'; - this.message = msg + ''; + this.message = String(msg); this.code = code >>> 0; if (Error.captureStackTrace) Error.captureStackTrace(this, RPCError); } -util.inherits(RPCError, Error); +Object.setPrototypeOf(RPCError.prototype, Error.prototype); /* * Expose diff --git a/lib/http/server.js b/lib/http/server.js index a5c7d0975..7b55b3341 100644 --- a/lib/http/server.js +++ b/lib/http/server.js @@ -55,7 +55,7 @@ function HTTPServer(options) { this.init(); } -util.inherits(HTTPServer, HTTPBase); +Object.setPrototypeOf(HTTPServer.prototype, HTTPBase.prototype); /** * Initialize routes. @@ -102,8 +102,8 @@ HTTPServer.prototype.initRouter = function initRouter() { this.use(this.jsonRPC(this.rpc)); this.get('/', async (req, res) => { - let totalTX = this.mempool ? this.mempool.map.size : 0; - let size = this.mempool ? this.mempool.getSize() : 0; + const totalTX = this.mempool ? this.mempool.map.size : 0; + const size = this.mempool ? this.mempool.getSize() : 0; let addr = this.pool.hosts.getLocal(); if (!addr) @@ -141,17 +141,16 @@ HTTPServer.prototype.initRouter = function initRouter() { // UTXO by address this.get('/coin/address/:address', async (req, res) => { - let valid = req.valid(); - let address = valid.str('address'); - let result = []; - let coins; + const valid = req.valid(); + const address = valid.str('address'); enforce(address, 'Address is required.'); enforce(!this.chain.options.spv, 'Cannot get coins in SPV mode.'); - coins = await this.node.getCoinsByAddress(address); + const coins = await this.node.getCoinsByAddress(address); + const result = []; - for (let coin of coins) + for (const coin of coins) result.push(coin.getJSON(this.network)); res.send(200, result); @@ -159,16 +158,15 @@ HTTPServer.prototype.initRouter = function initRouter() { // UTXO by id this.get('/coin/:hash/:index', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); - let index = valid.u32('index'); - let coin; + const valid = req.valid(); + const hash = valid.hash('hash'); + const index = valid.u32('index'); enforce(hash, 'Hash is required.'); enforce(index != null, 'Index is required.'); enforce(!this.chain.options.spv, 'Cannot get coins in SPV mode.'); - coin = await this.node.getCoin(hash, index); + const coin = await this.node.getCoin(hash, index); if (!coin) { res.send(404); @@ -180,17 +178,16 @@ HTTPServer.prototype.initRouter = function initRouter() { // Bulk read UTXOs this.post('/coin/address', async (req, res) => { - let valid = req.valid(); - let address = valid.array('addresses'); - let result = []; - let coins; + const valid = req.valid(); + const address = valid.array('addresses'); enforce(address, 'Address is required.'); enforce(!this.chain.options.spv, 'Cannot get coins in SPV mode.'); - coins = await this.node.getCoinsByAddress(address); + const coins = await this.node.getCoinsByAddress(address); + const result = []; - for (let coin of coins) + for (const coin of coins) result.push(coin.getJSON(this.network)); res.send(200, result); @@ -198,39 +195,37 @@ HTTPServer.prototype.initRouter = function initRouter() { // TX by hash this.get('/tx/:hash', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); - let meta, view; + const valid = req.valid(); + const hash = valid.hash('hash'); enforce(hash, 'Hash is required.'); enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.'); - meta = await this.node.getMeta(hash); + const meta = await this.node.getMeta(hash); if (!meta) { res.send(404); return; } - view = await this.node.getMetaView(meta); + const view = await this.node.getMetaView(meta); res.send(200, meta.getJSON(this.network, view)); }); // TX by address this.get('/tx/address/:address', async (req, res) => { - let valid = req.valid(); - let address = valid.str('address'); - let result = []; - let metas; + const valid = req.valid(); + const address = valid.str('address'); enforce(address, 'Address is required.'); enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.'); - metas = await this.node.getMetaByAddress(address); + const metas = await this.node.getMetaByAddress(address); + const result = []; - for (let meta of metas) { - let view = await this.node.getMetaView(meta); + for (const meta of metas) { + const view = await this.node.getMetaView(meta); result.push(meta.getJSON(this.network, view)); } @@ -239,18 +234,17 @@ HTTPServer.prototype.initRouter = function initRouter() { // Bulk read TXs this.post('/tx/address', async (req, res) => { - let valid = req.valid(); - let address = valid.array('address'); - let result = []; - let metas; + const valid = req.valid(); + const address = valid.array('addresses'); enforce(address, 'Address is required.'); enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.'); - metas = await this.node.getMetaByAddress(address); + const metas = await this.node.getMetaByAddress(address); + const result = []; - for (let meta of metas) { - let view = await this.node.getMetaView(meta); + for (const meta of metas) { + const view = await this.node.getMetaView(meta); result.push(meta.getJSON(this.network, view)); } @@ -259,9 +253,8 @@ HTTPServer.prototype.initRouter = function initRouter() { // Block by hash/height this.get('/block/:block', async (req, res) => { - let valid = req.valid(); + const valid = req.valid(); let hash = valid.get('block'); - let block, view, height; enforce(typeof hash === 'string', 'Hash or height required.'); enforce(!this.chain.options.spv, 'Cannot get block in SPV mode.'); @@ -269,37 +262,35 @@ HTTPServer.prototype.initRouter = function initRouter() { if (hash.length === 64) hash = util.revHex(hash); else - hash = +hash; + hash = parseInt(hash, 10); - block = await this.chain.db.getBlock(hash); + const block = await this.chain.db.getBlock(hash); if (!block) { res.send(404); return; } - view = await this.chain.db.getBlockView(block); + const view = await this.chain.db.getBlockView(block); if (!view) { res.send(404); return; } - height = await this.chain.db.getHeight(hash); + const height = await this.chain.db.getHeight(hash); res.send(200, block.getJSON(this.network, view, height)); }); // Mempool snapshot this.get('/mempool', async (req, res) => { - let result = []; - let hashes; - enforce(this.mempool, 'No mempool available.'); - hashes = this.mempool.getSnapshot(); + const hashes = this.mempool.getSnapshot(); + const result = []; - for (let hash of hashes) + for (const hash of hashes) result.push(util.revHex(hash)); res.send(200, result); @@ -307,13 +298,12 @@ HTTPServer.prototype.initRouter = function initRouter() { // Broadcast TX this.post('/broadcast', async (req, res) => { - let valid = req.valid(); - let raw = valid.buf('tx'); - let tx; + const valid = req.valid(); + const raw = valid.buf('tx'); enforce(raw, 'TX is required.'); - tx = TX.fromRaw(raw); + const tx = TX.fromRaw(raw); await this.node.sendTX(tx); @@ -322,24 +312,23 @@ HTTPServer.prototype.initRouter = function initRouter() { // Estimate fee this.get('/fee', async (req, res) => { - let valid = req.valid(); - let blocks = valid.u32('blocks'); - let fee; + const valid = req.valid(); + const blocks = valid.u32('blocks'); if (!this.fees) { res.send(200, { rate: this.network.feeRate }); return; } - fee = this.fees.estimateFee(blocks); + const fee = this.fees.estimateFee(blocks); res.send(200, { rate: fee }); }); // Reset chain this.post('/reset', async (req, res) => { - let valid = req.valid(); - let height = valid.u32('height'); + const valid = req.valid(); + const height = valid.u32('height'); enforce(height != null, 'Height is required.'); @@ -371,16 +360,21 @@ HTTPServer.prototype.initSockets = function initSockets() { HTTPServer.prototype.handleSocket = function handleSocket(socket) { socket.hook('auth', (args) => { - let valid = new Validator([args]); - let hash = this.options.apiHash; - let key = valid.str(0); - if (socket.auth) throw new Error('Already authed.'); if (!this.options.noAuth) { - if (!ccmp(hash256(key), hash)) - throw new Error('Bad key.'); + const valid = new Validator([args]); + const key = valid.str(0, ''); + + if (key.length > 255) + throw new Error('Invalid API key.'); + + const data = Buffer.from(key, 'ascii'); + const hash = digest.hash256(data); + + if (!ccmp(hash, this.options.apiHash)) + throw new Error('Invalid API key.'); } socket.auth = true; @@ -425,8 +419,8 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { }); socket.hook('set filter', (args) => { - let valid = new Validator([args]); - let data = valid.buf(0); + const valid = new Validator([args]); + const data = valid.buf(0); if (!data) throw new Error('Invalid parameter.'); @@ -441,27 +435,26 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { }); socket.hook('get entry', async (args) => { - let valid = new Validator([args]); - let block = valid.numhash(0); - let entry; + const valid = new Validator([args]); + const block = valid.numhash(0); if (block == null) throw new Error('Invalid parameter.'); - entry = await this.chain.db.getEntry(block); - - if (!(await entry.isMainChain())) - entry = null; + const entry = await this.chain.db.getEntry(block); if (!entry) return null; + if (!await entry.isMainChain()) + return null; + return entry.toRaw(); }); socket.hook('add filter', (args) => { - let valid = new Validator([args]); - let chunks = valid.array(0); + const valid = new Validator([args]); + const chunks = valid.array(0); if (!chunks) throw new Error('Invalid parameter.'); @@ -469,10 +462,10 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { if (!socket.filter) throw new Error('No filter set.'); - valid = new Validator([chunks]); + const items = new Validator([chunks]); for (let i = 0; i < chunks.length; i++) { - let data = valid.buf(i); + const data = items.buf(i); if (!data) throw new Error('Bad data chunk.'); @@ -492,8 +485,8 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { }); socket.hook('estimate fee', (args) => { - let valid = new Validator([args]); - let blocks = valid.u32(0); + const valid = new Validator([args]); + const blocks = valid.u32(0); if (!this.fees) return this.network.feeRate; @@ -502,14 +495,13 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { }); socket.hook('send', (args) => { - let valid = new Validator([args]); - let data = valid.buf(0); - let tx; + const valid = new Validator([args]); + const data = valid.buf(0); if (!data) throw new Error('Invalid parameter.'); - tx = TX.fromRaw(data); + const tx = TX.fromRaw(data); this.node.send(tx); @@ -517,8 +509,8 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { }); socket.hook('rescan', (args) => { - let valid = new Validator([args]); - let start = valid.numhash(0); + const valid = new Validator([args]); + const start = valid.numhash(0); if (start == null) throw new Error('Invalid parameter.'); @@ -535,62 +527,58 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { */ HTTPServer.prototype.bindChain = function bindChain() { - let pool = this.mempool || this.pool; + const pool = this.mempool || this.pool; this.chain.on('connect', (entry, block, view) => { - let list = this.channel('chain'); - let raw; + const list = this.channel('chain'); if (!list) return; - raw = entry.toRaw(); + const raw = entry.toRaw(); this.to('chain', 'chain connect', raw); for (let item = list.head; item; item = item.next) { - let socket = item.value; - let txs = this.filterBlock(socket, block); + const socket = item.value; + const txs = this.filterBlock(socket, block); socket.emit('block connect', raw, txs); } }); this.chain.on('disconnect', (entry, block, view) => { - let list = this.channel('chain'); - let raw; + const list = this.channel('chain'); if (!list) return; - raw = entry.toRaw(); + const raw = entry.toRaw(); this.to('chain', 'chain disconnect', raw); this.to('chain', 'block disconnect', raw); }); this.chain.on('reset', (tip) => { - let list = this.channel('chain'); - let raw; + const list = this.channel('chain'); if (!list) return; - raw = tip.toRaw(); + const raw = tip.toRaw(); this.to('chain', 'chain reset', raw); }); pool.on('tx', (tx) => { - let list = this.channel('mempool'); - let raw; + const list = this.channel('mempool'); if (!list) return; - raw = tx.toRaw(); + const raw = tx.toRaw(); for (let item = list.head; item; item = item.next) { - let socket = item.value; + const socket = item.value; if (!this.filterTX(socket, tx)) continue; @@ -609,12 +597,12 @@ HTTPServer.prototype.bindChain = function bindChain() { */ HTTPServer.prototype.filterBlock = function filterBlock(socket, block) { - let txs = []; - if (!socket.filter) - return txs; + return []; - for (let tx of block.txs) { + const txs = []; + + for (const tx of block.txs) { if (this.filterTX(socket, tx)) txs.push(tx.toRaw()); } @@ -631,20 +619,20 @@ HTTPServer.prototype.filterBlock = function filterBlock(socket, block) { */ HTTPServer.prototype.filterTX = function filterTX(socket, tx) { - let found = false; - if (!socket.filter) return false; + let found = false; + for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let hash = output.getHash(); + const output = tx.outputs[i]; + const hash = output.getHash(); if (!hash) continue; if (socket.filter.test(hash)) { - let prevout = Outpoint.fromTX(tx, i); + const prevout = Outpoint.fromTX(tx, i); socket.filter.add(prevout.toRaw()); found = true; } @@ -654,7 +642,7 @@ HTTPServer.prototype.filterTX = function filterTX(socket, tx) { return true; if (!tx.isCoinbase()) { - for (let {prevout} of tx.inputs) { + for (const {prevout} of tx.inputs) { if (socket.filter.test(prevout.toRaw())) return true; } @@ -672,7 +660,7 @@ HTTPServer.prototype.filterTX = function filterTX(socket, tx) { */ HTTPServer.prototype.scan = async function scan(socket, start) { - let scanner = this.scanner.bind(this, socket); + const scanner = this.scanner.bind(this, socket); await this.node.scan(start, socket.filter, scanner); return null; }; @@ -687,10 +675,10 @@ HTTPServer.prototype.scan = async function scan(socket, start) { */ HTTPServer.prototype.scanner = function scanner(socket, entry, txs) { - let block = entry.toRaw(); - let raw = []; + const block = entry.toRaw(); + const raw = []; - for (let tx of txs) + for (const tx of txs) raw.push(tx.toRaw()); socket.emit('block rescan', block, raw); @@ -713,7 +701,7 @@ function HTTPOptions(options) { this.logger = null; this.node = null; this.apiKey = base58.encode(random.randomBytes(20)); - this.apiHash = hash256(this.apiKey); + this.apiHash = digest.hash256(Buffer.from(this.apiKey, 'ascii')); this.noAuth = false; this.prefix = null; @@ -752,10 +740,12 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) { if (options.apiKey != null) { assert(typeof options.apiKey === 'string', 'API key must be a string.'); - assert(options.apiKey.length <= 200, - 'API key must be under 200 bytes.'); + assert(options.apiKey.length <= 255, + 'API key must be under 256 bytes.'); + assert(util.isAscii(options.apiKey), + 'API key must be ascii.'); this.apiKey = options.apiKey; - this.apiHash = hash256(this.apiKey); + this.apiHash = digest.hash256(Buffer.from(this.apiKey, 'ascii')); } if (options.noAuth != null) { @@ -776,8 +766,7 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) { } if (options.port != null) { - assert(typeof options.port === 'number', 'Port must be a number.'); - assert(options.port > 0 && options.port <= 0xffff); + assert(util.isU16(options.port), 'Port must be a number.'); this.port = options.port; } @@ -820,19 +809,9 @@ HTTPOptions.fromOptions = function fromOptions(options) { * Helpers */ -function hash256(data) { - if (typeof data !== 'string') - return Buffer.alloc(0); - - if (data.length > 200) - return Buffer.alloc(0); - - return digest.hash256(Buffer.from(data, 'utf8')); -} - function enforce(value, msg) { if (!value) { - let err = new Error(msg); + const err = new Error(msg); err.statusCode = 400; throw err; } diff --git a/lib/http/wallet.js b/lib/http/wallet.js index fd0d910ad..8111ff999 100644 --- a/lib/http/wallet.js +++ b/lib/http/wallet.js @@ -10,7 +10,6 @@ const assert = require('assert'); const EventEmitter = require('events'); const Network = require('../protocol/network'); -const util = require('../utils/util'); const Client = require('./client'); /** @@ -53,7 +52,7 @@ function HTTPWallet(options) { this._init(); } -util.inherits(HTTPWallet, EventEmitter); +Object.setPrototypeOf(HTTPWallet.prototype, EventEmitter.prototype); /** * Initialize the wallet. @@ -123,12 +122,10 @@ HTTPWallet.prototype.open = async function open(options) { */ HTTPWallet.prototype.create = async function create(options) { - let wallet; - await this.client.open(); await this.client.sendWalletAuth(); - wallet = await this.client.createWallet(options); + const wallet = await this.client.createWallet(options); this.id = wallet.id; this.token = wallet.token; @@ -348,7 +345,7 @@ HTTPWallet.prototype.setPassphrase = function setPassphrase(old, new_) { */ HTTPWallet.prototype.retoken = async function retoken(passphrase) { - let token = await this.client.retoken(this.id, passphrase); + const token = await this.client.retoken(this.id, passphrase); this.token = token; this.client.token = token; diff --git a/lib/mempool/fees.js b/lib/mempool/fees.js index ab5769618..2519f4cef 100644 --- a/lib/mempool/fees.js +++ b/lib/mempool/fees.js @@ -133,12 +133,10 @@ ConfirmStats.prototype.clearCurrent = function clearCurrent(height) { */ ConfirmStats.prototype.record = function record(blocks, val) { - let bucketIndex; - if (blocks < 1) return; - bucketIndex = this.bucketMap.search(val); + const bucketIndex = this.bucketMap.search(val); for (let i = blocks; i <= this.curBlockConf.length; i++) this.curBlockConf[i - 1][bucketIndex]++; @@ -173,21 +171,20 @@ ConfirmStats.prototype.updateAverages = function updateAverages() { */ ConfirmStats.prototype.estimateMedian = function estimateMedian(target, needed, breakpoint, greater, height) { + const max = this.buckets.length - 1; + const start = greater ? max : 0; + const step = greater ? -1 : 1; + const bins = this.unconfTX.length; let conf = 0; let total = 0; let extra = 0; - let max = this.buckets.length - 1; - let start = greater ? max : 0; - let step = greater ? -1 : 1; let near = start; let far = start; let bestNear = start; let bestFar = start; let found = false; - let bins = this.unconfTX.length; let median = -1; let sum = 0; - let minBucket, maxBucket; for (let i = start; i >= 0 && i <= max; i += step) { far = i; @@ -200,7 +197,7 @@ ConfirmStats.prototype.estimateMedian = function estimateMedian(target, needed, extra += this.oldUnconfTX[i]; if (total >= needed / (1 - this.decay)) { - let perc = conf / (total + extra); + const perc = conf / (total + extra); if (greater && perc < breakpoint) break; @@ -218,8 +215,8 @@ ConfirmStats.prototype.estimateMedian = function estimateMedian(target, needed, } } - minBucket = bestNear < bestFar ? bestNear : bestFar; - maxBucket = bestNear > bestFar ? bestNear : bestFar; + const minBucket = bestNear < bestFar ? bestNear : bestFar; + const maxBucket = bestNear > bestFar ? bestNear : bestFar; for (let i = minBucket; i <= maxBucket; i++) sum += this.txAvg[i]; @@ -247,8 +244,8 @@ ConfirmStats.prototype.estimateMedian = function estimateMedian(target, needed, */ ConfirmStats.prototype.addTX = function addTX(height, val) { - let bucketIndex = this.bucketMap.search(val); - let blockIndex = height % this.unconfTX.length; + const bucketIndex = this.bucketMap.search(val); + const blockIndex = height % this.unconfTX.length; this.unconfTX[blockIndex][bucketIndex]++; this.logger.spam('Adding tx to %s.', this.type); return bucketIndex; @@ -280,7 +277,7 @@ ConfirmStats.prototype.removeTX = function removeTX(entryHeight, bestHeight, buc bucketIndex); } } else { - let blockIndex = entryHeight % this.unconfTX.length; + const blockIndex = entryHeight % this.unconfTX.length; if (this.unconfTX[blockIndex][bucketIndex] > 0) { this.unconfTX[blockIndex][bucketIndex]--; } else { @@ -318,8 +315,8 @@ ConfirmStats.prototype.getSize = function getSize() { */ ConfirmStats.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeDouble(this.decay); writeArray(bw, this.buckets); @@ -341,13 +338,13 @@ ConfirmStats.prototype.toRaw = function toRaw() { */ ConfirmStats.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let decay = br.readDouble(); - let buckets = readArray(br); - let avg = readArray(br); - let txAvg = readArray(br); - let maxConfirms = br.readVarint(); - let confAvg = new Array(maxConfirms); + const br = new BufferReader(data); + const decay = br.readDouble(); + const buckets = readArray(br); + const avg = readArray(br); + const txAvg = readArray(br); + const maxConfirms = br.readVarint(); + const confAvg = new Array(maxConfirms); for (let i = 0; i < maxConfirms; i++) confAvg[i] = readArray(br); @@ -448,16 +445,18 @@ PolicyEstimator.VERSION = 0; */ PolicyEstimator.prototype.init = function init() { - let minFee = this.minTrackedFee; - let minPri = this.minTrackedPri; - let fee = []; - let priority = []; + const minFee = this.minTrackedFee; + const minPri = this.minTrackedPri; + + const fee = []; for (let b = minFee; b <= MAX_FEERATE; b *= FEE_SPACING) fee.push(b); fee.push(INF_FEERATE); + const priority = []; + for (let b = minPri; b <= MAX_PRIORITY; b *= PRI_SPACING) priority.push(b); @@ -489,7 +488,7 @@ PolicyEstimator.prototype.reset = function reset() { */ PolicyEstimator.prototype.removeTX = function removeTX(hash) { - let item = this.map.get(hash); + const item = this.map.get(hash); if (!item) { this.logger.spam('Mempool tx %s not found.', util.revHex(hash)); @@ -538,9 +537,8 @@ PolicyEstimator.prototype.isPriPoint = function isPriPoint(fee, priority) { */ PolicyEstimator.prototype.processTX = function processTX(entry, current) { - let height = entry.height; - let hash = entry.hash('hex'); - let fee, rate, priority, item; + const height = entry.height; + const hash = entry.hash('hex'); if (this.map.has(hash)) { this.logger.debug('Mempool tx %s already tracked.', entry.txid()); @@ -559,28 +557,25 @@ PolicyEstimator.prototype.processTX = function processTX(entry, current) { if (entry.dependencies) return; - fee = entry.getFee(); - rate = entry.getRate(); - priority = entry.getPriority(height); + const fee = entry.getFee(); + const rate = entry.getRate(); + const priority = entry.getPriority(height); this.logger.spam('Processing mempool tx %s.', entry.txid()); if (fee === 0 || this.isPriPoint(rate, priority)) { - item = new StatEntry(); + const item = new StatEntry(); item.blockHeight = height; item.bucketIndex = this.priStats.addTX(height, priority); + this.map.set(hash, item); } else if (this.isFeePoint(rate, priority)) { - item = new StatEntry(); + const item = new StatEntry(); item.blockHeight = height; item.bucketIndex = this.feeStats.addTX(height, rate); - } - - if (!item) { + this.map.set(hash, item); + } else { this.logger.spam('Not adding tx %s.', entry.txid()); - return; } - - this.map.set(hash, item); }; /** @@ -590,13 +585,11 @@ PolicyEstimator.prototype.processTX = function processTX(entry, current) { */ PolicyEstimator.prototype.processBlockTX = function processBlockTX(height, entry) { - let blocks, fee, rate, priority; - // Requires other mempool txs in order to be confirmed. Ignore. if (entry.dependencies) return; - blocks = height - entry.height; + const blocks = height - entry.height; if (blocks <= 0) { this.logger.debug( @@ -607,9 +600,9 @@ PolicyEstimator.prototype.processBlockTX = function processBlockTX(height, entry return; } - fee = entry.getFee(); - rate = entry.getRate(); - priority = entry.getPriority(height); + const fee = entry.getFee(); + const rate = entry.getRate(); + const priority = entry.getPriority(height); if (fee === 0 || this.isPriPoint(rate, priority)) this.priStats.record(blocks, priority); @@ -625,8 +618,6 @@ PolicyEstimator.prototype.processBlockTX = function processBlockTX(height, entry */ PolicyEstimator.prototype.processBlock = function processBlock(height, entries, current) { - let entry; - // Ignore reorgs. if (height <= this.bestHeight) return; @@ -673,7 +664,7 @@ PolicyEstimator.prototype.processBlock = function processBlock(height, entries, this.feeStats.clearCurrent(height); this.priStats.clearCurrent(height); - for (entry of entries) + for (const entry of entries) this.processBlockTX(height, entry); this.feeStats.updateAverages(); @@ -694,20 +685,18 @@ PolicyEstimator.prototype.processBlock = function processBlock(height, entries, */ PolicyEstimator.prototype.estimateFee = function estimateFee(target, smart) { - let rate; - if (!target) target = 1; if (smart == null) smart = true; - assert(util.isUInt32(target), 'Target must be a number.'); + assert(util.isU32(target), 'Target must be a number.'); assert(target <= this.feeStats.maxConfirms, 'Too many confirmations for estimate.'); if (!smart) { - rate = this.feeStats.estimateMedian( + const rate = this.feeStats.estimateMedian( target, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, this.bestHeight); @@ -717,7 +706,7 @@ PolicyEstimator.prototype.estimateFee = function estimateFee(target, smart) { return Math.floor(rate); } - rate = -1; + let rate = -1; while (rate < 0 && target <= this.feeStats.maxConfirms) { rate = this.feeStats.estimateMedian( target++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, @@ -740,26 +729,24 @@ PolicyEstimator.prototype.estimateFee = function estimateFee(target, smart) { */ PolicyEstimator.prototype.estimatePriority = function estimatePriority(target, smart) { - let priority; - if (!target) target = 1; if (smart == null) smart = true; - assert(util.isUInt32(target), 'Target must be a number.'); + assert(util.isU32(target), 'Target must be a number.'); assert(target <= this.priStats.maxConfirms, 'Too many confirmations for estimate.'); if (!smart) { - priority = this.priStats.estimateMedian( + const priority = this.priStats.estimateMedian( target, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, this.bestHeight); return Math.floor(priority); } - priority = -1; + let priority = -1; while (priority < 0 && target <= this.priStats.maxConfirms) { priority = this.priStats.estimateMedian( target++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, @@ -792,8 +779,8 @@ PolicyEstimator.prototype.getSize = function getSize() { */ PolicyEstimator.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeU8(PolicyEstimator.VERSION); bw.writeU32(this.bestHeight); @@ -810,7 +797,7 @@ PolicyEstimator.prototype.toRaw = function toRaw() { */ PolicyEstimator.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); if (br.readU8() !== PolicyEstimator.VERSION) throw new Error('Bad serialization version for estimator.'); @@ -869,12 +856,12 @@ function DoubleMap() { } DoubleMap.prototype.insert = function insert(key, value) { - let i = util.binarySearch(this.buckets, key, compare, true); + const i = util.binarySearch(this.buckets, key, compare, true); this.buckets.splice(i, 0, [key, value]); }; DoubleMap.prototype.search = function search(key) { - let i = util.binarySearch(this.buckets, key, compare, true); + const i = util.binarySearch(this.buckets, key, compare, true); assert(this.buckets.length !== 0, 'Cannot search.'); return this.buckets[i][1]; }; @@ -888,7 +875,7 @@ function compare(a, b) { } function sizeArray(buckets) { - let size = encoding.sizeVarint(buckets.length); + const size = encoding.sizeVarint(buckets.length); return size + buckets.length * 8; } @@ -900,7 +887,7 @@ function writeArray(bw, buckets) { } function readArray(br) { - let buckets = new Float64Array(br.readVarint()); + const buckets = new Float64Array(br.readVarint()); for (let i = 0; i < buckets.length; i++) buckets[i] = br.readDouble(); diff --git a/lib/mempool/layout-browser.js b/lib/mempool/layout-browser.js index e4833ea57..b7da4bb4c 100644 --- a/lib/mempool/layout-browser.js +++ b/lib/mempool/layout-browser.js @@ -6,6 +6,8 @@ 'use strict'; +const assert = require('assert'); + const layout = { binary: false, R: 'R', @@ -15,6 +17,8 @@ const layout = { return 'e' + hex(hash); }, ee: function ee(key) { + assert(typeof key === 'string'); + assert(key.length === 65); return key.slice(1, 65); } }; @@ -24,8 +28,9 @@ const layout = { */ function hex(hash) { - if (typeof hash !== 'string') + if (Buffer.isBuffer(hash)) hash = hash.toString('hex'); + assert(typeof hash === 'string'); return hash; } diff --git a/lib/mempool/layout.js b/lib/mempool/layout.js index ae4c26fdf..3d009a567 100644 --- a/lib/mempool/layout.js +++ b/lib/mempool/layout.js @@ -6,6 +6,8 @@ 'use strict'; +const assert = require('assert'); + /* * Database Layout: * R -> tip hash @@ -19,12 +21,14 @@ const layout = { V: Buffer.from([0x76]), F: Buffer.from([0x46]), e: function e(hash) { - let key = Buffer.allocUnsafe(33); + const key = Buffer.allocUnsafe(33); key[0] = 0x65; write(key, hash, 1); return key; }, ee: function ee(key) { + assert(Buffer.isBuffer(key)); + assert(key.length === 33); return key.toString('hex', 1, 33); } }; @@ -36,7 +40,8 @@ const layout = { function write(data, str, off) { if (Buffer.isBuffer(str)) return str.copy(data, off); - data.write(str, off, 'hex'); + assert(typeof str === 'string'); + return data.write(str, off, 'hex'); } /* diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 84e2a54b3..683f00b37 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -95,7 +95,7 @@ function Mempool(options) { this.txIndex = new TXIndex(); } -util.inherits(Mempool, AsyncObject); +Object.setPrototypeOf(Mempool.prototype, AsyncObject.prototype); /** * Open the chain, wait for the database to load. @@ -104,23 +104,21 @@ util.inherits(Mempool, AsyncObject); * @returns {Promise} */ -Mempool.prototype._open = async function open() { - let size = (this.options.maxSize / 1024).toFixed(2); - +Mempool.prototype._open = async function _open() { await this.chain.open(); await this.cache.open(); if (this.options.persistent) { - let entries = await this.cache.getEntries(); + const entries = await this.cache.getEntries(); - for (let entry of entries) + for (const entry of entries) this.trackEntry(entry); - for (let entry of entries) { + for (const entry of entries) { this.updateAncestors(entry, addFee); if (this.options.indexAddress) { - let view = await this.getCoinView(entry.tx); + const view = await this.getCoinView(entry.tx); this.indexEntry(entry, view); } } @@ -130,7 +128,7 @@ Mempool.prototype._open = async function open() { entries.length); if (this.fees) { - let fees = await this.cache.getFees(); + const fees = await this.cache.getFees(); if (fees) { this.fees.inject(fees); @@ -143,6 +141,8 @@ Mempool.prototype._open = async function open() { this.tip = this.chain.tip.hash; + const size = (this.options.maxSize / 1024).toFixed(2); + this.logger.info('Mempool loaded (maxsize=%dkb).', size); }; @@ -152,7 +152,7 @@ Mempool.prototype._open = async function open() { * @returns {Promise} */ -Mempool.prototype._close = async function close() { +Mempool.prototype._close = async function _close() { await this.cache.close(); }; @@ -167,7 +167,7 @@ Mempool.prototype._close = async function close() { */ Mempool.prototype.addBlock = async function addBlock(block, txs) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._addBlock(block, txs); } finally { @@ -184,20 +184,18 @@ Mempool.prototype.addBlock = async function addBlock(block, txs) { * @returns {Promise} */ -Mempool.prototype._addBlock = async function addBlock(block, txs) { - let entries; - +Mempool.prototype._addBlock = async function _addBlock(block, txs) { if (this.map.size === 0) { this.tip = block.hash; return; } - entries = []; + const entries = []; for (let i = txs.length - 1; i >= 1; i--) { - let tx = txs[i]; - let hash = tx.hash('hex'); - let entry = this.getEntry(hash); + const tx = txs[i]; + const hash = tx.hash('hex'); + const entry = this.getEntry(hash); if (!entry) { this.removeOrphan(hash); @@ -246,7 +244,7 @@ Mempool.prototype._addBlock = async function addBlock(block, txs) { */ Mempool.prototype.removeBlock = async function removeBlock(block, txs) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._removeBlock(block, txs); } finally { @@ -264,17 +262,17 @@ Mempool.prototype.removeBlock = async function removeBlock(block, txs) { * @returns {Promise} */ -Mempool.prototype._removeBlock = async function removeBlock(block, txs) { - let total = 0; - +Mempool.prototype._removeBlock = async function _removeBlock(block, txs) { if (this.map.size === 0) { this.tip = block.prevBlock; return; } + let total = 0; + for (let i = 1; i < txs.length; i++) { - let tx = txs[i]; - let hash = tx.hash('hex'); + const tx = txs[i]; + const hash = tx.hash('hex'); if (this.hasEntry(hash)) continue; @@ -313,7 +311,7 @@ Mempool.prototype._removeBlock = async function removeBlock(block, txs) { */ Mempool.prototype.reset = async function reset() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._reset(); } finally { @@ -326,7 +324,7 @@ Mempool.prototype.reset = async function reset() { * @private */ -Mempool.prototype._reset = async function reset() { +Mempool.prototype._reset = async function _reset() { this.logger.info('Mempool reset (%d txs removed).', this.map.size); this.size = 0; @@ -362,23 +360,23 @@ Mempool.prototype._reset = async function reset() { */ Mempool.prototype.limitSize = function limitSize(added) { - let maxSize = this.options.maxSize; - let threshold = maxSize - (maxSize / 10); - let expiryTime = this.options.expiryTime; - let now = util.now(); - let queue, start; + const maxSize = this.options.maxSize; if (this.size <= maxSize) return false; - start = util.hrtime(); - queue = new Heap(cmpRate); + const threshold = maxSize - (maxSize / 10); + const expiryTime = this.options.expiryTime; - for (let entry of this.map.values()) { + const now = util.now(); + let start = util.hrtime(); + const queue = new Heap(cmpRate); + + for (const entry of this.map.values()) { if (this.hasDepends(entry.tx)) continue; - if (now < entry.ts + expiryTime) { + if (now < entry.time + expiryTime) { queue.insert(entry); continue; } @@ -404,8 +402,8 @@ Mempool.prototype.limitSize = function limitSize(added) { queue.size()); while (queue.size() > 0) { - let entry = queue.shift(); - let hash = entry.hash('hex'); + const entry = queue.shift(); + const hash = entry.hash('hex'); assert(this.hasEntry(hash)); @@ -433,9 +431,11 @@ Mempool.prototype.limitSize = function limitSize(added) { */ Mempool.prototype.getTX = function getTX(hash) { - let entry = this.map.get(hash); + const entry = this.map.get(hash); + if (!entry) - return; + return null; + return entry.tx; }; @@ -457,16 +457,16 @@ Mempool.prototype.getEntry = function getEntry(hash) { */ Mempool.prototype.getCoin = function getCoin(hash, index) { - let entry = this.map.get(hash); + const entry = this.map.get(hash); if (!entry) - return; + return null; if (this.isSpent(hash, index)) - return; + return null; if (index >= entry.tx.outputs.length) - return; + return null; return Coin.fromTX(entry.tx, index, -1); }; @@ -482,7 +482,7 @@ Mempool.prototype.getCoin = function getCoin(hash, index) { */ Mempool.prototype.isSpent = function isSpent(hash, index) { - let key = Outpoint.toKey(hash, index); + const key = Outpoint.toKey(hash, index); return this.spents.has(key); }; @@ -494,7 +494,7 @@ Mempool.prototype.isSpent = function isSpent(hash, index) { */ Mempool.prototype.getSpent = function getSpent(hash, index) { - let key = Outpoint.toKey(hash, index); + const key = Outpoint.toKey(hash, index); return this.spents.get(key); }; @@ -506,11 +506,11 @@ Mempool.prototype.getSpent = function getSpent(hash, index) { */ Mempool.prototype.getSpentTX = function getSpentTX(hash, index) { - let key = Outpoint.toKey(hash, index); - let entry = this.spents.get(key); + const key = Outpoint.toKey(hash, index); + const entry = this.spents.get(key); if (!entry) - return; + return null; return entry.tx; }; @@ -522,16 +522,16 @@ Mempool.prototype.getSpentTX = function getSpentTX(hash, index) { */ Mempool.prototype.getCoinsByAddress = function getCoinsByAddress(addrs) { - let out = []; - if (!Array.isArray(addrs)) addrs = [addrs]; - for (let addr of addrs) { - let hash = Address.getHash(addr, 'hex'); - let coins = this.coinIndex.get(hash); + const out = []; - for (let coin of coins) + for (const addr of addrs) { + const hash = Address.getHash(addr, 'hex'); + const coins = this.coinIndex.get(hash); + + for (const coin of coins) out.push(coin); } @@ -545,16 +545,16 @@ Mempool.prototype.getCoinsByAddress = function getCoinsByAddress(addrs) { */ Mempool.prototype.getTXByAddress = function getTXByAddress(addrs) { - let out = []; - if (!Array.isArray(addrs)) addrs = [addrs]; - for (let addr of addrs) { - let hash = Address.getHash(addr, 'hex'); - let txs = this.txIndex.get(hash); + const out = []; - for (let tx of txs) + for (const addr of addrs) { + const hash = Address.getHash(addr, 'hex'); + const txs = this.txIndex.get(hash); + + for (const tx of txs) out.push(tx); } @@ -568,16 +568,16 @@ Mempool.prototype.getTXByAddress = function getTXByAddress(addrs) { */ Mempool.prototype.getMetaByAddress = function getMetaByAddress(addrs) { - let out = []; - if (!Array.isArray(addrs)) addrs = [addrs]; - for (let addr of addrs) { - let hash = Address.getHash(addr, 'hex'); - let txs = this.txIndex.getMeta(hash); + const out = []; + + for (const addr of addrs) { + const hash = Address.getHash(addr, 'hex'); + const txs = this.txIndex.getMeta(hash); - for (let tx of txs) + for (const tx of txs) out.push(tx); } @@ -591,14 +591,13 @@ Mempool.prototype.getMetaByAddress = function getMetaByAddress(addrs) { */ Mempool.prototype.getMeta = function getMeta(hash) { - let entry = this.getEntry(hash); - let meta; + const entry = this.getEntry(hash); if (!entry) - return; + return null; - meta = TXMeta.fromTX(entry.tx); - meta.ps = entry.ts; + const meta = TXMeta.fromTX(entry.tx); + meta.mtime = entry.time; return meta; }; @@ -670,8 +669,8 @@ Mempool.prototype.hasReject = function hasReject(hash) { */ Mempool.prototype.addTX = async function addTX(tx, id) { - let hash = tx.hash('hex'); - let unlock = await this.locker.lock(hash); + const hash = tx.hash('hex'); + const unlock = await this.locker.lock(hash); try { return await this._addTX(tx, id); } finally { @@ -689,11 +688,10 @@ Mempool.prototype.addTX = async function addTX(tx, id) { */ Mempool.prototype._addTX = async function _addTX(tx, id) { - let missing; - if (id == null) id = -1; + let missing; try { missing = await this.insertTX(tx, id); } catch (err) { @@ -722,17 +720,16 @@ Mempool.prototype._addTX = async function _addTX(tx, id) { */ Mempool.prototype.insertTX = async function insertTX(tx, id) { - let lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS; - let height = this.chain.height; - let hash = tx.hash('hex'); - let valid, reason, score, entry, view, missing; - assert(!tx.mutable, 'Cannot add mutable TX to mempool.'); + const lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS; + const height = this.chain.height; + const hash = tx.hash('hex'); + // Basic sanity checks. // This is important because it ensures // other functions will be overflow safe. - [valid, reason, score] = tx.checkSanity(); + const [valid, reason, score] = tx.checkSanity(); if (!valid) throw new VerifyError(tx, 'invalid', reason, score); @@ -769,7 +766,7 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) { // Non-contextual standardness checks. if (this.options.requireStandard) { - let [valid, reason, score] = tx.checkStandard(); + const [valid, reason, score] = tx.checkStandard(); if (!valid) throw new VerifyError(tx, 'nonstandard', reason, score); @@ -785,7 +782,7 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) { } // Verify transaction finality (see isFinal()). - if (!(await this.verifyFinal(tx, lockFlags))) { + if (!await this.verifyFinal(tx, lockFlags)) { throw new VerifyError(tx, 'nonstandard', 'non-final', @@ -803,7 +800,7 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) { // We can test whether this is an // non-fully-spent transaction on // the chain. - if (await this.chain.db.hasCoins(hash)) { + if (await this.chain.db.hasCoins(tx)) { throw new VerifyError(tx, 'alreadyknown', 'txn-already-known', @@ -823,10 +820,10 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) { // Get coin viewpoint as it // pertains to the mempool. - view = await this.getCoinView(tx); + const view = await this.getCoinView(tx); // Find missing outpoints. - missing = this.findMissing(tx, view); + const missing = this.findMissing(tx, view); // Maybe store as an orphan. if (missing) @@ -834,7 +831,7 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) { // Create a new mempool entry // at current chain height. - entry = MempoolEntry.fromTX(tx, view, height); + const entry = MempoolEntry.fromTX(tx, view, height); // Contextual verification. await this.verify(entry, view); @@ -862,14 +859,12 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) { */ Mempool.prototype.verify = async function verify(entry, view) { - let height = this.chain.height + 1; - let lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS; - let flags = Script.flags.STANDARD_VERIFY_FLAGS; - let tx = entry.tx; - let fee, reason, score, minFee; + const height = this.chain.height + 1; + const lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS; + const tx = entry.tx; // Verify sequence locks. - if (!(await this.verifyLocks(tx, view, lockFlags))) { + if (!await this.verifyLocks(tx, view, lockFlags)) { throw new VerifyError(tx, 'nonstandard', 'non-BIP68-final', @@ -904,7 +899,7 @@ Mempool.prototype.verify = async function verify(entry, view) { } // Make sure this guy gave a decent fee. - minFee = policy.getMinFee(entry.size, this.options.minRelay); + const minFee = policy.getMinFee(entry.size, this.options.minRelay); if (this.options.relayPriority && entry.fee < minFee) { if (!entry.isFree(height)) { @@ -918,7 +913,7 @@ Mempool.prototype.verify = async function verify(entry, view) { // Continuously rate-limit free (really, very-low-fee) // transactions. This mitigates 'penny-flooding'. if (this.options.limitFree && entry.fee < minFee) { - let now = util.now(); + const now = util.now(); // Use an exponentially decaying ~10-minute window. this.freeCount *= Math.pow(1 - 1 / 600, now - this.lastTime); @@ -949,37 +944,34 @@ Mempool.prototype.verify = async function verify(entry, view) { } // Contextual sanity checks. - [fee, reason, score] = tx.checkInputs(view, height); + const [fee, reason, score] = tx.checkInputs(view, height); if (fee === -1) throw new VerifyError(tx, 'invalid', reason, score); // Script verification. + let flags = Script.flags.STANDARD_VERIFY_FLAGS; try { await this.verifyInputs(tx, view, flags); } catch (err) { - let valid; - if (tx.hasWitness()) throw err; // Try without segwit and cleanstack. flags &= ~Script.flags.VERIFY_WITNESS; flags &= ~Script.flags.VERIFY_CLEANSTACK; - valid = await this.verifyResult(tx, view, flags); // If it failed, the first verification // was the only result we needed. - if (!valid) + if (!await this.verifyResult(tx, view, flags)) throw err; // If it succeeded, segwit may be causing the // failure. Try with segwit but without cleanstack. flags |= Script.flags.VERIFY_CLEANSTACK; - valid = await this.verifyResult(tx, view, flags); // Cleanstack was causing the failure. - if (valid) + if (await this.verifyResult(tx, view, flags)) throw err; // Do not insert into reject cache. @@ -989,10 +981,9 @@ Mempool.prototype.verify = async function verify(entry, view) { // Paranoid checks. if (this.options.paranoidChecks) { - let valid; - flags = Script.flags.MANDATORY_VERIFY_FLAGS; - valid = await this.verifyResult(tx, view, flags); - assert(valid, 'BUG: Verify failed for mandatory but not standard.'); + const flags = Script.flags.MANDATORY_VERIFY_FLAGS; + assert(await this.verifyResult(tx, view, flags), + 'BUG: Verify failed for mandatory but not standard.'); } }; @@ -1061,7 +1052,7 @@ Mempool.prototype.verifyInputs = async function verifyInputs(tx, view, flags) { */ Mempool.prototype.addEntry = async function addEntry(entry, view) { - let tx = entry.tx; + const tx = entry.tx; this.trackEntry(entry, view); @@ -1090,8 +1081,8 @@ Mempool.prototype.addEntry = async function addEntry(entry, view) { */ Mempool.prototype.removeEntry = function removeEntry(entry) { - let tx = entry.tx; - let hash = tx.hash('hex'); + const tx = entry.tx; + const hash = tx.hash('hex'); this.untrackEntry(entry); @@ -1122,11 +1113,11 @@ Mempool.prototype.evictEntry = function evictEntry(entry) { */ Mempool.prototype.removeSpenders = function removeSpenders(entry) { - let tx = entry.tx; - let hash = tx.hash('hex'); + const tx = entry.tx; + const hash = tx.hash('hex'); for (let i = 0; i < tx.outputs.length; i++) { - let spender = this.getSpent(hash, i); + const spender = this.getSpent(hash, i); if (!spender) continue; @@ -1144,7 +1135,7 @@ Mempool.prototype.removeSpenders = function removeSpenders(entry) { */ Mempool.prototype.countAncestors = function countAncestors(entry) { - return this._countAncestors(entry, 0, {}, entry, nop); + return this._countAncestors(entry, new Set(), entry, nop); }; /** @@ -1157,48 +1148,46 @@ Mempool.prototype.countAncestors = function countAncestors(entry) { */ Mempool.prototype.updateAncestors = function updateAncestors(entry, map) { - return this._countAncestors(entry, 0, {}, entry, map); + return this._countAncestors(entry, new Set(), entry, map); }; /** * Traverse ancestors and count. * @private * @param {MempoolEntry} entry - * @param {Number} count * @param {Object} set * @param {MempoolEntry} child * @param {Function} map * @returns {Number} */ -Mempool.prototype._countAncestors = function countAncestors(entry, count, set, child, map) { - let tx = entry.tx; +Mempool.prototype._countAncestors = function _countAncestors(entry, set, child, map) { + const tx = entry.tx; - for (let input of tx.inputs) { - let hash = input.prevout.hash; - let parent = this.getEntry(hash); + for (const input of tx.inputs) { + const hash = input.prevout.hash; + const parent = this.getEntry(hash); if (!parent) continue; - if (set[hash]) + if (set.has(hash)) continue; - set[hash] = true; - count += 1; + set.add(hash); map(parent, child); - if (count > this.options.maxAncestors) + if (set.size > this.options.maxAncestors) break; - count = this._countAncestors(parent, count, set, child, map); + this._countAncestors(parent, set, child, map); - if (count > this.options.maxAncestors) + if (set.size > this.options.maxAncestors) break; } - return count; + return set.size; }; /** @@ -1209,7 +1198,7 @@ Mempool.prototype._countAncestors = function countAncestors(entry, count, set, c */ Mempool.prototype.countDescendants = function countDescendants(entry) { - return this._countDescendants(entry, 0, {}); + return this._countDescendants(entry, new Set()); }; /** @@ -1217,34 +1206,31 @@ Mempool.prototype.countDescendants = function countDescendants(entry) { * descendants a transaction may have. * @private * @param {MempoolEntry} entry - * @param {Number} count * @param {Object} set * @returns {Number} */ -Mempool.prototype._countDescendants = function countDescendants(entry, count, set) { - let tx = entry.tx; - let hash = tx.hash('hex'); +Mempool.prototype._countDescendants = function _countDescendants(entry, set) { + const tx = entry.tx; + const hash = tx.hash('hex'); for (let i = 0; i < tx.outputs.length; i++) { - let child = this.getSpent(hash, i); - let next; + const child = this.getSpent(hash, i); if (!child) continue; - next = child.hash('hex'); + const next = child.hash('hex'); - if (set[next]) + if (set.has(next)) continue; - set[next] = true; - count += 1; + set.add(next); - count = this._countDescendants(child, count, set); + this._countDescendants(child, set); } - return count; + return set.size; }; /** @@ -1254,7 +1240,7 @@ Mempool.prototype._countDescendants = function countDescendants(entry, count, se */ Mempool.prototype.getAncestors = function getAncestors(entry) { - return this._getAncestors(entry, [], {}); + return this._getAncestors(entry, [], new Set()); }; /** @@ -1266,20 +1252,20 @@ Mempool.prototype.getAncestors = function getAncestors(entry) { * @returns {MempoolEntry[]} */ -Mempool.prototype._getAncestors = function getAncestors(entry, entries, set) { - let tx = entry.tx; +Mempool.prototype._getAncestors = function _getAncestors(entry, entries, set) { + const tx = entry.tx; - for (let input of tx.inputs) { - let hash = input.prevout.hash; - let parent = this.getEntry(hash); + for (const input of tx.inputs) { + const hash = input.prevout.hash; + const parent = this.getEntry(hash); if (!parent) continue; - if (set[hash]) + if (set.has(hash)) continue; - set[hash] = true; + set.add(hash); entries.push(parent); this._getAncestors(parent, entries, set); @@ -1295,7 +1281,7 @@ Mempool.prototype._getAncestors = function getAncestors(entry, entries, set) { */ Mempool.prototype.getDescendants = function getDescendants(entry) { - return this._getDescendants(entry, [], {}); + return this._getDescendants(entry, [], new Set()); }; /** @@ -1306,23 +1292,22 @@ Mempool.prototype.getDescendants = function getDescendants(entry) { * @returns {MempoolEntry[]} */ -Mempool.prototype._getDescendants = function getDescendants(entry, entries, set) { - let tx = entry.tx; - let hash = tx.hash('hex'); +Mempool.prototype._getDescendants = function _getDescendants(entry, entries, set) { + const tx = entry.tx; + const hash = tx.hash('hex'); for (let i = 0; i < tx.outputs.length; i++) { - let child = this.getSpent(hash, i); - let next; + const child = this.getSpent(hash, i); if (!child) continue; - next = child.hash('hex'); + const next = child.hash('hex'); - if (set[next]) + if (set.has(next)) continue; - set[next] = true; + set.add(next); entries.push(child); this._getDescendants(child, entries, set); @@ -1339,10 +1324,10 @@ Mempool.prototype._getDescendants = function getDescendants(entry, entries, set) */ Mempool.prototype.getDepends = function getDepends(tx) { - let prevout = tx.getPrevout(); - let depends = []; + const prevout = tx.getPrevout(); + const depends = []; - for (let hash of prevout) { + for (const hash of prevout) { if (this.hasEntry(hash)) depends.push(hash); } @@ -1357,8 +1342,8 @@ Mempool.prototype.getDepends = function getDepends(tx) { */ Mempool.prototype.hasDepends = function hasDepends(tx) { - for (let input of tx.inputs) { - let hash = input.prevout.hash; + for (const input of tx.inputs) { + const hash = input.prevout.hash; if (this.hasEntry(hash)) return true; } @@ -1374,10 +1359,10 @@ Mempool.prototype.hasDepends = function hasDepends(tx) { Mempool.prototype.getBalance = function getBalance() { let total = 0; - for (let [hash, entry] of this.map) { - let tx = entry.tx; + for (const [hash, entry] of this.map) { + const tx = entry.tx; for (let i = 0; i < tx.outputs.length; i++) { - let coin = this.getCoin(hash, i); + const coin = this.getCoin(hash, i); if (coin) total += coin.value; } @@ -1392,9 +1377,9 @@ Mempool.prototype.getBalance = function getBalance() { */ Mempool.prototype.getHistory = function getHistory() { - let txs = []; + const txs = []; - for (let entry of this.map.values()) + for (const entry of this.map.values()) txs.push(entry.tx); return txs; @@ -1427,8 +1412,6 @@ Mempool.prototype.hasOrphan = function hasOrphan(hash) { */ Mempool.prototype.storeOrphan = function storeOrphan(tx, missing, id) { - let hash = tx.hash('hex'); - if (tx.getWeight() > policy.MAX_TX_WEIGHT) { this.logger.debug('Ignoring large orphan: %s', tx.txid()); if (!tx.hasWitness()) @@ -1436,7 +1419,7 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx, missing, id) { return []; } - for (let prev of missing) { + for (const prev of missing) { if (this.hasReject(prev)) { this.logger.debug('Not storing orphan %s (rejected parents).', tx.txid()); this.rejects.add(tx.hash()); @@ -1449,7 +1432,9 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx, missing, id) { this.limitOrphans(); - for (let prev of missing) { + const hash = tx.hash('hex'); + + for (const prev of missing) { if (!this.waiting.has(prev)) this.waiting.set(prev, new Set()); @@ -1473,9 +1458,9 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx, missing, id) { */ Mempool.prototype.handleOrphans = async function handleOrphans(parent) { - let resolved = this.resolveOrphans(parent); + const resolved = this.resolveOrphans(parent); - for (let orphan of resolved) { + for (const orphan of resolved) { let tx, missing; try { @@ -1521,17 +1506,18 @@ Mempool.prototype.handleOrphans = async function handleOrphans(parent) { */ Mempool.prototype.resolveOrphans = function resolveOrphans(parent) { - let hash = parent.hash('hex'); - let set = this.waiting.get(hash); - let resolved = []; + const hash = parent.hash('hex'); + const set = this.waiting.get(hash); if (!set) - return resolved; + return []; assert(set.size > 0); - for (let orphanHash of set.keys()) { - let orphan = this.getOrphan(orphanHash); + const resolved = []; + + for (const orphanHash of set.keys()) { + const orphan = this.getOrphan(orphanHash); assert(orphan); @@ -1553,12 +1539,12 @@ Mempool.prototype.resolveOrphans = function resolveOrphans(parent) { */ Mempool.prototype.removeOrphan = function removeOrphan(hash) { - let orphan = this.getOrphan(hash); - let tx; + const orphan = this.getOrphan(hash); if (!orphan) return false; + let tx; try { tx = orphan.toTX(); } catch (e) { @@ -1566,11 +1552,11 @@ Mempool.prototype.removeOrphan = function removeOrphan(hash) { this.logger.warning('%s %s', 'Warning: possible memory corruption.', 'Orphan failed deserialization.'); - return; + return false; } - for (let prev of tx.getPrevout()) { - let set = this.waiting.get(prev); + for (const prev of tx.getPrevout()) { + const set = this.waiting.get(prev); if (!set) continue; @@ -1596,19 +1582,20 @@ Mempool.prototype.removeOrphan = function removeOrphan(hash) { */ Mempool.prototype.limitOrphans = function limitOrphans() { - let index, hash; - if (this.orphans.size < this.options.maxOrphans) return false; - index = random.randomRange(0, this.orphans.size); + let index = random.randomRange(0, this.orphans.size); + let hash; for (hash of this.orphans.keys()) { if (index === 0) break; index--; } + assert(hash); + this.logger.debug('Removing orphan %s from mempool.', util.revHex(hash)); this.removeOrphan(hash); @@ -1627,8 +1614,8 @@ Mempool.prototype.limitOrphans = function limitOrphans() { */ Mempool.prototype.isDoubleSpend = function isDoubleSpend(tx) { - for (let input of tx.inputs) { - let prevout = input.prevout; + for (const input of tx.inputs) { + const prevout = input.prevout; if (this.isSpent(prevout.hash, prevout.index)) return true; } @@ -1644,7 +1631,7 @@ Mempool.prototype.isDoubleSpend = function isDoubleSpend(tx) { */ Mempool.prototype.getSpentView = async function getSpentView(tx) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this.getCoinView(tx); } finally { @@ -1660,28 +1647,25 @@ Mempool.prototype.getSpentView = async function getSpentView(tx) { */ Mempool.prototype.getCoinView = async function getCoinView(tx) { - let view = new CoinView(); - let prevout = tx.getPrevout(); + const view = new CoinView(); - for (let hash of prevout) { - let entry = this.getEntry(hash); - let coins; + for (const {prevout} of tx.inputs) { + const entry = this.getEntry(prevout.hash); if (entry) { view.addTX(entry.tx, -1); continue; } - coins = await this.chain.db.getCoins(hash); + const coin = await this.chain.db.readCoin(prevout); - if (!coins) { - coins = new Coins(); - coins.hash = hash; - view.add(coins); + if (!coin) { + const coins = new Coins(); + view.add(prevout.hash, coins); continue; } - view.add(coins); + view.addEntry(prevout, coin); } return view; @@ -1695,17 +1679,17 @@ Mempool.prototype.getCoinView = async function getCoinView(tx) { */ Mempool.prototype.findMissing = function findMissing(tx, view) { - let missing = []; + const missing = []; - for (let input of tx.inputs) { - if (view.hasEntry(input)) + for (const {prevout} of tx.inputs) { + if (view.hasEntry(prevout)) continue; - missing.push(input.prevout.hash); + missing.push(prevout.hash); } if (missing.length === 0) - return; + return null; return missing; }; @@ -1717,9 +1701,9 @@ Mempool.prototype.findMissing = function findMissing(tx, view) { */ Mempool.prototype.getSnapshot = function getSnapshot() { - let keys = []; + const keys = []; - for (let hash of this.map.keys()) + for (const hash of this.map.keys()) keys.push(hash); return keys; @@ -1756,16 +1740,16 @@ Mempool.prototype.verifyFinal = function verifyFinal(tx, flags) { */ Mempool.prototype.trackEntry = function trackEntry(entry, view) { - let tx = entry.tx; - let hash = tx.hash('hex'); + const tx = entry.tx; + const hash = tx.hash('hex'); assert(!this.map.has(hash)); this.map.set(hash, entry); assert(!tx.isCoinbase()); - for (let input of tx.inputs) { - let key = input.prevout.toKey(); + for (const input of tx.inputs) { + const key = input.prevout.toKey(); this.spents.set(key, entry); } @@ -1782,16 +1766,16 @@ Mempool.prototype.trackEntry = function trackEntry(entry, view) { */ Mempool.prototype.untrackEntry = function untrackEntry(entry) { - let tx = entry.tx; - let hash = tx.hash('hex'); + const tx = entry.tx; + const hash = tx.hash('hex'); assert(this.map.has(hash)); this.map.delete(hash); assert(!tx.isCoinbase()); - for (let input of tx.inputs) { - let key = input.prevout.toKey(); + for (const input of tx.inputs) { + const key = input.prevout.toKey(); this.spents.delete(key); } @@ -1809,12 +1793,12 @@ Mempool.prototype.untrackEntry = function untrackEntry(entry) { */ Mempool.prototype.indexEntry = function indexEntry(entry, view) { - let tx = entry.tx; + const tx = entry.tx; this.txIndex.insert(entry, view); - for (let input of tx.inputs) { - let prev = input.prevout; + for (const input of tx.inputs) { + const prev = input.prevout; this.coinIndex.remove(prev.hash, prev.index); } @@ -1829,14 +1813,14 @@ Mempool.prototype.indexEntry = function indexEntry(entry, view) { */ Mempool.prototype.unindexEntry = function unindexEntry(entry) { - let tx = entry.tx; - let hash = tx.hash('hex'); + const tx = entry.tx; + const hash = tx.hash('hex'); this.txIndex.remove(hash); - for (let input of tx.inputs) { - let prevout = input.prevout.hash; - let prev = this.getTX(prevout.hash); + for (const input of tx.inputs) { + const prevout = input.prevout.hash; + const prev = this.getTX(prevout.hash); if (!prev) continue; @@ -1856,9 +1840,9 @@ Mempool.prototype.unindexEntry = function unindexEntry(entry) { */ Mempool.prototype.removeDoubleSpends = function removeDoubleSpends(tx) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let spent = this.getSpent(prevout.hash, prevout.index); + for (const input of tx.inputs) { + const prevout = input.prevout; + const spent = this.getSpent(prevout.hash, prevout.index); if (!spent) continue; @@ -1890,7 +1874,7 @@ Mempool.prototype.getSize = function getSize() { * @param {Amount} fee */ -Mempool.prototype.prioritise = function _prioritise(entry, pri, fee) { +Mempool.prototype.prioritise = function prioritise(entry, pri, fee) { if (-pri > entry.priority) pri = -entry.priority; @@ -1902,12 +1886,12 @@ Mempool.prototype.prioritise = function _prioritise(entry, pri, fee) { if (fee === 0) return; - this.updateAncestors(entry, preprioritise); + this.updateAncestors(entry, prePrioritise); entry.deltaFee += fee; entry.descFee += fee; - this.updateAncestors(entry, prioritise); + this.updateAncestors(entry, postPrioritise); }; /** @@ -1996,7 +1980,7 @@ MempoolOptions.prototype.fromOptions = function fromOptions(options) { } if (options.limitFreeRelay != null) { - assert(util.isUInt32(options.limitFreeRelay)); + assert(util.isU32(options.limitFreeRelay)); this.limitFreeRelay = options.limitFreeRelay; } @@ -2031,27 +2015,27 @@ MempoolOptions.prototype.fromOptions = function fromOptions(options) { } if (options.maxSize != null) { - assert(util.isUInt53(options.maxSize)); + assert(util.isU64(options.maxSize)); this.maxSize = options.maxSize; } if (options.maxOrphans != null) { - assert(util.isUInt32(options.maxOrphans)); + assert(util.isU32(options.maxOrphans)); this.maxOrphans = options.maxOrphans; } if (options.maxAncestors != null) { - assert(util.isUInt32(options.maxAncestors)); + assert(util.isU32(options.maxAncestors)); this.maxAncestors = options.maxAncestors; } if (options.expiryTime != null) { - assert(util.isUInt32(options.expiryTime)); + assert(util.isU32(options.expiryTime)); this.expiryTime = options.expiryTime; } if (options.minRelay != null) { - assert(util.isUint53(options.minRelay)); + assert(util.isU64(options.minRelay)); this.minRelay = options.minRelay; } @@ -2072,12 +2056,12 @@ MempoolOptions.prototype.fromOptions = function fromOptions(options) { } if (options.maxFiles != null) { - assert(util.isUInt32(options.maxFiles)); + assert(util.isU32(options.maxFiles)); this.maxFiles = options.maxFiles; } if (options.cacheSize != null) { - assert(util.isUInt53(options.cacheSize)); + assert(util.isU64(options.cacheSize)); this.cacheSize = options.cacheSize; } @@ -2129,28 +2113,30 @@ TXIndex.prototype.reset = function reset() { }; TXIndex.prototype.get = function get(addr) { - let items = this.index.get(addr); - let out = []; + const items = this.index.get(addr); if (!items) - return out; + return []; + + const out = []; - for (let entry of items.values()) + for (const entry of items.values()) out.push(entry.tx); return out; }; TXIndex.prototype.getMeta = function getMeta(addr) { - let items = this.index.get(addr); - let out = []; + const items = this.index.get(addr); if (!items) - return out; + return []; - for (let entry of items.values()) { - let meta = TXMeta.fromTX(entry.tx); - meta.ps = entry.ts; + const out = []; + + for (const entry of items.values()) { + const meta = TXMeta.fromTX(entry.tx); + meta.mtime = entry.time; out.push(meta); } @@ -2158,14 +2144,14 @@ TXIndex.prototype.getMeta = function getMeta(addr) { }; TXIndex.prototype.insert = function insert(entry, view) { - let tx = entry.tx; - let hash = tx.hash('hex'); - let addrs = tx.getHashes(view, 'hex'); + const tx = entry.tx; + const hash = tx.hash('hex'); + const addrs = tx.getHashes(view, 'hex'); if (addrs.length === 0) return; - for (let addr of addrs) { + for (const addr of addrs) { let items = this.index.get(addr); if (!items) { @@ -2181,13 +2167,13 @@ TXIndex.prototype.insert = function insert(entry, view) { }; TXIndex.prototype.remove = function remove(hash) { - let addrs = this.map.get(hash); + const addrs = this.map.get(hash); if (!addrs) return; - for (let addr of addrs) { - let items = this.index.get(addr); + for (const addr of addrs) { + const items = this.index.get(addr); assert(items); assert(items.has(hash)); @@ -2221,35 +2207,35 @@ CoinIndex.prototype.reset = function reset() { }; CoinIndex.prototype.get = function get(addr) { - let items = this.index.get(addr); - let out = []; + const items = this.index.get(addr); if (!items) - return out; + return []; + + const out = []; - for (let coin of items.values()) + for (const coin of items.values()) out.push(coin.toCoin()); return out; }; CoinIndex.prototype.insert = function insert(tx, index) { - let output = tx.outputs[index]; - let hash = tx.hash('hex'); - let addr = output.getHash('hex'); - let items, key; + const output = tx.outputs[index]; + const hash = tx.hash('hex'); + const addr = output.getHash('hex'); if (!addr) return; - items = this.index.get(addr); + let items = this.index.get(addr); if (!items) { items = new Map(); this.index.set(addr, items); } - key = Outpoint.toKey(hash, index); + const key = Outpoint.toKey(hash, index); assert(!items.has(key)); items.set(key, new IndexedCoin(tx, index)); @@ -2258,14 +2244,13 @@ CoinIndex.prototype.insert = function insert(tx, index) { }; CoinIndex.prototype.remove = function remove(hash, index) { - let key = Outpoint.toKey(hash, index); - let addr = this.map.get(key); - let items; + const key = Outpoint.toKey(hash, index); + const addr = this.map.get(key); if (!addr) return; - items = this.index.get(addr); + const items = this.index.get(addr); assert(items); assert(items.has(key)); @@ -2337,7 +2322,7 @@ function MempoolCache(options) { MempoolCache.VERSION = 2; MempoolCache.prototype.getVersion = async function getVersion() { - let data = await this.db.get(layout.V); + const data = await this.db.get(layout.V); if (!data) return -1; @@ -2346,21 +2331,21 @@ MempoolCache.prototype.getVersion = async function getVersion() { }; MempoolCache.prototype.getTip = async function getTip() { - let hash = await this.db.get(layout.R); + const hash = await this.db.get(layout.R); if (!hash) - return; + return null; return hash.toString('hex'); }; MempoolCache.prototype.getFees = async function getFees() { - let data = await this.db.get(layout.F); - let fees; + const data = await this.db.get(layout.F); if (!data) - return; + return null; + let fees; try { fees = Fees.fromRaw(data); } catch (e) { @@ -2449,7 +2434,7 @@ MempoolCache.prototype.flush = async function flush() { }; MempoolCache.prototype.init = async function init(hash) { - let batch = this.db.batch(); + const batch = this.db.batch(); batch.put(layout.V, encoding.U32(MempoolCache.VERSION)); batch.put(layout.R, Buffer.from(hash, 'hex')); await batch.write(); @@ -2496,10 +2481,10 @@ MempoolCache.prototype.verify = async function verify() { }; MempoolCache.prototype.wipe = async function wipe() { - let batch = this.db.batch(); - let keys = await this.getKeys(); + const batch = this.db.batch(); + const keys = await this.getKeys(); - for (let key of keys) + for (const key of keys) batch.del(key); batch.put(layout.V, encoding.U32(MempoolCache.VERSION)); @@ -2529,11 +2514,11 @@ function removeFee(parent, child) { parent.descSize -= child.descSize; } -function preprioritise(parent, child) { +function prePrioritise(parent, child) { parent.descFee -= child.deltaFee; } -function prioritise(parent, child) { +function postPrioritise(parent, child) { parent.descFee += child.deltaFee; } @@ -2558,16 +2543,16 @@ function cmpRate(a, b) { y = xs * yf; if (x === y) { - x = a.ts; - y = b.ts; + x = a.time; + y = b.time; } return x - y; } function useDesc(a) { - let x = a.deltaFee * a.descSize; - let y = a.descFee * a.size; + const x = a.deltaFee * a.descSize; + const y = a.descFee * a.size; return y > x; } diff --git a/lib/mempool/mempoolentry.js b/lib/mempool/mempoolentry.js index 7876cc4e8..2ca6f637a 100644 --- a/lib/mempool/mempoolentry.js +++ b/lib/mempool/mempoolentry.js @@ -21,12 +21,12 @@ const TX = require('../primitives/tx'); * @param {TX} options.tx - Transaction in mempool. * @param {Number} options.height - Entry height. * @param {Number} options.priority - Entry priority. - * @param {Number} options.ts - Entry time. + * @param {Number} options.time - Entry time. * @param {Amount} options.value - Value of on-chain coins. * @property {TX} tx * @property {Number} height * @property {Number} priority - * @property {Number} ts + * @property {Number} time * @property {Amount} value */ @@ -41,7 +41,7 @@ function MempoolEntry(options) { this.priority = 0; this.fee = 0; this.deltaFee = 0; - this.ts = 0; + this.time = 0; this.value = 0; this.dependencies = false; this.descFee = 0; @@ -65,7 +65,7 @@ MempoolEntry.prototype.fromOptions = function fromOptions(options) { this.priority = options.priority; this.fee = options.fee; this.deltaFee = options.deltaFee; - this.ts = options.ts; + this.time = options.time; this.value = options.value; this.dependencies = options.dependencies; this.descFee = options.descFee; @@ -91,16 +91,16 @@ MempoolEntry.fromOptions = function fromOptions(options) { */ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) { - let flags = Script.flags.STANDARD_VERIFY_FLAGS; - let value = tx.getChainValue(view); - let sigops = tx.getSigopsCost(view, flags); - let size = tx.getSigopsSize(sigops); - let priority = tx.getPriority(view, height, size); - let fee = tx.getFee(view); - let dependencies = false; + const flags = Script.flags.STANDARD_VERIFY_FLAGS; + const value = tx.getChainValue(view); + const sigops = tx.getSigopsCost(view, flags); + const size = tx.getSigopsSize(sigops); + const priority = tx.getPriority(view, height, size); + const fee = tx.getFee(view); - for (let input of tx.inputs) { - if (view.getHeight(input) === -1) { + let dependencies = false; + for (const {prevout} of tx.inputs) { + if (view.getHeight(prevout) === -1) { dependencies = true; break; } @@ -113,7 +113,7 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) { this.priority = priority; this.fee = fee; this.deltaFee = fee; - this.ts = util.now(); + this.time = util.now(); this.value = value; this.dependencies = dependencies; this.descFee = fee; @@ -161,8 +161,8 @@ MempoolEntry.prototype.txid = function txid() { */ MempoolEntry.prototype.getPriority = function getPriority(height) { - let delta = height - this.height; - let priority = (delta * this.value) / this.size; + const delta = height - this.height; + const priority = (delta * this.value) / this.size; let result = this.priority + Math.floor(priority); if (result < 0) result = 0; @@ -225,7 +225,7 @@ MempoolEntry.prototype.getDescRate = function getDescRate() { */ MempoolEntry.prototype.memUsage = function memUsage() { - let tx = this.tx; + const tx = this.tx; let total = 0; total += 176; // mempool entry @@ -240,7 +240,7 @@ MempoolEntry.prototype.memUsage = function memUsage() { total += 32; // input array - for (let input of tx.inputs) { + for (const input of tx.inputs) { total += 120; // input total += 104; // prevout total += 88; // prevout hash @@ -250,7 +250,7 @@ MempoolEntry.prototype.memUsage = function memUsage() { total += 32; // script code array total += input.script.code.length * 40; // opcodes - for (let op of input.script.code) { + for (const op of input.script.code) { if (op.data) total += 80; // op buffers } @@ -262,14 +262,14 @@ MempoolEntry.prototype.memUsage = function memUsage() { total += 32; // output array - for (let output of tx.outputs) { + for (const output of tx.outputs) { total += 104; // output total += 40; // script total += 80; // script raw buffer total += 32; // script code array total += output.script.code.length * 40; // opcodes - for (let op of output.script.code) { + for (const op of output.script.code) { if (op.data) total += 80; // op buffers } @@ -287,7 +287,7 @@ MempoolEntry.prototype.memUsage = function memUsage() { */ MempoolEntry.prototype.isFree = function isFree(height) { - let priority = this.getPriority(height); + const priority = this.getPriority(height); return priority > policy.FREE_THRESHOLD; }; @@ -306,14 +306,14 @@ MempoolEntry.prototype.getSize = function getSize() { */ MempoolEntry.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(this.getSize()); + const bw = new StaticWriter(this.getSize()); bw.writeBytes(this.tx.toRaw()); bw.writeU32(this.height); bw.writeU32(this.size); bw.writeU32(this.sigops); bw.writeDouble(this.priority); bw.writeU64(this.fee); - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU64(this.value); bw.writeU8(this.dependencies ? 1 : 0); return bw.render(); @@ -327,7 +327,7 @@ MempoolEntry.prototype.toRaw = function toRaw() { */ MempoolEntry.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.tx = TX.fromReader(br); this.height = br.readU32(); this.size = br.readU32(); @@ -335,7 +335,7 @@ MempoolEntry.prototype.fromRaw = function fromRaw(data) { this.priority = br.readDouble(); this.fee = br.readU64(); this.deltaFee = this.fee; - this.ts = br.readU32(); + this.time = br.readU32(); this.value = br.readU64(); this.dependencies = br.readU8() === 1; this.descFee = this.fee; diff --git a/lib/mining/common.js b/lib/mining/common.js index 90a82d03b..2740ace67 100644 --- a/lib/mining/common.js +++ b/lib/mining/common.js @@ -34,7 +34,7 @@ const B0 = 0x1; common.swap32 = function swap32(data) { for (let i = 0; i < data.length; i += 4) { - let field = data.readUInt32LE(i, true); + const field = data.readUInt32LE(i, true); data.writeUInt32BE(field, i, true); } @@ -48,7 +48,7 @@ common.swap32 = function swap32(data) { */ common.swap32hex = function swap32hex(str) { - let data = Buffer.from(str, 'hex'); + const data = Buffer.from(str, 'hex'); return common.swap32(data).toString('hex'); }; @@ -111,8 +111,8 @@ common.double256 = function double256(target) { */ common.getDifficulty = function getDifficulty(target) { - let d = DIFF; - let n = common.double256(target); + const d = DIFF; + const n = common.double256(target); if (n === 0) return d; @@ -127,7 +127,7 @@ common.getDifficulty = function getDifficulty(target) { */ common.getTarget = function getTarget(bits) { - let target = consensus.fromCompact(bits); + const target = consensus.fromCompact(bits); if (target.isNeg()) throw new Error('Target is negative.'); @@ -135,7 +135,7 @@ common.getTarget = function getTarget(bits) { if (target.cmpn(0) === 0) throw new Error('Target is zero.'); - return target.toBuffer('le', 32); + return target.toArrayLike(Buffer, 'le', 32); }; /** @@ -145,7 +145,7 @@ common.getTarget = function getTarget(bits) { */ common.getBits = function getBits(data) { - let target = new BN(data, 'le'); + const target = new BN(data, 'le'); if (target.cmpn(0) === 0) throw new Error('Target is zero.'); diff --git a/lib/mining/cpuminer.js b/lib/mining/cpuminer.js index 6c30bbf6b..3e39d2b53 100644 --- a/lib/mining/cpuminer.js +++ b/lib/mining/cpuminer.js @@ -44,7 +44,7 @@ function CPUMiner(miner) { this._init(); } -util.inherits(CPUMiner, AsyncObject); +Object.setPrototypeOf(CPUMiner.prototype, AsyncObject.prototype); /** * Nonce range interval. @@ -76,7 +76,7 @@ CPUMiner.prototype._init = function _init() { * @returns {Promise} */ -CPUMiner.prototype._open = async function open() { +CPUMiner.prototype._open = async function _open() { }; /** @@ -86,7 +86,7 @@ CPUMiner.prototype._open = async function open() { * @returns {Promise} */ -CPUMiner.prototype._close = async function close() { +CPUMiner.prototype._close = async function _close() { await this.stop(); }; @@ -107,17 +107,13 @@ CPUMiner.prototype.start = function start() { * @returns {Promise} */ -CPUMiner.prototype._start = async function start() { - let job; - +CPUMiner.prototype._start = async function _start() { assert(!this.running, 'Miner is already running.'); this.running = true; this.stopping = false; for (;;) { - let block, entry; - this.job = null; try { @@ -132,6 +128,7 @@ CPUMiner.prototype._start = async function start() { if (this.stopping) break; + let block; try { block = await this.mineAsync(this.job); } catch (e) { @@ -147,6 +144,7 @@ CPUMiner.prototype._start = async function start() { if (!block) continue; + let entry; try { entry = await this.chain.add(block); } catch (e) { @@ -178,7 +176,7 @@ CPUMiner.prototype._start = async function start() { this.emit('block', block, entry); } - job = this.stopJob; + const job = this.stopJob; if (job) { this.stopJob = null; @@ -193,7 +191,7 @@ CPUMiner.prototype._start = async function start() { */ CPUMiner.prototype.stop = async function stop() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._stop(); } finally { @@ -250,7 +248,7 @@ CPUMiner.prototype.wait = function wait() { */ CPUMiner.prototype.createJob = async function createJob(tip, address) { - let attempt = await this.miner.createBlock(tip, address); + const attempt = await this.miner.createBlock(tip, address); return new CPUJob(this, attempt); }; @@ -263,7 +261,7 @@ CPUMiner.prototype.createJob = async function createJob(tip, address) { */ CPUMiner.prototype.mineBlock = async function mineBlock(tip, address) { - let job = await this.createJob(tip, address); + const job = await this.createJob(tip, address); return await this.mineAsync(job); }; @@ -292,9 +290,10 @@ CPUMiner.prototype.notifyEntry = function notifyEntry() { */ CPUMiner.prototype.findNonce = function findNonce(job) { - let data = job.getHeader(); - let target = job.attempt.target; - let interval = CPUMiner.INTERVAL; + const data = job.getHeader(); + const target = job.attempt.target; + const interval = CPUMiner.INTERVAL; + let min = 0; let max = interval; let nonce; @@ -322,16 +321,17 @@ CPUMiner.prototype.findNonce = function findNonce(job) { */ CPUMiner.prototype.findNonceAsync = async function findNonceAsync(job) { - let data = job.getHeader(); - let target = job.attempt.target; - let interval = CPUMiner.INTERVAL; + if (!this.workers) + return this.findNonce(job); + + const data = job.getHeader(); + const target = job.attempt.target; + const interval = CPUMiner.INTERVAL; + let min = 0; let max = interval; let nonce; - if (!this.workers) - return this.findNonce(job); - while (max <= 0xffffffff) { nonce = await this.workers.mine(data, target, min, max); @@ -357,10 +357,9 @@ CPUMiner.prototype.findNonceAsync = async function findNonceAsync(job) { */ CPUMiner.prototype.mine = function mine(job) { - let nonce; - job.start = util.now(); + let nonce; for (;;) { nonce = this.findNonce(job); @@ -394,7 +393,7 @@ CPUMiner.prototype.mineAsync = async function mineAsync(job) { break; if (job.destroyed) - return; + return null; job.updateNonce(); @@ -411,10 +410,10 @@ CPUMiner.prototype.mineAsync = async function mineAsync(job) { */ CPUMiner.prototype.sendStatus = function sendStatus(job, nonce) { - let attempt = job.attempt; - let tip = util.revHex(attempt.prevBlock); - let hashes = job.getHashes(nonce); - let hashrate = job.getRate(nonce); + const attempt = job.attempt; + const tip = util.revHex(attempt.prevBlock); + const hashes = job.getHashes(nonce); + const hashrate = job.getRate(nonce); this.logger.info( 'Status: hashrate=%dkhs hashes=%d target=%d height=%d tip=%s', @@ -453,12 +452,12 @@ function CPUJob(miner, attempt) { */ CPUJob.prototype.getHeader = function getHeader() { - let attempt = this.attempt; - let n1 = this.nonce1; - let n2 = this.nonce2; - let ts = attempt.ts; - let root = attempt.getRoot(n1, n2); - let data = attempt.getHeader(root, ts, 0); + const attempt = this.attempt; + const n1 = this.nonce1; + const n2 = this.nonce2; + const time = attempt.time; + const root = attempt.getRoot(n1, n2); + const data = attempt.getHeader(root, time, 0); return data; }; @@ -469,16 +468,15 @@ CPUJob.prototype.getHeader = function getHeader() { */ CPUJob.prototype.commit = function commit(nonce) { - let attempt = this.attempt; - let n1 = this.nonce1; - let n2 = this.nonce2; - let ts = attempt.ts; - let proof; + const attempt = this.attempt; + const n1 = this.nonce1; + const n2 = this.nonce2; + const time = attempt.time; assert(!this.committed, 'Job already committed.'); this.committed = true; - proof = attempt.getProof(n1, n2, ts, nonce); + const proof = attempt.getProof(n1, n2, time, nonce); return attempt.commit(proof); }; @@ -536,7 +534,7 @@ CPUJob.prototype.destroy = function destroy() { */ CPUJob.prototype.getHashes = function getHashes(nonce) { - let extra = this.nonce1 * 0x100000000 + this.nonce2; + const extra = this.nonce1 * 0x100000000 + this.nonce2; return extra * 0xffffffff + nonce; }; @@ -547,9 +545,9 @@ CPUJob.prototype.getHashes = function getHashes(nonce) { */ CPUJob.prototype.getRate = function getRate(nonce) { - let hashes = this.getHashes(nonce); - let seconds = util.now() - this.start; - return Math.floor(hashes / seconds); + const hashes = this.getHashes(nonce); + const seconds = util.now() - this.start; + return Math.floor(hashes / Math.max(1, seconds)); }; /** diff --git a/lib/mining/miner.js b/lib/mining/miner.js index fc40bd3c1..6b19a254c 100644 --- a/lib/mining/miner.js +++ b/lib/mining/miner.js @@ -36,7 +36,7 @@ function Miner(options) { this.options = new MinerOptions(options); this.network = this.options.network; this.logger = this.options.logger.context('miner'); - this.workers = null; + this.workers = this.options.workers; this.chain = this.options.chain; this.mempool = this.options.mempool; this.addresses = this.options.addresses; @@ -46,7 +46,7 @@ function Miner(options) { this.init(); } -util.inherits(Miner, AsyncObject); +Object.setPrototypeOf(Miner.prototype, AsyncObject.prototype); /** * Open the miner, wait for the chain and mempool to load. @@ -68,7 +68,7 @@ Miner.prototype.init = function init() { * @returns {Promise} */ -Miner.prototype._open = async function open() { +Miner.prototype._open = async function _open() { await this.chain.open(); if (this.mempool) @@ -90,7 +90,7 @@ Miner.prototype._open = async function open() { * @returns {Promise} */ -Miner.prototype._close = async function close() { +Miner.prototype._close = async function _close() { await this.cpu.close(); }; @@ -103,7 +103,7 @@ Miner.prototype._close = async function close() { */ Miner.prototype.createBlock = async function createBlock(tip, address) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._createBlock(tip, address); } finally { @@ -120,9 +120,8 @@ Miner.prototype.createBlock = async function createBlock(tip, address) { * @returns {Promise} - Returns {@link BlockTemplate}. */ -Miner.prototype._createBlock = async function createBlock(tip, address) { +Miner.prototype._createBlock = async function _createBlock(tip, address) { let version = this.options.version; - let ts, mtp, locktime, target, attempt, state; if (!tip) tip = this.chain.tip; @@ -133,22 +132,19 @@ Miner.prototype._createBlock = async function createBlock(tip, address) { if (version === -1) version = await this.chain.computeBlockVersion(tip); - mtp = await tip.getMedianTime(); - ts = Math.max(this.network.now(), mtp + 1); - locktime = ts; - - state = await this.chain.getDeployments(ts, tip); + const mtp = await tip.getMedianTime(); + const time = Math.max(this.network.now(), mtp + 1); - if (state.hasMTP()) - locktime = mtp; + const state = await this.chain.getDeployments(time, tip); + const target = await this.chain.getTarget(time, tip); - target = await this.chain.getTarget(ts, tip); + const locktime = state.hasMTP() ? mtp : time; - attempt = new BlockTemplate({ + const attempt = new BlockTemplate({ prevBlock: tip.hash, height: tip.height + 1, version: version, - ts: ts, + time: time, bits: target, locktime: locktime, mtp: mtp, @@ -172,7 +168,7 @@ Miner.prototype._createBlock = async function createBlock(tip, address) { attempt.getDifficulty()); if (this.options.preverify) { - let block = attempt.toBlock(); + const block = attempt.toBlock(); try { await this.chain._verifyBlock(block); @@ -199,7 +195,7 @@ Miner.prototype._createBlock = async function createBlock(tip, address) { */ Miner.prototype.updateTime = function updateTime(attempt) { - attempt.ts = Math.max(this.network.now(), attempt.mtp + 1); + attempt.time = Math.max(this.network.now(), attempt.mtp + 1); }; /** @@ -255,39 +251,39 @@ Miner.prototype.getAddress = function getAddress() { Miner.prototype.assemble = function assemble(attempt) { let priority = this.options.priorityWeight > 0; - let queue = new Heap(cmpRate); - let depMap = {}; + const queue = new Heap(cmpRate); + const depMap = new Map(); if (priority) queue.set(cmpPriority); if (!this.mempool) { attempt.refresh(); - return []; + return; } assert(this.mempool.tip === this.chain.tip.hash, 'Mempool/chain tip mismatch! Unsafe to create block.'); - for (let entry of this.mempool.map.values()) { - let item = BlockEntry.fromEntry(entry, attempt); - let tx = item.tx; + for (const entry of this.mempool.map.values()) { + const item = BlockEntry.fromEntry(entry, attempt); + const tx = item.tx; if (tx.isCoinbase()) throw new Error('Cannot add coinbase to block.'); - for (let {prevout} of tx.inputs) { - let hash = prevout.hash; + for (const {prevout} of tx.inputs) { + const hash = prevout.hash; if (!this.mempool.hasEntry(hash)) continue; item.depCount += 1; - if (!depMap[hash]) - depMap[hash] = []; + if (!depMap.has(hash)) + depMap.set(hash, []); - depMap[hash].push(item); + depMap.get(hash).push(item); } if (item.depCount > 0) @@ -297,12 +293,11 @@ Miner.prototype.assemble = function assemble(attempt) { } while (queue.size() > 0) { - let item = queue.shift(); - let tx = item.tx; - let hash = item.hash; + const item = queue.shift(); + const tx = item.tx; + const hash = item.hash; let weight = attempt.weight; let sigops = attempt.sigops; - let deps; if (!tx.isFinal(attempt.height, attempt.locktime)) continue; @@ -339,12 +334,12 @@ Miner.prototype.assemble = function assemble(attempt) { attempt.fees += item.fee; attempt.items.push(item); - deps = depMap[hash]; + const deps = depMap.get(hash); if (!deps) continue; - for (let item of deps) { + for (const item of deps) { if (--item.depCount === 0) queue.insert(item); } @@ -356,7 +351,7 @@ Miner.prototype.assemble = function assemble(attempt) { 'Block exceeds reserved weight!'); if (this.options.preverify) { - let block = attempt.toBlock(); + const block = attempt.toBlock(); assert(block.getWeight() <= attempt.weight, 'Block exceeds reserved weight!'); @@ -432,13 +427,13 @@ MinerOptions.prototype.fromOptions = function fromOptions(options) { } if (options.version != null) { - assert(util.isNumber(options.version)); + assert(util.isInt(options.version)); this.version = options.version; } if (options.address) { if (Array.isArray(options.address)) { - for (let item of options.address) + for (const item of options.address) this.addresses.push(new Address(item)); } else { this.addresses.push(new Address(options.address)); @@ -447,7 +442,7 @@ MinerOptions.prototype.fromOptions = function fromOptions(options) { if (options.addresses) { assert(Array.isArray(options.addresses)); - for (let item of options.addresses) + for (const item of options.addresses) this.addresses.push(new Address(item)); } @@ -466,41 +461,41 @@ MinerOptions.prototype.fromOptions = function fromOptions(options) { } if (options.minWeight != null) { - assert(util.isNumber(options.minWeight)); + assert(util.isU32(options.minWeight)); this.minWeight = options.minWeight; } if (options.maxWeight != null) { - assert(util.isNumber(options.maxWeight)); + assert(util.isU32(options.maxWeight)); assert(options.maxWeight <= consensus.MAX_BLOCK_WEIGHT, 'Max weight must be below MAX_BLOCK_WEIGHT'); this.maxWeight = options.maxWeight; } if (options.maxSigops != null) { - assert(util.isNumber(options.maxSigops)); + assert(util.isU32(options.maxSigops)); assert(options.maxSigops <= consensus.MAX_BLOCK_SIGOPS_COST, 'Max sigops must be below MAX_BLOCK_SIGOPS_COST'); this.maxSigops = options.maxSigops; } if (options.priorityWeight != null) { - assert(util.isNumber(options.priorityWeight)); + assert(util.isU32(options.priorityWeight)); this.priorityWeight = options.priorityWeight; } if (options.priorityThreshold != null) { - assert(util.isNumber(options.priorityThreshold)); + assert(util.isU32(options.priorityThreshold)); this.priorityThreshold = options.priorityThreshold; } if (options.reservedWeight != null) { - assert(util.isNumber(options.reservedWeight)); + assert(util.isU32(options.reservedWeight)); this.reservedWeight = options.reservedWeight; } if (options.reservedSigops != null) { - assert(util.isNumber(options.reservedSigops)); + assert(util.isU32(options.reservedSigops)); this.reservedSigops = options.reservedSigops; } diff --git a/lib/mining/template.js b/lib/mining/template.js index 6dd5e7a12..a1a3477bb 100644 --- a/lib/mining/template.js +++ b/lib/mining/template.js @@ -11,7 +11,6 @@ const assert = require('assert'); const util = require('../utils/util'); const digest = require('../crypto/digest'); const merkle = require('../crypto/merkle'); -const BN = require('../crypto/bn'); const StaticWriter = require('../utils/staticwriter'); const Address = require('../primitives/address'); const TX = require('../primitives/tx'); @@ -40,7 +39,7 @@ function BlockTemplate(options) { this.prevBlock = encoding.NULL_HASH; this.version = 1; this.height = 0; - this.ts = 0; + this.time = 0; this.bits = 0; this.target = encoding.ZERO_HASH; this.locktime = 0; @@ -88,9 +87,9 @@ BlockTemplate.prototype.fromOptions = function fromOptions(options) { this.height = options.height; } - if (options.ts != null) { - assert(typeof options.ts === 'number'); - this.ts = options.ts; + if (options.time != null) { + assert(typeof options.time === 'number'); + this.time = options.time; } if (options.bits != null) @@ -171,16 +170,15 @@ BlockTemplate.fromOptions = function fromOptions(options) { */ BlockTemplate.prototype.getWitnessHash = function getWitnessHash() { - let nonce = encoding.ZERO_HASH; - let leaves = []; - let root, malleated; + const nonce = encoding.ZERO_HASH; + const leaves = []; leaves.push(encoding.ZERO_HASH); - for (let item of this.items) + for (const item of this.items) leaves.push(item.tx.witnessHash()); - [root, malleated] = merkle.createRoot(leaves); + const [root, malleated] = merkle.createRoot(leaves); assert(!malleated); @@ -224,7 +222,7 @@ BlockTemplate.prototype.setTarget = function setTarget(target) { */ BlockTemplate.prototype.getReward = function getReward() { - let reward = consensus.getReward(this.height, this.interval); + const reward = consensus.getReward(this.height, this.interval); return reward + this.fees; }; @@ -235,39 +233,37 @@ BlockTemplate.prototype.getReward = function getReward() { */ BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) { - let scale = consensus.WITNESS_SCALE_FACTOR; - let cb = new TX(); - let padding = 0; - let input, output, commit; + const scale = consensus.WITNESS_SCALE_FACTOR; + const cb = new TX(); // Coinbase input. - input = new Input(); + const input = new Input(); // Height (required in v2+ blocks) - input.script.push(new BN(this.height)); + input.script.pushInt(this.height); // Coinbase flags. - input.script.push(encoding.ZERO_HASH160); + input.script.pushData(encoding.ZERO_HASH160); // Smaller nonce for good measure. - input.script.push(util.nonce(4)); + input.script.pushData(util.nonce(4)); // Extra nonce: incremented when // the nonce overflows. - input.script.push(encoding.ZERO_U64); + input.script.pushData(encoding.ZERO_U64); input.script.compile(); // Set up the witness nonce. if (this.witness) { - input.witness.set(0, encoding.ZERO_HASH); + input.witness.push(encoding.ZERO_HASH); input.witness.compile(); } cb.inputs.push(input); // Reward output. - output = new Output(); + const output = new Output(); output.script.fromPubkeyhash(encoding.ZERO_HASH160); output.value = this.getReward(); @@ -277,13 +273,15 @@ BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) { // need to set up the commitment. if (this.witness) { // Commitment output. - commit = new Output(); + const commit = new Output(); commit.script.fromCommitment(hash); cb.outputs.push(commit); } // Padding for the CB height (constant size). - padding = 5 - input.script.code[0].getSize(); + const op = input.script.get(0); + assert(op); + const padding = 5 - op.getSize(); assert(padding >= 0); // Reserved size. @@ -298,21 +296,20 @@ BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) { // CB size = 208 // Sigops cost = 4 if (!this.witness) { - assert.equal(cb.getWeight() + padding * scale, 500); - assert.equal(cb.getBaseSize() + padding, 125); - assert.equal(cb.getSize() + padding, 125); + assert.strictEqual(cb.getWeight() + padding * scale, 500); + assert.strictEqual(cb.getBaseSize() + padding, 125); + assert.strictEqual(cb.getSize() + padding, 125); } else { - assert.equal(cb.getWeight() + padding * scale, 724); - assert.equal(cb.getBaseSize() + padding, 172); - assert.equal(cb.getSize() + padding, 208); + assert.strictEqual(cb.getWeight() + padding * scale, 724); + assert.strictEqual(cb.getBaseSize() + padding, 172); + assert.strictEqual(cb.getSize() + padding, 208); } // Setup coinbase flags (variable size). - input.script.set(1, this.coinbaseFlags); + input.script.setData(1, this.coinbaseFlags); input.script.compile(); // Setup output script (variable size). - output.script.clear(); output.script.fromAddress(this.address); cb.refresh(); @@ -328,11 +325,10 @@ BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) { */ BlockTemplate.prototype.refresh = function refresh() { - let hash = this.getWitnessHash(); - let cb = this.createCoinbase(hash); - let raw = cb.toNormal(); + const hash = this.getWitnessHash(); + const cb = this.createCoinbase(hash); + const raw = cb.toNormal(); let size = 0; - let left, right; size += 4; // version size += 1; // varint inputs length @@ -341,11 +337,11 @@ BlockTemplate.prototype.refresh = function refresh() { // Cut off right after the nonce // push and before the sequence. - left = raw.slice(0, size); + const left = raw.slice(0, size); // Include the sequence. size += 4 + 4; // nonce1 + nonce2 - right = raw.slice(size); + const right = raw.slice(size); this.commitment = hash; this.left = left; @@ -362,13 +358,12 @@ BlockTemplate.prototype.refresh = function refresh() { BlockTemplate.prototype.getRawCoinbase = function getRawCoinbase(nonce1, nonce2) { let size = 0; - let bw; size += this.left.length; size += 4 + 4; size += this.right.length; - bw = new StaticWriter(size); + const bw = new StaticWriter(size); bw.writeBytes(this.left); bw.writeU32BE(nonce1); bw.writeU32BE(nonce2); @@ -385,26 +380,26 @@ BlockTemplate.prototype.getRawCoinbase = function getRawCoinbase(nonce1, nonce2) */ BlockTemplate.prototype.getRoot = function getRoot(nonce1, nonce2) { - let raw = this.getRawCoinbase(nonce1, nonce2); - let hash = digest.hash256(raw); + const raw = this.getRawCoinbase(nonce1, nonce2); + const hash = digest.hash256(raw); return this.tree.withFirst(hash); }; /** * Create raw block header with given parameters. * @param {Buffer} root - * @param {Number} ts + * @param {Number} time * @param {Number} nonce * @returns {Buffer} */ -BlockTemplate.prototype.getHeader = function getHeader(root, ts, nonce) { - let bw = new StaticWriter(80); +BlockTemplate.prototype.getHeader = function getHeader(root, time, nonce) { + const bw = new StaticWriter(80); bw.writeU32(this.version); bw.writeHash(this.prevBlock); bw.writeHash(root); - bw.writeU32(ts); + bw.writeU32(time); bw.writeU32(this.bits); bw.writeU32(nonce); @@ -415,16 +410,16 @@ BlockTemplate.prototype.getHeader = function getHeader(root, ts, nonce) { * Calculate proof with given parameters. * @param {Number} nonce1 * @param {Number} nonce2 - * @param {Number} ts + * @param {Number} time * @param {Number} nonce * @returns {BlockProof} */ -BlockTemplate.prototype.getProof = function getProof(nonce1, nonce2, ts, nonce) { - let root = this.getRoot(nonce1, nonce2); - let data = this.getHeader(root, ts, nonce); - let hash = digest.hash256(data); - return new BlockProof(hash, root, nonce1, nonce2, ts, nonce); +BlockTemplate.prototype.getProof = function getProof(nonce1, nonce2, time, nonce) { + const root = this.getRoot(nonce1, nonce2); + const data = this.getHeader(root, time, nonce); + const hash = digest.hash256(data); + return new BlockProof(hash, root, nonce1, nonce2, time, nonce); }; /** @@ -435,12 +430,11 @@ BlockTemplate.prototype.getProof = function getProof(nonce1, nonce2, ts, nonce) */ BlockTemplate.prototype.getCoinbase = function getCoinbase(nonce1, nonce2) { - let raw = this.getRawCoinbase(nonce1, nonce2); - let tx = TX.fromRaw(raw); - let input; + const raw = this.getRawCoinbase(nonce1, nonce2); + const tx = TX.fromRaw(raw); if (this.witness) { - input = tx.inputs[0]; + const input = tx.inputs[0]; input.witness.push(encoding.ZERO_HASH); input.witness.compile(); tx.refresh(); @@ -456,26 +450,25 @@ BlockTemplate.prototype.getCoinbase = function getCoinbase(nonce1, nonce2) { */ BlockTemplate.prototype.commit = function commit(proof) { - let root = proof.root; - let n1 = proof.nonce1; - let n2 = proof.nonce2; - let ts = proof.ts; - let nonce = proof.nonce; - let block = new Block(); - let tx; + const root = proof.root; + const n1 = proof.nonce1; + const n2 = proof.nonce2; + const time = proof.time; + const nonce = proof.nonce; + const block = new Block(); block.version = this.version; block.prevBlock = this.prevBlock; block.merkleRoot = root.toString('hex'); - block.ts = ts; + block.time = time; block.bits = this.bits; block.nonce = nonce; - tx = this.getCoinbase(n1, n2); + const tx = this.getCoinbase(n1, n2); block.txs.push(tx); - for (let item of this.items) + for (const item of this.items) block.txs.push(item.tx); return block; @@ -498,7 +491,7 @@ BlockTemplate.prototype.toCoinbase = function toCoinbase() { */ BlockTemplate.prototype.toBlock = function toBlock() { - let proof = this.getProof(0, 0, this.ts, 0); + const proof = this.getProof(0, 0, this.time, 0); return this.commit(proof); }; @@ -529,13 +522,11 @@ BlockTemplate.prototype.setAddress = function setAddress(address) { */ BlockTemplate.prototype.addTX = function addTX(tx, view) { - let item, weight, sigops; - assert(!tx.mutable, 'Cannot add mutable TX to block.'); - item = BlockEntry.fromTX(tx, view, this); - weight = item.tx.getWeight(); - sigops = item.sigops; + const item = BlockEntry.fromTX(tx, view, this); + const weight = item.tx.getWeight(); + const sigops = item.sigops; if (!tx.isFinal(this.height, this.locktime)) return false; @@ -567,16 +558,14 @@ BlockTemplate.prototype.addTX = function addTX(tx, view) { */ BlockTemplate.prototype.pushTX = function pushTX(tx, view) { - let item, weight, sigops; - assert(!tx.mutable, 'Cannot add mutable TX to block.'); if (!view) view = new CoinView(); - item = BlockEntry.fromTX(tx, view, this); - weight = item.tx.getWeight(); - sigops = item.sigops; + const item = BlockEntry.fromTX(tx, view, this); + const weight = item.tx.getWeight(); + const sigops = item.sigops; this.weight += weight; this.sigops += sigops; @@ -624,7 +613,7 @@ function BlockEntry(tx) { */ BlockEntry.fromTX = function fromTX(tx, view, attempt) { - let item = new BlockEntry(tx); + const item = new BlockEntry(tx); item.fee = tx.getFee(view); item.rate = tx.getRate(view); item.priority = tx.getPriority(view, attempt.height); @@ -642,7 +631,7 @@ BlockEntry.fromTX = function fromTX(tx, view, attempt) { */ BlockEntry.fromEntry = function fromEntry(entry, attempt) { - let item = new BlockEntry(entry.tx); + const item = new BlockEntry(entry.tx); item.fee = entry.getFee(); item.rate = entry.getDeltaRate(); item.priority = entry.getPriority(attempt.height); @@ -659,16 +648,16 @@ BlockEntry.fromEntry = function fromEntry(entry, attempt) { * @param {Hash} root * @param {Number} nonce1 * @param {Number} nonce2 - * @param {Number} ts + * @param {Number} time * @param {Number} nonce */ -function BlockProof(hash, root, nonce1, nonce2, ts, nonce) { +function BlockProof(hash, root, nonce1, nonce2, time, nonce) { this.hash = hash; this.root = root; this.nonce1 = nonce1; this.nonce2 = nonce2; - this.ts = ts; + this.time = time; this.nonce = nonce; } @@ -695,26 +684,26 @@ function MerkleTree() { } MerkleTree.prototype.withFirst = function withFirst(hash) { - for (let step of this.steps) + for (const step of this.steps) hash = digest.root256(hash, step); return hash; }; MerkleTree.prototype.toJSON = function toJSON() { - let steps = []; + const steps = []; - for (let step of this.steps) + for (const step of this.steps) steps.push(step.toString('hex')); return steps; }; MerkleTree.prototype.fromItems = function fromItems(items) { - let leaves = []; + const leaves = []; leaves.push(encoding.ZERO_HASH); - for (let item of items) + for (const item of items) leaves.push(item.tx.hash()); return this.fromLeaves(leaves); @@ -725,12 +714,12 @@ MerkleTree.fromItems = function fromItems(items) { }; MerkleTree.prototype.fromBlock = function fromBlock(txs) { - let leaves = []; + const leaves = []; leaves.push(encoding.ZERO_HASH); for (let i = 1; i < txs.length; i++) { - let tx = txs[i]; + const tx = txs[i]; leaves.push(tx.hash()); } @@ -745,7 +734,7 @@ MerkleTree.prototype.fromLeaves = function fromLeaves(leaves) { let len = leaves.length; while (len > 1) { - let hashes = [encoding.ZERO_HASH]; + const hashes = [encoding.ZERO_HASH]; this.steps.push(leaves[1]); @@ -753,7 +742,7 @@ MerkleTree.prototype.fromLeaves = function fromLeaves(leaves) { leaves.push(leaves[len - 1]); for (let i = 2; i < len; i += 2) { - let hash = digest.root256(leaves[i], leaves[i + 1]); + const hash = digest.root256(leaves[i], leaves[i + 1]); hashes.push(hash); } diff --git a/lib/native.js b/lib/native.js index 0c9df7333..cdd376393 100644 --- a/lib/native.js +++ b/lib/native.js @@ -8,7 +8,7 @@ exports.binding = null; -if (+process.env.BCOIN_NO_NATIVE !== 1) { +if (Number(process.env.BCOIN_NO_NATIVE) !== 1) { try { exports.binding = require('bcoin-native'); } catch (e) { diff --git a/lib/net/bip150.js b/lib/net/bip150.js index 36905e40f..810857bc8 100644 --- a/lib/net/bip150.js +++ b/lib/net/bip150.js @@ -11,7 +11,6 @@ const assert = require('assert'); const path = require('path'); const EventEmitter = require('events'); -const util = require('../utils/util'); const co = require('../utils/co'); const digest = require('../crypto/digest'); const random = require('../crypto/random'); @@ -87,7 +86,7 @@ function BIP150(bip151, host, outbound, db, key) { this._init(); } -util.inherits(BIP150, EventEmitter); +Object.setPrototypeOf(BIP150.prototype, EventEmitter.prototype); /** * Initialize BIP150. @@ -121,8 +120,7 @@ BIP150.prototype.isAuthed = function isAuthed() { */ BIP150.prototype.challenge = function challenge(hash) { - let type = this.outbound ? 'r' : 'i'; - let msg, sig; + const type = this.outbound ? 'r' : 'i'; assert(this.bip151.handshake, 'No BIP151 handshake before challenge.'); assert(!this.challengeReceived, 'Peer challenged twice.'); @@ -131,7 +129,7 @@ BIP150.prototype.challenge = function challenge(hash) { if (hash.equals(encoding.ZERO_HASH)) throw new Error('Auth failure.'); - msg = this.hash(this.input.sid, type, this.publicKey); + const msg = this.hash(this.input.sid, type, this.publicKey); if (!ccmp(hash, msg)) return encoding.ZERO_SIG64; @@ -141,7 +139,7 @@ BIP150.prototype.challenge = function challenge(hash) { this.emit('auth'); } - sig = secp256k1.sign(msg, this.privateKey); + const sig = secp256k1.sign(msg, this.privateKey); // authreply return secp256k1.fromDER(sig); @@ -156,8 +154,7 @@ BIP150.prototype.challenge = function challenge(hash) { */ BIP150.prototype.reply = function reply(data) { - let type = this.outbound ? 'i' : 'r'; - let sig, msg, result; + const type = this.outbound ? 'i' : 'r'; assert(this.challengeSent, 'Unsolicited reply.'); assert(!this.replyReceived, 'Peer replied twice.'); @@ -169,10 +166,10 @@ BIP150.prototype.reply = function reply(data) { if (!this.peerIdentity) return random.randomBytes(32); - sig = secp256k1.toDER(data); - msg = this.hash(this.output.sid, type, this.peerIdentity); + const sig = secp256k1.toDER(data); + const msg = this.hash(this.output.sid, type, this.peerIdentity); - result = secp256k1.verify(msg, sig, this.peerIdentity); + const result = secp256k1.verify(msg, sig, this.peerIdentity); if (!result) return random.randomBytes(32); @@ -180,7 +177,7 @@ BIP150.prototype.reply = function reply(data) { if (this.isAuthed()) { this.auth = true; this.emit('auth'); - return; + return null; } assert(this.outbound, 'No challenge received before reply on inbound.'); @@ -197,14 +194,12 @@ BIP150.prototype.reply = function reply(data) { */ BIP150.prototype.propose = function propose(hash) { - let match; - assert(!this.outbound, 'Outbound peer tried to propose.'); assert(!this.challengeSent, 'Unsolicited propose.'); assert(!this.proposeReceived, 'Peer proposed twice.'); this.proposeReceived = true; - match = this.findAuthorized(hash); + const match = this.findAuthorized(hash); if (!match) return encoding.ZERO_HASH; @@ -228,13 +223,11 @@ BIP150.prototype.propose = function propose(hash) { */ BIP150.prototype.toChallenge = function toChallenge() { - let msg; - assert(this.bip151.handshake, 'No BIP151 handshake before challenge.'); assert(this.outbound, 'Cannot challenge an inbound connection.'); assert(this.peerIdentity, 'Cannot challenge without a peer identity.'); - msg = this.hash(this.output.sid, 'i', this.peerIdentity); + const msg = this.hash(this.output.sid, 'i', this.peerIdentity); assert(!this.challengeSent, 'Cannot initiate challenge twice.'); this.challengeSent = true; @@ -254,7 +247,7 @@ BIP150.prototype.toChallenge = function toChallenge() { */ BIP150.prototype.rekey = function rekey(sid, key, req, res) { - let seed = Buffer.allocUnsafe(130); + const seed = Buffer.allocUnsafe(130); sid.copy(seed, 0); key.copy(seed, 32); req.copy(seed, 64); @@ -268,11 +261,11 @@ BIP150.prototype.rekey = function rekey(sid, key, req, res) { */ BIP150.prototype.rekeyInput = function rekeyInput() { - let stream = this.input; - let req = this.peerIdentity; - let res = this.publicKey; - let k1 = this.rekey(stream.sid, stream.k1, req, res); - let k2 = this.rekey(stream.sid, stream.k2, req, res); + const stream = this.input; + const req = this.peerIdentity; + const res = this.publicKey; + const k1 = this.rekey(stream.sid, stream.k1, req, res); + const k2 = this.rekey(stream.sid, stream.k2, req, res); stream.rekey(k1, k2); }; @@ -282,11 +275,11 @@ BIP150.prototype.rekeyInput = function rekeyInput() { */ BIP150.prototype.rekeyOutput = function rekeyOutput() { - let stream = this.output; - let req = this.publicKey; - let res = this.peerIdentity; - let k1 = this.rekey(stream.sid, stream.k1, req, res); - let k2 = this.rekey(stream.sid, stream.k2, req, res); + const stream = this.output; + const req = this.publicKey; + const res = this.peerIdentity; + const k1 = this.rekey(stream.sid, stream.k1, req, res); + const k2 = this.rekey(stream.sid, stream.k2, req, res); stream.rekey(k1, k2); }; @@ -299,7 +292,7 @@ BIP150.prototype.rekeyOutput = function rekeyOutput() { */ BIP150.prototype.hash = function hash(sid, ch, key) { - let data = Buffer.allocUnsafe(66); + const data = Buffer.allocUnsafe(66); sid.copy(data, 0); data[32] = ch.charCodeAt(0); key.copy(data, 33); @@ -318,8 +311,8 @@ BIP150.prototype.hash = function hash(sid, ch, key) { BIP150.prototype.findAuthorized = function findAuthorized(hash) { // Scary O(n) stuff. - for (let key of this.db.authorized) { - let msg = this.hash(this.output.sid, 'p', key); + for (const key of this.db.authorized) { + const msg = this.hash(this.output.sid, 'p', key); // XXX Do we really need a constant // time compare here? Do it just to @@ -327,6 +320,8 @@ BIP150.prototype.findAuthorized = function findAuthorized(hash) { if (ccmp(msg, hash)) return key; } + + return null; }; /** @@ -347,8 +342,8 @@ BIP150.prototype.destroy = function destroy() { * @returns {Job} */ -BIP150.prototype.cleanup = function cleanup(err) { - let job = this.job; +BIP150.prototype.cleanup = function cleanup() { + const job = this.job; assert(!this.completed, 'Already completed.'); assert(job, 'No completion job.'); @@ -376,7 +371,7 @@ BIP150.prototype.cleanup = function cleanup(err) { */ BIP150.prototype.resolve = function resolve(result) { - let job = this.cleanup(); + const job = this.cleanup(); job.resolve(result); }; @@ -387,7 +382,7 @@ BIP150.prototype.resolve = function resolve(result) { */ BIP150.prototype.reject = function reject(err) { - let job = this.cleanup(); + const job = this.cleanup(); job.reject(err); }; @@ -411,7 +406,7 @@ BIP150.prototype.wait = function wait(timeout) { * @param {Function} reject */ -BIP150.prototype._wait = function wait(timeout, resolve, reject) { +BIP150.prototype._wait = function _wait(timeout, resolve, reject) { assert(!this.auth, 'Cannot wait for init after handshake.'); this.job = co.job(resolve, reject); @@ -447,7 +442,7 @@ BIP150.prototype.getAddress = function getAddress() { */ BIP150.address = function address(key) { - let bw = new StaticWriter(27); + const bw = new StaticWriter(27); bw.writeU8(0x0f); bw.writeU16BE(0xff01); bw.writeBytes(digest.hash160(key)); @@ -470,7 +465,7 @@ function AuthDB(options) { this.prefix = null; this.dnsKnown = []; - this.known = {}; + this.known = new Map(); this.authorized = []; this._init(options); @@ -540,15 +535,13 @@ AuthDB.prototype.close = async function close() { */ AuthDB.prototype.addKnown = function addKnown(host, key) { - let addr; - assert(typeof host === 'string', 'Known host must be a string.'); assert(Buffer.isBuffer(key) && key.length === 33, 'Invalid public key for known peer.'); - addr = IP.fromHostname(host); + const addr = IP.fromHostname(host); if (addr.type === IP.types.DNS) { // Defer this for resolution. @@ -556,7 +549,7 @@ AuthDB.prototype.addKnown = function addKnown(host, key) { return; } - this.known[host] = key; + this.known.set(host, key); }; /** @@ -576,12 +569,10 @@ AuthDB.prototype.addAuthorized = function addAuthorized(key) { */ AuthDB.prototype.setKnown = function setKnown(map) { - let keys = Object.keys(map); + this.known.clear(); - this.known = {}; - - for (let host of keys) { - let key = map[host]; + for (const host of Object.keys(map)) { + const key = map[host]; this.addKnown(host, key); } }; @@ -594,7 +585,7 @@ AuthDB.prototype.setKnown = function setKnown(map) { AuthDB.prototype.setAuthorized = function setAuthorized(keys) { this.authorized.length = 0; - for (let key of keys) + for (const key of keys) this.addAuthorized(key); }; @@ -605,15 +596,14 @@ AuthDB.prototype.setAuthorized = function setAuthorized(keys) { */ AuthDB.prototype.getKnown = function getKnown(hostname) { - let known = this.known[hostname]; - let addr; + const known = this.known.get(hostname); if (known) return known; - addr = IP.fromHostname(hostname); + const addr = IP.fromHostname(hostname); - return this.known[addr.host]; + return this.known.get(addr.host); }; /** @@ -623,10 +613,10 @@ AuthDB.prototype.getKnown = function getKnown(hostname) { */ AuthDB.prototype.lookup = async function lookup() { - let jobs = []; + const jobs = []; - for (let addr of this.dnsKnown) - jobs.push(this.populate(addr[0], addr[1])); + for (const [addr, key] of this.dnsKnown) + jobs.push(this.populate(addr, key)); await Promise.all(jobs); }; @@ -641,12 +631,11 @@ AuthDB.prototype.lookup = async function lookup() { */ AuthDB.prototype.populate = async function populate(addr, key) { - let hosts; - assert(addr.type === IP.types.DNS, 'Resolved host passed.'); this.logger.info('Resolving authorized hosts from: %s.', addr.host); + let hosts; try { hosts = await this.resolve(addr.host); } catch (e) { @@ -658,7 +647,7 @@ AuthDB.prototype.populate = async function populate(addr, key) { if (addr.port !== 0) host = IP.toHostname(host, addr.port); - this.known[host] = key; + this.known.set(host, key); } }; @@ -669,16 +658,15 @@ AuthDB.prototype.populate = async function populate(addr, key) { */ AuthDB.prototype.readKnown = async function readKnown() { - let file, text; - if (fs.unsupported) return; if (!this.prefix) return; - file = path.join(this.prefix, 'known-peers'); + const file = path.join(this.prefix, 'known-peers'); + let text; try { text = await fs.readFile(file, 'utf8'); } catch (e) { @@ -697,47 +685,55 @@ AuthDB.prototype.readKnown = async function readKnown() { */ AuthDB.prototype.parseKnown = function parseKnown(text) { - let lines = text.split(/\n+/); + assert(typeof text === 'string'); + + if (text.charCodeAt(0) === 0xfeff) + text = text.substring(1); + + text = text.replace(/\r\n/g, '\n'); + text = text.replace(/\r/g, '\n'); - for (let line of lines) { - let parts, hostname, host, ip, key; + let num = 0; - line = line.trim(); + for (const chunk of text.split('\n')) { + const line = chunk.trim(); + + num += 1; if (line.length === 0) continue; - if (/^\s*#/.test(line)) + if (line[0] === '#') continue; - parts = line.split(/\s+/); + const parts = line.split(/\s+/); if (parts.length < 2) - continue; + throw new Error(`No key present on line ${num}: "${line}".`); - hostname = parts[0].trim().split(','); + const hosts = parts[0].split(','); - if (hostname.length >= 2) { - host = hostname[0]; - ip = hostname[1]; + let host, addr; + if (hosts.length >= 2) { + host = hosts[0]; + addr = hosts[1]; } else { host = null; - ip = hostname[0]; + addr = hosts[0]; } - key = parts[1].trim(); - key = Buffer.from(key, 'hex'); + const key = Buffer.from(parts[1], 'hex'); if (key.length !== 33) - throw new Error(`Invalid key: ${parts[1]}.`); + throw new Error(`Invalid key on line ${num}: "${parts[1]}".`); if (host && host.length > 0) this.addKnown(host, key); - if (ip.length === 0) + if (addr.length === 0) continue; - this.addKnown(ip, key); + this.addKnown(addr, key); } }; @@ -748,16 +744,15 @@ AuthDB.prototype.parseKnown = function parseKnown(text) { */ AuthDB.prototype.readAuth = async function readAuth() { - let file, text; - if (fs.unsupported) return; if (!this.prefix) return; - file = path.join(this.prefix, 'authorized-peers'); + const file = path.join(this.prefix, 'authorized-peers'); + let text; try { text = await fs.readFile(file, 'utf8'); } catch (e) { @@ -776,23 +771,31 @@ AuthDB.prototype.readAuth = async function readAuth() { */ AuthDB.prototype.parseAuth = function parseAuth(text) { - let lines = text.split(/\n+/); + assert(typeof text === 'string'); + + if (text.charCodeAt(0) === 0xfeff) + text = text.substring(1); + + text = text.replace(/\r\n/g, '\n'); + text = text.replace(/\r/g, '\n'); + + let num = 0; - for (let line of lines) { - let key; + for (const chunk of text.split('\n')) { + const line = chunk.trim(); - line = line.trim(); + num += 1; if (line.length === 0) continue; - if (/^\s*#/.test(line)) + if (line[0] === '#') continue; - key = Buffer.from(line, 'hex'); + const key = Buffer.from(line, 'hex'); if (key.length !== 33) - throw new Error(`Invalid key: ${line}.`); + throw new Error(`Invalid key on line ${num}: "${line}".`); this.addAuthorized(key); } diff --git a/lib/net/bip151.js b/lib/net/bip151.js index 43f249432..d01516b42 100644 --- a/lib/net/bip151.js +++ b/lib/net/bip151.js @@ -95,7 +95,7 @@ function BIP151Stream(cipher) { */ BIP151Stream.prototype.init = function init(publicKey) { - let bw = new StaticWriter(33); + const bw = new StaticWriter(33); this.publicKey = publicKey; this.secret = secp256k1.ecdh(this.publicKey, this.privateKey); @@ -126,7 +126,7 @@ BIP151Stream.prototype.init = function init(publicKey) { */ BIP151Stream.prototype.shouldRekey = function shouldRekey(packet) { - let now = util.now(); + const now = util.now(); this.processed += packet.length; @@ -149,7 +149,7 @@ BIP151Stream.prototype.rekey = function rekey(k1, k2) { assert(this.prk, 'Cannot rekey before initialization.'); if (!k1) { - let seed = Buffer.allocUnsafe(64); + const seed = Buffer.allocUnsafe(64); this.sid.copy(seed, 0); @@ -329,7 +329,7 @@ function BIP151(cipher) { this.bip150 = null; } -util.inherits(BIP151, EventEmitter); +Object.setPrototypeOf(BIP151.prototype, EventEmitter.prototype); /** * Cipher list. @@ -354,7 +354,7 @@ BIP151.MAX_MESSAGE = 12 * 1000 * 1000; */ BIP151.prototype.error = function error() { - let msg = util.fmt.apply(util, arguments); + const msg = util.fmt.apply(util, arguments); this.emit('error', new Error(msg)); }; @@ -466,7 +466,7 @@ BIP151.prototype.encack = function encack(publicKey) { */ BIP151.prototype.cleanup = function cleanup() { - let job = this.job; + const job = this.job; assert(!this.completed, 'Already completed.'); assert(job, 'No completion job.'); @@ -493,7 +493,7 @@ BIP151.prototype.cleanup = function cleanup() { */ BIP151.prototype.resolve = function resolve(result) { - let job = this.cleanup(); + const job = this.cleanup(); job.resolve(result); }; @@ -503,7 +503,7 @@ BIP151.prototype.resolve = function resolve(result) { */ BIP151.prototype.reject = function reject(err) { - let job = this.cleanup(); + const job = this.cleanup(); job.reject(err); }; @@ -527,7 +527,7 @@ BIP151.prototype.wait = function wait(timeout) { * @param {Function} reject */ -BIP151.prototype._wait = function wait(timeout, resolve, reject) { +BIP151.prototype._wait = function _wait(timeout, resolve, reject) { assert(!this.handshake, 'Cannot wait for init after handshake.'); this.job = co.job(resolve, reject); @@ -595,11 +595,10 @@ BIP151.prototype.packetSize = function packetSize(cmd, body) { * @returns {Buffer} Ciphertext payload */ -BIP151.prototype.packet = function _packet(cmd, body) { - let size = this.packetSize(cmd, body); - let bw = new StaticWriter(size); - let payloadSize = size - 20; - let packet, payload; +BIP151.prototype.packet = function packet(cmd, body) { + const size = this.packetSize(cmd, body); + const bw = new StaticWriter(size); + const payloadSize = size - 20; bw.writeU32(payloadSize); bw.writeVarString(cmd, 'ascii'); @@ -607,17 +606,17 @@ BIP151.prototype.packet = function _packet(cmd, body) { bw.writeBytes(body); bw.seek(16); - packet = bw.render(); - payload = packet.slice(4, 4 + payloadSize); + const msg = bw.render(); + const payload = msg.slice(4, 4 + payloadSize); - this.maybeRekey(packet); + this.maybeRekey(msg); - this.output.encryptSize(packet); + this.output.encryptSize(msg); this.output.encrypt(payload); - this.output.finish().copy(packet, 4 + payloadSize); + this.output.finish().copy(msg, 4 + payloadSize); this.output.sequence(); - return packet; + return msg; }; /** @@ -632,7 +631,7 @@ BIP151.prototype.feed = function feed(data) { this.pending.push(data); while (this.total >= this.waiting) { - let chunk = this.read(this.waiting); + const chunk = this.read(this.waiting); this.parse(chunk); } }; @@ -645,35 +644,32 @@ BIP151.prototype.feed = function feed(data) { */ BIP151.prototype.read = function read(size) { - let pending, chunk, off, len; - assert(this.total >= size, 'Reading too much.'); if (size === 0) return Buffer.alloc(0); - pending = this.pending[0]; + const pending = this.pending[0]; if (pending.length > size) { - chunk = pending.slice(0, size); + const chunk = pending.slice(0, size); this.pending[0] = pending.slice(size); this.total -= chunk.length; return chunk; } if (pending.length === size) { - chunk = this.pending.shift(); + const chunk = this.pending.shift(); this.total -= chunk.length; return chunk; } - chunk = Buffer.allocUnsafe(size); - off = 0; - len = 0; + const chunk = Buffer.allocUnsafe(size); + let off = 0; while (off < chunk.length) { - pending = this.pending[0]; - len = pending.copy(chunk, off); + const pending = this.pending[0]; + const len = pending.copy(chunk, off); if (len === pending.length) this.pending.shift(); else @@ -681,7 +677,7 @@ BIP151.prototype.read = function read(size) { off += len; } - assert.equal(off, chunk.length); + assert.strictEqual(off, chunk.length); this.total -= chunk.length; @@ -695,10 +691,8 @@ BIP151.prototype.read = function read(size) { */ BIP151.prototype.parse = function parse(data) { - let payload, tag, br; - if (!this.hasSize) { - let size = this.input.decryptSize(data); + const size = this.input.decryptSize(data); assert(this.waiting === 4); assert(data.length === 4); @@ -720,8 +714,8 @@ BIP151.prototype.parse = function parse(data) { return; } - payload = data.slice(0, this.waiting - 16); - tag = data.slice(this.waiting - 16, this.waiting); + const payload = data.slice(0, this.waiting - 16); + const tag = data.slice(this.waiting - 16, this.waiting); this.hasSize = false; this.waiting = 4; @@ -741,7 +735,7 @@ BIP151.prototype.parse = function parse(data) { this.input.decrypt(payload); this.input.sequence(); - br = new BufferReader(payload); + const br = new BufferReader(payload); while (br.left()) { let cmd, body; diff --git a/lib/net/bip152.js b/lib/net/bip152.js index 949ef7a56..1a33af0d9 100644 --- a/lib/net/bip152.js +++ b/lib/net/bip152.js @@ -13,7 +13,6 @@ const assert = require('assert'); const util = require('../utils/util'); const BufferReader = require('../utils/reader'); -const BufferWriter = require('../utils/writer'); const StaticWriter = require('../utils/staticwriter'); const encoding = require('../utils/encoding'); const consensus = require('../protocol/consensus'); @@ -60,7 +59,7 @@ function CompactBlock(options) { this.fromOptions(options); } -util.inherits(CompactBlock, AbstractBlock); +Object.setPrototypeOf(CompactBlock.prototype, AbstractBlock.prototype); /** * Inject properties from options object. @@ -91,9 +90,7 @@ CompactBlock.prototype.fromOptions = function fromOptions(options) { if (options.totalTX != null) this.totalTX = options.totalTX; - this.sipKey = options.sipKey; - - this.initKey(); + this.sipKey = this.getKey(); return this; }; @@ -124,41 +121,36 @@ CompactBlock.prototype.verifyBody = function verifyBody() { */ CompactBlock.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let count; + const br = new BufferReader(data); - this.version = br.readU32(); - this.prevBlock = br.readHash('hex'); - this.merkleRoot = br.readHash('hex'); - this.ts = br.readU32(); - this.bits = br.readU32(); - this.nonce = br.readU32(); + this.readHead(br); this.keyNonce = br.readBytes(8); + this.sipKey = this.getKey(); - this.initKey(); - - count = br.readVarint(); + const idCount = br.readVarint(); - this.totalTX += count; + this.totalTX += idCount; - for (let i = 0; i < count; i++) - this.ids.push(br.readU32() + br.readU16() * 0x100000000); + for (let i = 0; i < idCount; i++) { + const lo = br.readU32(); + const hi = br.readU16(); + this.ids.push(hi * 0x100000000 + lo); + } - count = br.readVarint(); + const txCount = br.readVarint(); - this.totalTX += count; + this.totalTX += txCount; - for (let i = 0; i < count; i++) { - let index = br.readVarint(); - let tx; + for (let i = 0; i < txCount; i++) { + const index = br.readVarint(); assert(index <= 0xffff); assert(index < this.totalTX); - tx = TX.fromReader(br); + const tx = TX.fromReader(br); - this.ptx.push(new PrefilledTX(index, tx)); + this.ptx.push([index, tx]); } return this; @@ -223,7 +215,7 @@ CompactBlock.prototype.toNormalWriter = function toNormalWriter(bw) { */ CompactBlock.prototype.frameRaw = function frameRaw(witness) { - let size = this.getSize(witness); + const size = this.getSize(witness); return this.writeRaw(new StaticWriter(size), witness).render(); }; @@ -242,12 +234,13 @@ CompactBlock.prototype.getSize = function getSize(witness) { size += this.ids.length * 6; size += encoding.sizeVarint(this.ptx.length); - for (let ptx of this.ptx) { - size += encoding.sizeVarint(ptx.index); + for (const [index, tx] of this.ptx) { + size += encoding.sizeVarint(index); + if (witness) - size += ptx.tx.getSize(); + size += tx.getSize(); else - size += ptx.tx.getBaseSize(); + size += tx.getBaseSize(); } return size; @@ -261,28 +254,29 @@ CompactBlock.prototype.getSize = function getSize(witness) { */ CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) { - this.writeAbbr(bw); + this.writeHead(bw); bw.writeBytes(this.keyNonce); bw.writeVarint(this.ids.length); - for (let id of this.ids) { - let lo = id % 0x100000000; - let hi = (id - lo) / 0x100000000; - hi &= 0xffff; + for (const id of this.ids) { + const lo = id % 0x100000000; + const hi = (id - lo) / 0x100000000; + assert(hi <= 0xffff); bw.writeU32(lo); bw.writeU16(hi); } bw.writeVarint(this.ptx.length); - for (let ptx of this.ptx) { - bw.writeVarint(ptx.index); + for (const [index, tx] of this.ptx) { + bw.writeVarint(index); + if (witness) - ptx.tx.toWriter(bw); + tx.toWriter(bw); else - ptx.tx.toNormalWriter(bw); + tx.toNormalWriter(bw); } return bw; @@ -306,26 +300,24 @@ CompactBlock.prototype.toRequest = function toRequest() { */ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) { - let have = {}; - if (this.count === this.totalTX) return true; - for (let entry of mempool.map.values()) { - let tx = entry.tx; + const set = new Set(); + + for (const {tx} of mempool.map.values()) { let hash = tx.hash(); - let id, index; if (witness) hash = tx.witnessHash(); - id = this.sid(hash); - index = this.idMap.get(id); + const id = this.sid(hash); + const index = this.idMap.get(id); if (index == null) continue; - if (have[index]) { + if (set.has(index)) { // Siphash collision, just request it. this.available[index] = null; this.count--; @@ -333,7 +325,7 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) { } this.available[index] = tx; - have[index] = true; + set.add(index); this.count++; // We actually may have a siphash collision @@ -374,12 +366,10 @@ CompactBlock.prototype.fillMissing = function fillMissing(res) { */ CompactBlock.prototype.sid = function sid(hash) { - let hi, lo; - if (typeof hash === 'string') hash = Buffer.from(hash, 'hex'); - [hi, lo] = siphash256(hash, this.sipKey); + const [hi, lo] = siphash256(hash, this.sipKey); return (hi & 0xffff) * 0x100000000 + (lo >>> 0); }; @@ -397,12 +387,13 @@ CompactBlock.prototype.hasIndex = function hasIndex(index) { /** * Initialize the siphash key. * @private + * @returns {Buffer} */ -CompactBlock.prototype.initKey = function initKey() { - let data = Buffer.concat([this.abbr(), this.keyNonce]); - let hash = digest.sha256(data); - this.sipKey = hash.slice(0, 16); +CompactBlock.prototype.getKey = function getKey() { + const data = Buffer.concat([this.toHead(), this.keyNonce]); + const hash = digest.sha256(data); + return hash.slice(0, 16); }; /** @@ -411,47 +402,46 @@ CompactBlock.prototype.initKey = function initKey() { */ CompactBlock.prototype.init = function init() { - let last = -1; - let offset = 0; - if (this.totalTX === 0) throw new Error('Empty vectors.'); if (this.totalTX > consensus.MAX_BLOCK_SIZE / 10) throw new Error('Compact block too big.'); + // Custom limit to avoid a hashdos. + // Min valid tx size: (4 + 1 + 41 + 1 + 9 + 4) = 60 + // Min block header size: 81 + // Max number of transactions: (1000000 - 81) / 60 = 16665 + if (this.totalTX > (consensus.MAX_BLOCK_SIZE - 81) / 60) + throw new Error('Compact block too big.'); + // No sparse arrays here, v8. for (let i = 0; i < this.totalTX; i++) this.available.push(null); + let last = -1; + let offset = 0; + for (let i = 0; i < this.ptx.length; i++) { - let ptx = this.ptx[i]; - assert(ptx); - last += ptx.index + 1; + const [index, tx] = this.ptx[i]; + last += index + 1; assert(last <= 0xffff); assert(last <= this.ids.length + i); - this.available[last] = ptx.tx; + this.available[last] = tx; this.count++; } for (let i = 0; i < this.ids.length; i++) { - let id; + const id = this.ids[i]; while (this.available[i + offset]) offset++; - id = this.ids[i]; - - // Fails on siphash collision + // Fails on siphash collision. if (this.idMap.has(id)) return false; this.idMap.set(id, i + offset); - - // We're supposed to fail here if there's - // more than 12 hash collisions, but we - // don't have lowlevel access to our hash - // table. Hopefully we don't get hashdos'd. } return true; @@ -464,18 +454,18 @@ CompactBlock.prototype.init = function init() { */ CompactBlock.prototype.toBlock = function toBlock() { - let block = new Block(); + const block = new Block(); block.version = this.version; block.prevBlock = this.prevBlock; block.merkleRoot = this.merkleRoot; - block.ts = this.ts; + block.time = this.time; block.bits = this.bits; block.nonce = this.nonce; block._hash = this._hash; block._hhash = this._hhash; - for (let tx of this.available) { + for (const tx of this.available) { assert(tx, 'Compact block is not full.'); block.txs.push(tx); } @@ -496,7 +486,7 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) { this.version = block.version; this.prevBlock = block.prevBlock; this.merkleRoot = block.merkleRoot; - this.ts = block.ts; + this.time = block.time; this.bits = block.bits; this.nonce = block.nonce; this.totalTX = block.txs.length; @@ -507,23 +497,21 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) { nonce = util.nonce(); this.keyNonce = nonce; - - this.initKey(); + this.sipKey = this.getKey(); for (let i = 1; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; let hash = tx.hash(); - let id; if (witness) hash = tx.witnessHash(); - id = this.sid(hash); + const id = this.sid(hash); this.ids.push(id); } - this.ptx.push(new PrefilledTX(0, block.txs[0])); + this.ptx.push([0, block.txs[0]]); return this; }; @@ -562,7 +550,7 @@ function TXRequest(options) { if (!(this instanceof TXRequest)) return new TXRequest(options); - this.hash = null; + this.hash = encoding.NULL_HASH; this.indexes = []; if (options) @@ -631,19 +619,18 @@ TXRequest.fromCompact = function fromCompact(block) { */ TXRequest.prototype.fromReader = function fromReader(br) { - let offset = 0; - let count; - this.hash = br.readHash('hex'); - count = br.readVarint(); + const count = br.readVarint(); for (let i = 0; i < count; i++) { - let index = br.readVarint(); + const index = br.readVarint(); assert(index <= 0xffff); this.indexes.push(index); } + let offset = 0; + for (let i = 0; i < count; i++) { let index = this.indexes[i]; index += offset; @@ -698,7 +685,11 @@ TXRequest.prototype.getSize = function getSize() { size += encoding.sizeVarint(this.indexes.length); for (let i = 0; i < this.indexes.length; i++) { - let index = this.indexes[i] - (i === 0 ? 0 : this.indexes[i - 1] + 1); + let index = this.indexes[i]; + + if (i > 0) + index -= this.indexes[i - 1] + 1; + size += encoding.sizeVarint(index); } @@ -716,7 +707,11 @@ TXRequest.prototype.toWriter = function toWriter(bw) { bw.writeVarint(this.indexes.length); for (let i = 0; i < this.indexes.length; i++) { - let index = this.indexes[i] - (i === 0 ? 0 : this.indexes[i - 1] + 1); + let index = this.indexes[i]; + + if (i > 0) + index -= this.indexes[i - 1] + 1; + bw.writeVarint(index); } @@ -729,7 +724,8 @@ TXRequest.prototype.toWriter = function toWriter(bw) { */ TXRequest.prototype.toRaw = function toRaw() { - return this.toWriter(new BufferWriter()).render(); + const size = this.getSize(); + return this.toWriter(new StaticWriter(size)).render(); }; /** @@ -745,7 +741,7 @@ function TXResponse(options) { if (!(this instanceof TXResponse)) return new TXResponse(options); - this.hash = null; + this.hash = encoding.NULL_HASH; this.txs = []; if (options) @@ -786,11 +782,9 @@ TXResponse.fromOptions = function fromOptions(options) { */ TXResponse.prototype.fromReader = function fromReader(br) { - let count; - this.hash = br.readHash('hex'); - count = br.readVarint(); + const count = br.readVarint(); for (let i = 0; i < count; i++) this.txs.push(TX.fromReader(br)); @@ -839,7 +833,7 @@ TXResponse.fromRaw = function fromRaw(data) { TXResponse.prototype.fromBlock = function fromBlock(block, req) { this.hash = req.hash; - for (let index of req.indexes) { + for (const index of req.indexes) { if (index >= block.txs.length) break; @@ -908,7 +902,7 @@ TXResponse.prototype.getSize = function getSize(witness) { size += 32; size += encoding.sizeVarint(this.txs.length); - for (let tx of this.txs) { + for (const tx of this.txs) { if (witness) size += tx.getSize(); else @@ -930,7 +924,7 @@ TXResponse.prototype.writeRaw = function writeRaw(bw, witness) { bw.writeVarint(this.txs.length); - for (let tx of this.txs) { + for (const tx of this.txs) { if (witness) tx.toWriter(bw); else @@ -948,24 +942,10 @@ TXResponse.prototype.writeRaw = function writeRaw(bw, witness) { */ TXResponse.prototype.frameRaw = function frameRaw(witness) { - let size = this.getSize(witness); + const size = this.getSize(witness); return this.writeRaw(new StaticWriter(size), witness).render(); }; -/** - * Represents a prefilled TX. - * @constructor - * @param {Number} index - * @param {TX} tx - * @property {Number} index - * @property {TX} tx - */ - -function PrefilledTX(index, tx) { - this.index = index; - this.tx = tx; -} - /* * Expose */ diff --git a/lib/net/dns.js b/lib/net/dns.js index b6a8f64a8..e2310d42e 100644 --- a/lib/net/dns.js +++ b/lib/net/dns.js @@ -20,7 +20,7 @@ const options = { }; /** - * Resolve host (no getaddrinfo). + * Resolve host (async w/ libcares). * @param {String} host * @param {String?} proxy - Tor socks proxy. * @returns {Promise} @@ -59,8 +59,6 @@ exports.lookup = function lookup(host, proxy) { return socks.resolve(proxy, host); return new Promise((resolve, reject) => { - let addrs = []; - dns.lookup(host, options, to((err, result) => { if (err) { reject(err); @@ -72,7 +70,9 @@ exports.lookup = function lookup(host, proxy) { return; } - for (let addr of result) + const addrs = []; + + for (const addr of result) addrs.push(addr.address); resolve(addrs); @@ -85,7 +85,7 @@ exports.lookup = function lookup(host, proxy) { */ function to(callback) { - let timeout = setTimeout(() => { + const timeout = setTimeout(() => { callback(new Error('DNS request timed out.')); callback = null; }, 5000); diff --git a/lib/net/external.js b/lib/net/external.js index 82b59276a..b455e5cb1 100644 --- a/lib/net/external.js +++ b/lib/net/external.js @@ -22,32 +22,24 @@ const external = exports; */ external.getIPv4 = async function getIPv4() { - let res, ip; - try { - res = await request({ + const res = await request({ method: 'GET', uri: 'http://ipv4.icanhazip.com', expect: 'txt', timeout: 2000 }); - } catch (e) { - return await external.getIPv42(); - } - try { - ip = res.body.trim(); - ip = IP.toBuffer(ip); + const str = res.body.trim(); + const raw = IP.toBuffer(str); - if (!IP.isIPv4(ip)) + if (!IP.isIPv4(raw)) throw new Error('Could not find IPv4.'); - ip = IP.toString(ip); + return IP.toString(raw); } catch (e) { return await external.getIPv42(); } - - return ip; }; /** @@ -58,22 +50,20 @@ external.getIPv4 = async function getIPv4() { */ external.getIPv42 = async function getIPv42() { - let res, match, ip, raw; - - res = await request({ + const res = await request({ method: 'GET', uri: 'http://checkip.dyndns.org', expect: 'html', timeout: 2000 }); - match = /IP Address:\s*([0-9a-f.:]+)/i.exec(res.body); + const match = /IP Address:\s*([0-9a-f.:]+)/i.exec(res.body); if (!match) throw new Error('Could not find IPv4.'); - ip = match[1]; - raw = IP.toBuffer(ip); + const str = match[1]; + const raw = IP.toBuffer(str); if (!IP.isIPv4(raw)) throw new Error('Could not find IPv4.'); @@ -88,20 +78,18 @@ external.getIPv42 = async function getIPv42() { */ external.getIPv6 = async function getIPv6() { - let res, ip; - - res = await request({ + const res = await request({ method: 'GET', uri: 'http://ipv6.icanhazip.com', expect: 'txt', timeout: 2000 }); - ip = res.body.trim(); - ip = IP.toBuffer(ip); + const str = res.body.trim(); + const raw = IP.toBuffer(str); - if (!IP.isIPv6(ip)) + if (!IP.isIPv6(raw)) throw new Error('Could not find IPv6.'); - return IP.toString(ip); + return IP.toString(raw); }; diff --git a/lib/net/framer.js b/lib/net/framer.js index d17743322..7a568f72d 100644 --- a/lib/net/framer.js +++ b/lib/net/framer.js @@ -29,40 +29,38 @@ function Framer(network) { * Frame a payload with a header. * @param {String} cmd - Packet type. * @param {Buffer} payload + * @param {Buffer?} checksum - Precomputed checksum. * @returns {Buffer} Payload with header prepended. */ -Framer.prototype.packet = function _packet(cmd, payload, checksum) { - let packet; - +Framer.prototype.packet = function packet(cmd, payload, checksum) { assert(payload, 'No payload.'); - assert(cmd.length < 12); assert(payload.length <= 0xffffffff); - packet = Buffer.allocUnsafe(24 + payload.length); + const msg = Buffer.allocUnsafe(24 + payload.length); // Magic value - packet.writeUInt32LE(this.network.magic, 0, true); + msg.writeUInt32LE(this.network.magic, 0, true); // Command - packet.write(cmd, 4, 'ascii'); + msg.write(cmd, 4, 'ascii'); for (let i = 4 + cmd.length; i < 16; i++) - packet[i] = 0; + msg[i] = 0; // Payload length - packet.writeUInt32LE(payload.length, 16, true); + msg.writeUInt32LE(payload.length, 16, true); if (!checksum) checksum = digest.hash256(payload); // Checksum - checksum.copy(packet, 20, 0, 4); + checksum.copy(msg, 20, 0, 4); - payload.copy(packet, 24); + payload.copy(msg, 24); - return packet; + return msg; }; /* diff --git a/lib/net/hostlist.js b/lib/net/hostlist.js index 075c23a52..3f0b8d502 100644 --- a/lib/net/hostlist.js +++ b/lib/net/hostlist.js @@ -133,11 +133,11 @@ HostList.scores = { * @private */ -HostList.prototype._init = function init() { - let options = this.options; - let scores = HostList.scores; - let hosts = IP.getPublic(); - let port = this.address.port; +HostList.prototype._init = function _init() { + const options = this.options; + const scores = HostList.scores; + const hosts = IP.getPublic(); + const port = this.address.port; for (let i = 0; i < this.options.maxBuckets; i++) this.fresh.push(new Map()); @@ -151,7 +151,7 @@ HostList.prototype._init = function init() { this.pushLocal(this.address, scores.MANUAL); this.addLocal(options.host, options.port, scores.BIND); - for (let host of hosts) + for (const host of hosts) this.addLocal(host, port, scores.IF); }; @@ -227,10 +227,10 @@ HostList.prototype.stop = function stop() { */ HostList.prototype.injectSeeds = function injectSeeds() { - let nodes = seeds.get(this.network.type); + const nodes = seeds.get(this.network.type); - for (let node of nodes) { - let addr = NetAddress.fromHostname(node, this.network); + for (const node of nodes) { + const addr = NetAddress.fromHostname(node, this.network); if (!addr.isRoutable()) continue; @@ -252,8 +252,7 @@ HostList.prototype.injectSeeds = function injectSeeds() { */ HostList.prototype.loadFile = async function loadFile() { - let filename = this.options.filename; - let data, json; + const filename = this.options.filename; if (fs.unsupported) return; @@ -264,6 +263,7 @@ HostList.prototype.loadFile = async function loadFile() { if (!filename) return; + let data; try { data = await fs.readFile(filename, 'utf8'); } catch (e) { @@ -272,7 +272,7 @@ HostList.prototype.loadFile = async function loadFile() { throw e; } - json = JSON.parse(data); + const json = JSON.parse(data); this.fromJSON(json); }; @@ -284,8 +284,7 @@ HostList.prototype.loadFile = async function loadFile() { */ HostList.prototype.flush = async function flush() { - let filename = this.options.filename; - let json, data; + const filename = this.options.filename; if (fs.unsupported) return; @@ -303,8 +302,8 @@ HostList.prototype.flush = async function flush() { this.logger.debug('Writing hosts to %s.', filename); - json = this.toJSON(); - data = JSON.stringify(json); + const json = this.toJSON(); + const data = JSON.stringify(json); try { await fs.writeFile(filename, data, 'utf8'); @@ -329,7 +328,7 @@ HostList.prototype.size = function size() { */ HostList.prototype.isFull = function isFull() { - let max = this.options.maxBuckets * this.options.maxEntries; + const max = this.options.maxBuckets * this.options.maxEntries; return this.size() >= max; }; @@ -340,10 +339,10 @@ HostList.prototype.isFull = function isFull() { HostList.prototype.reset = function reset() { this.map.clear(); - for (let bucket of this.fresh) + for (const bucket of this.fresh) bucket.clear(); - for (let bucket of this.used) + for (const bucket of this.used) bucket.reset(); this.totalFresh = 0; @@ -385,7 +384,7 @@ HostList.prototype.clearBanned = function clearBanned() { */ HostList.prototype.isBanned = function isBanned(host) { - let time = this.banned.get(host); + const time = this.banned.get(host); if (time == null) return false; @@ -404,9 +403,7 @@ HostList.prototype.isBanned = function isBanned(host) { */ HostList.prototype.getHost = function getHost() { - let now = this.network.now(); let buckets = null; - let factor = 1; if (this.totalFresh > 0) buckets = this.fresh; @@ -417,18 +414,21 @@ HostList.prototype.getHost = function getHost() { } if (!buckets) - return; + return null; + + const now = this.network.now(); + let factor = 1; for (;;) { let index = util.random(0, buckets.length); - let bucket = buckets[index]; - let entry, num; + const bucket = buckets[index]; if (bucket.size === 0) continue; index = util.random(0, bucket.size); + let entry; if (buckets === this.used) { entry = bucket.head; while (index--) @@ -441,7 +441,7 @@ HostList.prototype.getHost = function getHost() { } } - num = util.random(0, 1 << 30); + const num = util.random(0, 1 << 30); if (num < factor * entry.chance(now) * (1 << 30)) return entry; @@ -458,11 +458,11 @@ HostList.prototype.getHost = function getHost() { */ HostList.prototype.freshBucket = function freshBucket(entry) { - let addr = entry.addr; - let src = entry.src; - let data = concat32(addr.raw, src.raw); - let hash = murmur3(data, 0xfba4c795); - let index = hash % this.fresh.length; + const addr = entry.addr; + const src = entry.src; + const data = concat32(addr.raw, src.raw); + const hash = murmur3(data, 0xfba4c795); + const index = hash % this.fresh.length; return this.fresh[index]; }; @@ -474,9 +474,9 @@ HostList.prototype.freshBucket = function freshBucket(entry) { */ HostList.prototype.usedBucket = function usedBucket(entry) { - let addr = entry.addr; - let hash = murmur3(addr.raw, 0xfba4c795); - let index = hash % this.used.length; + const addr = entry.addr; + const hash = murmur3(addr.raw, 0xfba4c795); + const index = hash % this.used.length; return this.used[index]; }; @@ -488,17 +488,15 @@ HostList.prototype.usedBucket = function usedBucket(entry) { */ HostList.prototype.add = function add(addr, src) { - let now = this.network.now(); - let penalty = 2 * 60 * 60; - let interval = 24 * 60 * 60; - let factor = 1; - let entry, bucket; - assert(addr.port !== 0); - entry = this.map.get(addr.hostname); + let entry = this.map.get(addr.hostname); if (entry) { + const now = this.network.now(); + let penalty = 2 * 60 * 60; + let interval = 24 * 60 * 60; + // No source means we're inserting // this ourselves. No penalty. if (!src) @@ -509,18 +507,18 @@ HostList.prototype.add = function add(addr, src) { entry.addr.services >>>= 0; // Online? - if (now - addr.ts < 24 * 60 * 60) + if (now - addr.time < 24 * 60 * 60) interval = 60 * 60; // Periodically update time. - if (entry.addr.ts < addr.ts - interval - penalty) { - entry.addr.ts = addr.ts; + if (entry.addr.time < addr.time - interval - penalty) { + entry.addr.time = addr.time; this.needsFlush = true; } // Do not update if no new // information is present. - if (entry.addr.ts && addr.ts <= entry.addr.ts) + if (entry.addr.time && addr.time <= entry.addr.time) return false; // Do not update if the entry was @@ -539,6 +537,7 @@ HostList.prototype.add = function add(addr, src) { // Stochastic test: previous refCount // N: 2^N times harder to increase it. + let factor = 1; for (let i = 0; i < entry.refCount; i++) factor *= 2; @@ -556,7 +555,7 @@ HostList.prototype.add = function add(addr, src) { this.totalFresh++; } - bucket = this.freshBucket(entry); + const bucket = this.freshBucket(entry); if (bucket.has(entry.key())) return false; @@ -579,9 +578,9 @@ HostList.prototype.add = function add(addr, src) { */ HostList.prototype.evictFresh = function evictFresh(bucket) { - let old; + let old = null; - for (let entry of bucket.values()) { + for (const entry of bucket.values()) { if (this.isStale(entry)) { bucket.delete(entry.key()); @@ -598,7 +597,7 @@ HostList.prototype.evictFresh = function evictFresh(bucket) { continue; } - if (entry.addr.ts < old.addr.ts) + if (entry.addr.time < old.addr.time) old = entry; } @@ -620,18 +619,18 @@ HostList.prototype.evictFresh = function evictFresh(bucket) { */ HostList.prototype.isStale = function isStale(entry) { - let now = this.network.now(); + const now = this.network.now(); if (entry.lastAttempt && entry.lastAttempt >= now - 60) return false; - if (entry.addr.ts > now + 10 * 60) + if (entry.addr.time > now + 10 * 60) return true; - if (entry.addr.ts === 0) + if (entry.addr.time === 0) return true; - if (now - entry.addr.ts > HostList.HORIZON_DAYS * 24 * 60 * 60) + if (now - entry.addr.time > HostList.HORIZON_DAYS * 24 * 60 * 60) return true; if (entry.lastSuccess === 0 && entry.attempts >= HostList.RETRIES) @@ -652,10 +651,10 @@ HostList.prototype.isStale = function isStale(entry) { */ HostList.prototype.remove = function remove(hostname) { - let entry = this.map.get(hostname); + const entry = this.map.get(hostname); if (!entry) - return; + return null; if (entry.used) { let head = entry; @@ -665,7 +664,7 @@ HostList.prototype.remove = function remove(hostname) { while (head.prev) head = head.prev; - for (let bucket of this.used) { + for (const bucket of this.used) { if (bucket.head === head) { bucket.remove(entry); this.totalUsed--; @@ -676,7 +675,7 @@ HostList.prototype.remove = function remove(hostname) { assert(!head); } else { - for (let bucket of this.fresh) { + for (const bucket of this.fresh) { if (bucket.delete(entry.key())) entry.refCount--; } @@ -696,8 +695,8 @@ HostList.prototype.remove = function remove(hostname) { */ HostList.prototype.markAttempt = function markAttempt(hostname) { - let entry = this.map.get(hostname); - let now = this.network.now(); + const entry = this.map.get(hostname); + const now = this.network.now(); if (!entry) return; @@ -712,14 +711,14 @@ HostList.prototype.markAttempt = function markAttempt(hostname) { */ HostList.prototype.markSuccess = function markSuccess(hostname) { - let entry = this.map.get(hostname); - let now = this.network.now(); + const entry = this.map.get(hostname); + const now = this.network.now(); if (!entry) return; - if (now - entry.addr.ts > 20 * 60) - entry.addr.ts = now; + if (now - entry.addr.time > 20 * 60) + entry.addr.time = now; }; /** @@ -729,13 +728,13 @@ HostList.prototype.markSuccess = function markSuccess(hostname) { */ HostList.prototype.markAck = function markAck(hostname, services) { - let entry = this.map.get(hostname); - let now = this.network.now(); - let bucket, evicted, old, fresh; + const entry = this.map.get(hostname); if (!entry) return; + const now = this.network.now(); + entry.addr.services |= services; entry.addr.services >>>= 0; @@ -749,7 +748,8 @@ HostList.prototype.markAck = function markAck(hostname, services) { assert(entry.refCount > 0); // Remove from fresh. - for (let bucket of this.fresh) { + let old; + for (const bucket of this.fresh) { if (bucket.delete(entry.key())) { entry.refCount--; old = bucket; @@ -761,7 +761,7 @@ HostList.prototype.markAck = function markAck(hostname, services) { this.totalFresh--; // Find room in used bucket. - bucket = this.usedBucket(entry); + const bucket = this.usedBucket(entry); if (bucket.size < this.options.maxEntries) { entry.used = true; @@ -771,8 +771,8 @@ HostList.prototype.markAck = function markAck(hostname, services) { } // No room. Evict. - evicted = this.evictUsed(bucket); - fresh = this.freshBucket(evicted); + const evicted = this.evictUsed(bucket); + let fresh = this.freshBucket(evicted); // Move to entry's old bucket if no room. if (fresh.size >= this.options.maxEntries) @@ -799,7 +799,7 @@ HostList.prototype.evictUsed = function evictUsed(bucket) { let old = bucket.head; for (let entry = bucket.head; entry; entry = entry.next) { - if (entry.addr.ts < old.addr.ts) + if (entry.addr.time < old.addr.time) old = entry; } @@ -812,12 +812,12 @@ HostList.prototype.evictUsed = function evictUsed(bucket) { */ HostList.prototype.toArray = function toArray() { - let out = []; + const out = []; - for (let entry of this.map.values()) + for (const entry of this.map.values()) out.push(entry.addr); - assert.equal(out.length, this.size()); + assert.strictEqual(out.length, this.size()); return out; }; @@ -828,15 +828,15 @@ HostList.prototype.toArray = function toArray() { */ HostList.prototype.addSeed = function addSeed(host) { - let addr = IP.fromHostname(host, this.network.port); + const ip = IP.fromHostname(host, this.network.port); - if (addr.type === IP.types.DNS) { + if (ip.type === IP.types.DNS) { // Defer for resolution. - this.dnsSeeds.push(addr); - return; + this.dnsSeeds.push(ip); + return null; } - addr = NetAddress.fromHost(addr.host, addr.port, this.network); + const addr = NetAddress.fromHost(ip.host, ip.port, this.network); this.add(addr); @@ -850,15 +850,15 @@ HostList.prototype.addSeed = function addSeed(host) { */ HostList.prototype.addNode = function addNode(host) { - let addr = IP.fromHostname(host, this.network.port); + const ip = IP.fromHostname(host, this.network.port); - if (addr.type === IP.types.DNS) { + if (ip.type === IP.types.DNS) { // Defer for resolution. - this.dnsNodes.push(addr); - return; + this.dnsNodes.push(ip); + return null; } - addr = NetAddress.fromHost(addr.host, addr.port, this.network); + const addr = NetAddress.fromHost(ip.host, ip.port, this.network); this.nodes.push(addr); this.add(addr); @@ -873,10 +873,10 @@ HostList.prototype.addNode = function addNode(host) { */ HostList.prototype.removeNode = function removeNode(host) { - let addr = IP.fromHostname(host, this.network.port); + const addr = IP.fromHostname(host, this.network.port); for (let i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; + const node = this.nodes[i]; if (node.host !== addr.host) continue; @@ -900,7 +900,7 @@ HostList.prototype.removeNode = function removeNode(host) { HostList.prototype.setSeeds = function setSeeds(seeds) { this.dnsSeeds.length = 0; - for (let host of seeds) + for (const host of seeds) this.addSeed(host); }; @@ -913,7 +913,7 @@ HostList.prototype.setNodes = function setNodes(nodes) { this.dnsNodes.length = 0; this.nodes.length = 0; - for (let host of nodes) + for (const host of nodes) this.addNode(host); }; @@ -926,7 +926,7 @@ HostList.prototype.setNodes = function setNodes(nodes) { */ HostList.prototype.addLocal = function addLocal(host, port, score) { - let addr = NetAddress.fromHost(host, port, this.network); + const addr = NetAddress.fromHost(host, port, this.network); addr.services = this.options.services; return this.pushLocal(addr, score); }; @@ -939,15 +939,13 @@ HostList.prototype.addLocal = function addLocal(host, port, score) { */ HostList.prototype.pushLocal = function pushLocal(addr, score) { - let local; - if (!addr.isRoutable()) return false; if (this.local.has(addr.hostname)) return false; - local = new LocalAddress(addr, score); + const local = new LocalAddress(addr, score); this.local.set(addr.hostname, local); @@ -971,8 +969,8 @@ HostList.prototype.getLocal = function getLocal(src) { if (this.local.size === 0) return null; - for (let dest of this.local.values()) { - let reach = src.getReachability(dest.addr); + for (const dest of this.local.values()) { + const reach = src.getReachability(dest.addr); if (reach < bestReach) continue; @@ -984,7 +982,7 @@ HostList.prototype.getLocal = function getLocal(src) { } } - bestDest.ts = this.network.now(); + bestDest.time = this.network.now(); return bestDest; }; @@ -996,7 +994,7 @@ HostList.prototype.getLocal = function getLocal(src) { */ HostList.prototype.markLocal = function markLocal(addr) { - let local = this.local.get(addr.hostname); + const local = this.local.get(addr.hostname); if (!local) return false; @@ -1013,9 +1011,9 @@ HostList.prototype.markLocal = function markLocal(addr) { */ HostList.prototype.discoverSeeds = async function discoverSeeds() { - let jobs = []; + const jobs = []; - for (let seed of this.dnsSeeds) + for (const seed of this.dnsSeeds) jobs.push(this.populateSeed(seed)); await Promise.all(jobs); @@ -1028,9 +1026,9 @@ HostList.prototype.discoverSeeds = async function discoverSeeds() { */ HostList.prototype.discoverNodes = async function discoverNodes() { - let jobs = []; + const jobs = []; - for (let node of this.dnsNodes) + for (const node of this.dnsNodes) jobs.push(this.populateNode(node)); await Promise.all(jobs); @@ -1044,7 +1042,7 @@ HostList.prototype.discoverNodes = async function discoverNodes() { */ HostList.prototype.populateNode = async function populateNode(addr) { - let addrs = await this.populate(addr); + const addrs = await this.populate(addr); if (addrs.length === 0) return; @@ -1061,9 +1059,9 @@ HostList.prototype.populateNode = async function populateNode(addr) { */ HostList.prototype.populateSeed = async function populateSeed(seed) { - let addrs = await this.populate(seed); + const addrs = await this.populate(seed); - for (let addr of addrs) + for (const addr of addrs) this.add(addr); }; @@ -1075,13 +1073,13 @@ HostList.prototype.populateSeed = async function populateSeed(seed) { */ HostList.prototype.populate = async function populate(target) { - let addrs = []; - let hosts; + const addrs = []; assert(target.type === IP.types.DNS, 'Resolved host passed.'); this.logger.info('Resolving host: %s.', target.host); + let hosts; try { hosts = await this.resolve(target.host); } catch (e) { @@ -1089,8 +1087,8 @@ HostList.prototype.populate = async function populate(target) { return addrs; } - for (let host of hosts) { - let addr = NetAddress.fromHost(host, target.port, this.network); + for (const host of hosts) { + const addr = NetAddress.fromHost(host, target.port, this.network); addrs.push(addr); } @@ -1103,22 +1101,22 @@ HostList.prototype.populate = async function populate(target) { */ HostList.prototype.toJSON = function toJSON() { - let addrs = []; - let fresh = []; - let used = []; + const addrs = []; + const fresh = []; + const used = []; - for (let entry of this.map.values()) + for (const entry of this.map.values()) addrs.push(entry.toJSON()); - for (let bucket of this.fresh) { - let keys = []; - for (let key of bucket.keys()) + for (const bucket of this.fresh) { + const keys = []; + for (const key of bucket.keys()) keys.push(key); fresh.push(keys); } - for (let bucket of this.used) { - let keys = []; + for (const bucket of this.used) { + const keys = []; for (let entry = bucket.head; entry; entry = entry.next) keys.push(entry.key()); used.push(keys); @@ -1140,12 +1138,12 @@ HostList.prototype.toJSON = function toJSON() { */ HostList.prototype.fromJSON = function fromJSON(json) { - let sources = {}; - let map = new Map(); + const sources = new Map(); + const map = new Map(); let totalFresh = 0; let totalUsed = 0; - let fresh = []; - let used = []; + const fresh = []; + const used = []; assert(json && typeof json === 'object'); @@ -1154,14 +1152,14 @@ HostList.prototype.fromJSON = function fromJSON(json) { assert(Array.isArray(json.addrs)); - for (let addr of json.addrs) { - let entry = HostEntry.fromJSON(addr, this.network); - let src = sources[entry.src.hostname]; + for (const addr of json.addrs) { + const entry = HostEntry.fromJSON(addr, this.network); + let src = sources.get(entry.src.hostname); // Save some memory. if (!src) { src = entry.src; - sources[src.hostname] = src; + sources.set(src.hostname, src); } entry.src = src; @@ -1173,11 +1171,11 @@ HostList.prototype.fromJSON = function fromJSON(json) { assert(json.fresh.length <= this.options.maxBuckets, 'Buckets mismatch.'); - for (let keys of json.fresh) { - let bucket = new Map(); + for (const keys of json.fresh) { + const bucket = new Map(); - for (let key of keys) { - let entry = map.get(key); + for (const key of keys) { + const entry = map.get(key); assert(entry); if (entry.refCount === 0) totalFresh++; @@ -1198,11 +1196,11 @@ HostList.prototype.fromJSON = function fromJSON(json) { assert(json.used.length <= this.options.maxBuckets, 'Buckets mismatch.'); - for (let keys of json.used) { - let bucket = new List(); + for (const keys of json.used) { + const bucket = new List(); - for (let key of keys) { - let entry = map.get(key); + for (const key of keys) { + const entry = map.get(key); assert(entry); assert(entry.refCount === 0); assert(!entry.used); @@ -1220,7 +1218,7 @@ HostList.prototype.fromJSON = function fromJSON(json) { assert(used.length === this.used.length, 'Buckets mismatch.'); - for (let entry of map.values()) + for (const entry of map.values()) assert(entry.used || entry.refCount > 0); this.map = map; @@ -1311,16 +1309,15 @@ HostEntry.prototype.key = function key() { * @returns {Number} */ -HostEntry.prototype.chance = function _chance(now) { - let attempts = this.attempts; - let chance = 1; +HostEntry.prototype.chance = function chance(now) { + let c = 1; if (now - this.lastAttempt < 60 * 10) - chance *= 0.01; + c *= 0.01; - chance *= Math.pow(0.66, Math.min(attempts, 8)); + c *= Math.pow(0.66, Math.min(this.attempts, 8)); - return chance; + return c; }; /** @@ -1350,7 +1347,7 @@ HostEntry.prototype.toJSON = function toJSON() { addr: this.addr.hostname, src: this.src.hostname, services: this.addr.services.toString(2), - ts: this.addr.ts, + time: this.addr.time, attempts: this.attempts, lastSuccess: this.lastSuccess, lastAttempt: this.lastAttempt @@ -1376,14 +1373,14 @@ HostEntry.prototype.fromJSON = function fromJSON(json, network) { assert(typeof json.services === 'string'); assert(json.services.length > 0); assert(json.services.length <= 32); - this.addr.services = parseInt(json.services, 2); - assert(util.isUInt32(this.addr.services)); + const services = parseInt(json.services, 2); + assert(util.isU32(services)); + this.addr.services = services; } - if (json.ts != null) { - assert(util.isNumber(json.ts)); - assert(json.ts >= 0); - this.addr.ts = json.ts; + if (json.time != null) { + assert(util.isU64(json.time)); + this.addr.time = json.time; } if (json.src != null) { @@ -1392,20 +1389,17 @@ HostEntry.prototype.fromJSON = function fromJSON(json, network) { } if (json.attempts != null) { - assert(util.isNumber(json.attempts)); - assert(json.attempts >= 0); + assert(util.isU64(json.attempts)); this.attempts = json.attempts; } if (json.lastSuccess != null) { - assert(util.isNumber(json.lastSuccess)); - assert(json.lastSuccess >= 0); + assert(util.isU64(json.lastSuccess)); this.lastSuccess = json.lastSuccess; } if (json.lastAttempt != null) { - assert(util.isNumber(json.lastAttempt)); - assert(json.lastAttempt >= 0); + assert(util.isU64(json.lastAttempt)); this.lastAttempt = json.lastAttempt; } @@ -1458,7 +1452,7 @@ function HostListOptions(options) { this.address = new NetAddress(); this.address.services = this.services; - this.address.ts = this.network.now(); + this.address.time = this.network.now(); this.seeds = this.network.seeds; this.nodes = []; @@ -1518,7 +1512,7 @@ HostListOptions.prototype.fromOptions = function fromOptions(options) { if (options.host != null) { assert(typeof options.host === 'string'); - let raw = IP.toBuffer(options.host); + const raw = IP.toBuffer(options.host); this.host = IP.toString(raw); if (IP.isRoutable(raw)) this.address.setHost(this.host); @@ -1583,7 +1577,7 @@ HostListOptions.prototype.fromOptions = function fromOptions(options) { this.flushInterval = options.flushInterval; } - this.address.ts = this.network.now(); + this.address.time = this.network.now(); this.address.services = this.services; return this; @@ -1594,7 +1588,7 @@ HostListOptions.prototype.fromOptions = function fromOptions(options) { */ function concat32(left, right) { - let data = POOL32; + const data = POOL32; left.copy(data, 0); right.copy(data, 32); return data; diff --git a/lib/net/packets.js b/lib/net/packets.js index 2b4922440..c1702512f 100644 --- a/lib/net/packets.js +++ b/lib/net/packets.js @@ -77,7 +77,7 @@ exports.types = { * @default */ -exports.typesByVal = util.revMap(exports.types); +exports.typesByVal = util.reverse(exports.types); /** * Base Packet @@ -140,7 +140,7 @@ Packet.prototype.fromRaw = function fromRaw(data) { * @param {Object?} options * @param {Number} options.version - Protocol version. * @param {Number} options.services - Service bits. - * @param {Number} options.ts - Timestamp of discovery. + * @param {Number} options.time - Timestamp of discovery. * @param {NetAddress} options.local - Our address. * @param {NetAddress} options.remote - Their address. * @param {Buffer} options.nonce @@ -150,7 +150,7 @@ Packet.prototype.fromRaw = function fromRaw(data) { * should be relayed immediately. * @property {Number} version - Protocol version. * @property {Number} services - Service bits. - * @property {Number} ts - Timestamp of discovery. + * @property {Number} time - Timestamp of discovery. * @property {NetAddress} local - Our address. * @property {NetAddress} remote - Their address. * @property {Buffer} nonce @@ -168,7 +168,7 @@ function VersionPacket(options) { this.version = common.PROTOCOL_VERSION; this.services = common.LOCAL_SERVICES; - this.ts = util.now(); + this.time = util.now(); this.remote = new NetAddress(); this.local = new NetAddress(); this.nonce = encoding.ZERO_U64; @@ -180,7 +180,7 @@ function VersionPacket(options) { this.fromOptions(options); } -util.inherits(VersionPacket, Packet); +Object.setPrototypeOf(VersionPacket.prototype, Packet.prototype); VersionPacket.prototype.cmd = 'version'; VersionPacket.prototype.type = exports.types.VERSION; @@ -198,8 +198,8 @@ VersionPacket.prototype.fromOptions = function fromOptions(options) { if (options.services != null) this.services = options.services; - if (options.ts != null) - this.ts = options.ts; + if (options.time != null) + this.time = options.time; if (options.remote) this.remote.fromOptions(options.remote); @@ -254,15 +254,15 @@ VersionPacket.prototype.getSize = function getSize() { */ VersionPacket.prototype.toWriter = function toWriter(bw) { - bw.write32(this.version); + bw.writeI32(this.version); bw.writeU32(this.services); bw.writeU32(0); - bw.write64(this.ts); + bw.writeI64(this.time); this.remote.toWriter(bw, false); this.local.toWriter(bw, false); bw.writeBytes(this.nonce); bw.writeVarString(this.agent, 'ascii'); - bw.write32(this.height); + bw.writeI32(this.height); bw.writeU8(this.noRelay ? 0 : 1); return bw; }; @@ -273,7 +273,7 @@ VersionPacket.prototype.toWriter = function toWriter(bw) { */ VersionPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -284,14 +284,14 @@ VersionPacket.prototype.toRaw = function toRaw() { */ VersionPacket.prototype.fromReader = function fromReader(br) { - this.version = br.read32(); + this.version = br.readI32(); this.services = br.readU32(); // Note: hi service bits // are currently unused. br.readU32(); - this.ts = br.read53(); + this.time = br.readI53(); this.remote.fromReader(br, false); if (br.left() > 0) { @@ -303,7 +303,7 @@ VersionPacket.prototype.fromReader = function fromReader(br) { this.agent = br.readVarString('ascii', 256); if (br.left() > 0) - this.height = br.read32(); + this.height = br.readI32(); if (br.left() > 0) this.noRelay = br.readU8() === 0; @@ -312,7 +312,7 @@ VersionPacket.prototype.fromReader = function fromReader(br) { this.version = 300; assert(this.version >= 0, 'Version is negative.'); - assert(this.ts >= 0, 'Timestamp is negative.'); + assert(this.time >= 0, 'Timestamp is negative.'); // No idea why so many peers do this. if (this.height < 0) @@ -366,7 +366,7 @@ function VerackPacket() { Packet.call(this); } -util.inherits(VerackPacket, Packet); +Object.setPrototypeOf(VerackPacket.prototype, Packet.prototype); VerackPacket.prototype.cmd = 'verack'; VerackPacket.prototype.type = exports.types.VERACK; @@ -410,7 +410,7 @@ function PingPacket(nonce) { this.nonce = nonce || null; } -util.inherits(PingPacket, Packet); +Object.setPrototypeOf(PingPacket.prototype, Packet.prototype); PingPacket.prototype.cmd = 'ping'; PingPacket.prototype.type = exports.types.PING; @@ -430,7 +430,7 @@ PingPacket.prototype.getSize = function getSize() { */ PingPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -506,7 +506,7 @@ function PongPacket(nonce) { this.nonce = nonce || encoding.ZERO_U64; } -util.inherits(PongPacket, Packet); +Object.setPrototypeOf(PongPacket.prototype, Packet.prototype); PongPacket.prototype.cmd = 'pong'; PongPacket.prototype.type = exports.types.PONG; @@ -595,7 +595,7 @@ function GetAddrPacket() { Packet.call(this); } -util.inherits(GetAddrPacket, Packet); +Object.setPrototypeOf(GetAddrPacket.prototype, Packet.prototype); GetAddrPacket.prototype.cmd = 'getaddr'; GetAddrPacket.prototype.type = exports.types.GETADDR; @@ -639,7 +639,7 @@ function AddrPacket(items) { this.items = items || []; } -util.inherits(AddrPacket, Packet); +Object.setPrototypeOf(AddrPacket.prototype, Packet.prototype); AddrPacket.prototype.cmd = 'addr'; AddrPacket.prototype.type = exports.types.ADDR; @@ -664,7 +664,7 @@ AddrPacket.prototype.getSize = function getSize() { AddrPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarint(this.items.length); - for (let item of this.items) + for (const item of this.items) item.toWriter(bw, true); return bw; @@ -676,7 +676,7 @@ AddrPacket.prototype.toWriter = function toWriter(bw) { */ AddrPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -687,8 +687,8 @@ AddrPacket.prototype.toRaw = function toRaw() { */ AddrPacket.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let count = br.readVarint(); + const br = new BufferReader(data); + const count = br.readVarint(); for (let i = 0; i < count; i++) this.items.push(NetAddress.fromReader(br, true)); @@ -735,7 +735,7 @@ function InvPacket(items) { this.items = items || []; } -util.inherits(InvPacket, Packet); +Object.setPrototypeOf(InvPacket.prototype, Packet.prototype); InvPacket.prototype.cmd = 'inv'; InvPacket.prototype.type = exports.types.INV; @@ -762,7 +762,7 @@ InvPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarint(this.items.length); - for (let item of this.items) + for (const item of this.items) item.toWriter(bw); return bw; @@ -774,7 +774,7 @@ InvPacket.prototype.toWriter = function toWriter(bw) { */ InvPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -785,7 +785,7 @@ InvPacket.prototype.toRaw = function toRaw() { */ InvPacket.prototype.fromReader = function fromReader(br) { - let count = br.readVarint(); + const count = br.readVarint(); assert(count <= 50000, 'Inv item count too high.'); @@ -842,7 +842,7 @@ function GetDataPacket(items) { InvPacket.call(this, items); } -util.inherits(GetDataPacket, InvPacket); +Object.setPrototypeOf(GetDataPacket.prototype, InvPacket.prototype); GetDataPacket.prototype.cmd = 'getdata'; GetDataPacket.prototype.type = exports.types.GETDATA; @@ -884,7 +884,7 @@ function NotFoundPacket(items) { InvPacket.call(this, items); } -util.inherits(NotFoundPacket, InvPacket); +Object.setPrototypeOf(NotFoundPacket.prototype, InvPacket.prototype); NotFoundPacket.prototype.cmd = 'notfound'; NotFoundPacket.prototype.type = exports.types.NOTFOUND; @@ -932,7 +932,7 @@ function GetBlocksPacket(locator, stop) { this.stop = stop || null; } -util.inherits(GetBlocksPacket, Packet); +Object.setPrototypeOf(GetBlocksPacket.prototype, Packet.prototype); GetBlocksPacket.prototype.cmd = 'getblocks'; GetBlocksPacket.prototype.type = exports.types.GETBLOCKS; @@ -962,7 +962,7 @@ GetBlocksPacket.prototype.toWriter = function toWriter(bw) { bw.writeU32(this.version); bw.writeVarint(this.locator.length); - for (let hash of this.locator) + for (const hash of this.locator) bw.writeHash(hash); bw.writeHash(this.stop || encoding.ZERO_HASH); @@ -976,7 +976,7 @@ GetBlocksPacket.prototype.toWriter = function toWriter(bw) { */ GetBlocksPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -987,11 +987,9 @@ GetBlocksPacket.prototype.toRaw = function toRaw() { */ GetBlocksPacket.prototype.fromReader = function fromReader(br) { - let count; - this.version = br.readU32(); - count = br.readVarint(); + const count = br.readVarint(); assert(count <= 50000, 'Too many block hashes.'); @@ -1044,7 +1042,7 @@ function GetHeadersPacket(locator, stop) { GetBlocksPacket.call(this, locator, stop); } -util.inherits(GetHeadersPacket, GetBlocksPacket); +Object.setPrototypeOf(GetHeadersPacket.prototype, GetBlocksPacket.prototype); GetHeadersPacket.prototype.cmd = 'getheaders'; GetHeadersPacket.prototype.type = exports.types.GETHEADERS; @@ -1088,7 +1086,7 @@ function HeadersPacket(items) { this.items = items || []; } -util.inherits(HeadersPacket, Packet); +Object.setPrototypeOf(HeadersPacket.prototype, Packet.prototype); HeadersPacket.prototype.cmd = 'headers'; HeadersPacket.prototype.type = exports.types.HEADERS; @@ -1103,7 +1101,7 @@ HeadersPacket.prototype.getSize = function getSize() { size += encoding.sizeVarint(this.items.length); - for (let item of this.items) + for (const item of this.items) size += item.getSize(); return size; @@ -1119,7 +1117,7 @@ HeadersPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarint(this.items.length); - for (let item of this.items) + for (const item of this.items) item.toWriter(bw); return bw; @@ -1131,7 +1129,7 @@ HeadersPacket.prototype.toWriter = function toWriter(bw) { */ HeadersPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -1142,7 +1140,7 @@ HeadersPacket.prototype.toRaw = function toRaw() { */ HeadersPacket.prototype.fromReader = function fromReader(br) { - let count = br.readVarint(); + const count = br.readVarint(); assert(count <= 2000, 'Too many headers.'); @@ -1187,7 +1185,7 @@ function SendHeadersPacket() { Packet.call(this); } -util.inherits(SendHeadersPacket, Packet); +Object.setPrototypeOf(SendHeadersPacket.prototype, Packet.prototype); SendHeadersPacket.prototype.cmd = 'sendheaders'; SendHeadersPacket.prototype.type = exports.types.SENDHEADERS; @@ -1234,7 +1232,7 @@ function BlockPacket(block, witness) { this.witness = witness || false; } -util.inherits(BlockPacket, Packet); +Object.setPrototypeOf(BlockPacket.prototype, Packet.prototype); BlockPacket.prototype.cmd = 'block'; BlockPacket.prototype.type = exports.types.BLOCK; @@ -1336,7 +1334,7 @@ function TXPacket(tx, witness) { this.witness = witness || false; } -util.inherits(TXPacket, Packet); +Object.setPrototypeOf(TXPacket.prototype, Packet.prototype); TXPacket.prototype.cmd = 'tx'; TXPacket.prototype.type = exports.types.TX; @@ -1444,7 +1442,7 @@ function RejectPacket(options) { this.fromOptions(options); } -util.inherits(RejectPacket, Packet); +Object.setPrototypeOf(RejectPacket.prototype, Packet.prototype); /** * Reject codes. Note that `internal` and higher @@ -1474,7 +1472,7 @@ RejectPacket.codes = { * @const {RevMap} */ -RejectPacket.codesByVal = util.revMap(RejectPacket.codes); +RejectPacket.codesByVal = util.reverse(RejectPacket.codes); RejectPacket.prototype.cmd = 'reject'; RejectPacket.prototype.type = exports.types.REJECT; @@ -1535,10 +1533,10 @@ RejectPacket.prototype.rhash = function rhash() { */ RejectPacket.prototype.getCode = function getCode() { - let code = RejectPacket.codesByVal[this.code]; + const code = RejectPacket.codesByVal[this.code]; if (!code) - return this.code + ''; + return this.code.toString(10); return code.toLowerCase(); }; @@ -1586,7 +1584,7 @@ RejectPacket.prototype.toWriter = function toWriter(bw) { */ RejectPacket.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -1709,8 +1707,8 @@ RejectPacket.fromError = function fromError(err, obj) { */ RejectPacket.prototype.inspect = function inspect() { - let code = RejectPacket.codesByVal[this.code] || this.code; - let hash = this.hash ? util.revHex(this.hash) : null; + const code = RejectPacket.codesByVal[this.code] || this.code; + const hash = this.hash ? util.revHex(this.hash) : null; return '= this.waiting) { - let chunk = Buffer.allocUnsafe(this.waiting); + const chunk = Buffer.allocUnsafe(this.waiting); let off = 0; - let len = 0; while (off < chunk.length) { - len = this.pending[0].copy(chunk, off); + const len = this.pending[0].copy(chunk, off); if (len === this.pending[0].length) this.pending.shift(); else @@ -74,7 +75,7 @@ Parser.prototype.feed = function feed(data) { off += len; } - assert.equal(off, chunk.length); + assert.strictEqual(off, chunk.length); this.total -= chunk.length; this.parse(chunk); @@ -87,8 +88,6 @@ Parser.prototype.feed = function feed(data) { */ Parser.prototype.parse = function parse(data) { - let payload, checksum; - assert(data.length <= common.MAX_MESSAGE); if (!this.header) { @@ -96,7 +95,7 @@ Parser.prototype.parse = function parse(data) { return; } - checksum = digest.hash256(data).readUInt32LE(0, true); + const checksum = digest.hash256(data).readUInt32LE(0, true); if (checksum !== this.header.checksum) { this.waiting = 24; @@ -105,6 +104,7 @@ Parser.prototype.parse = function parse(data) { return; } + let payload; try { payload = this.parsePayload(this.header.cmd, data); } catch (e) { @@ -127,26 +127,25 @@ Parser.prototype.parse = function parse(data) { */ Parser.prototype.parseHeader = function parseHeader(data) { - let i, magic, cmd, size, checksum; - - magic = data.readUInt32LE(0, true); + const magic = data.readUInt32LE(0, true); if (magic !== this.network.magic) { this.error('Invalid magic value: %s.', util.hex32(magic)); return null; } - // Count length of the cmd - for (i = 0; data[i + 4] !== 0 && i < 12; i++); + // Count length of the cmd. + let i = 0; + for (; data[i + 4] !== 0 && i < 12; i++); if (i === 12) { this.error('Non NULL-terminated command.'); return null; } - cmd = data.toString('ascii', 4, 4 + i); + const cmd = data.toString('ascii', 4, 4 + i); - size = data.readUInt32LE(16, true); + const size = data.readUInt32LE(16, true); if (size > common.MAX_MESSAGE) { this.waiting = 24; @@ -156,7 +155,7 @@ Parser.prototype.parseHeader = function parseHeader(data) { this.waiting = size; - checksum = data.readUInt32LE(20, true); + const checksum = data.readUInt32LE(20, true); return new Header(cmd, size, checksum); }; diff --git a/lib/net/peer.js b/lib/net/peer.js index e0beb5d16..b9f1fd27b 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -46,7 +46,7 @@ const packetTypes = packets.types; * @property {Boolean} destroyed * @property {Boolean} ack - Whether verack has been received. * @property {Boolean} connected - * @property {Number} ts + * @property {Number} time * @property {Boolean} preferHeaders - Whether the peer has * requested getheaders. * @property {Hash?} hashContinue - The block hash at which to continue @@ -89,7 +89,7 @@ function Peer(options) { this.destroyed = false; this.ack = false; this.handshake = false; - this.ts = 0; + this.time = 0; this.lastSend = 0; this.lastRecv = 0; this.drainSize = 0; @@ -146,7 +146,7 @@ function Peer(options) { this._init(); } -util.inherits(Peer, EventEmitter); +Object.setPrototypeOf(Peer.prototype, EventEmitter.prototype); /** * Max output bytes buffered before @@ -229,7 +229,7 @@ Peer.TIMEOUT_INTERVAL = 20 * 60000; */ Peer.fromInbound = function fromInbound(options, socket) { - let peer = new Peer(options); + const peer = new Peer(options); peer.accept(socket); return peer; }; @@ -242,7 +242,7 @@ Peer.fromInbound = function fromInbound(options, socket) { */ Peer.fromOutbound = function fromOutbound(options, addr) { - let peer = new Peer(options); + const peer = new Peer(options); peer.connect(addr); return peer; }; @@ -262,7 +262,7 @@ Peer.fromOptions = function fromOptions(options) { * @private */ -Peer.prototype._init = function init() { +Peer.prototype._init = function _init() { this.parser.on('packet', async (packet) => { try { await this.readPacket(packet); @@ -341,7 +341,7 @@ Peer.prototype.setCipher = function setCipher(cipher) { }); this.bip151.on('packet', (cmd, body) => { - let payload; + let payload = null; try { payload = this.parser.parsePayload(cmd, body); } catch (e) { @@ -359,9 +359,9 @@ Peer.prototype.setCipher = function setCipher(cipher) { */ Peer.prototype.setAuth = function setAuth(db, key) { - let bip151 = this.bip151; - let hostname = this.hostname(); - let outbound = this.outbound; + const bip151 = this.bip151; + const hostname = this.hostname(); + const outbound = this.outbound; assert(this.bip151, 'BIP151 not set.'); assert(!this.bip150, 'BIP150 already set.'); @@ -418,7 +418,7 @@ Peer.prototype.accept = function accept(socket) { this.address = NetAddress.fromSocket(socket, this.network); this.address.services = 0; - this.ts = util.ms(); + this.time = util.ms(); this.outbound = false; this.connected = true; @@ -435,11 +435,9 @@ Peer.prototype.accept = function accept(socket) { */ Peer.prototype.connect = function connect(addr) { - let socket; - assert(!this.socket); - socket = this.options.createSocket(addr.port, addr.host); + const socket = this.options.createSocket(addr.port, addr.host); this.address = addr; this.outbound = true; @@ -486,7 +484,7 @@ Peer.prototype.open = async function open() { * @returns {Promise} */ -Peer.prototype._open = async function open() { +Peer.prototype._open = async function _open() { this.opened = true; // Connect to peer. @@ -513,25 +511,26 @@ Peer.prototype._open = async function open() { Peer.prototype.initConnect = function initConnect() { if (this.connected) { assert(!this.outbound); - return; + return Promise.resolve(); } return new Promise((resolve, reject) => { - let cleanup = () => { + const cleanup = () => { if (this.connectTimeout != null) { clearTimeout(this.connectTimeout); this.connectTimeout = null; } + // eslint-disable-next-line no-use-before-define this.socket.removeListener('error', onError); }; - let onError = (err) => { + const onError = (err) => { cleanup(); reject(err); }; this.socket.once('connect', () => { - this.ts = util.ms(); + this.time = util.ms(); this.connected = true; this.emit('connect'); @@ -705,8 +704,6 @@ Peer.prototype.finalize = async function finalize() { */ Peer.prototype.announceBlock = function announceBlock(blocks) { - let inv = []; - if (!this.handshake) return; @@ -716,7 +713,9 @@ Peer.prototype.announceBlock = function announceBlock(blocks) { if (!Array.isArray(blocks)) blocks = [blocks]; - for (let block of blocks) { + const inv = []; + + for (const block of blocks) { assert(block instanceof Block); // Don't send if they already have it. @@ -755,8 +754,6 @@ Peer.prototype.announceBlock = function announceBlock(blocks) { */ Peer.prototype.announceTX = function announceTX(txs) { - let inv = []; - if (!this.handshake) return; @@ -771,7 +768,9 @@ Peer.prototype.announceTX = function announceTX(txs) { if (!Array.isArray(txs)) txs = [txs]; - for (let tx of txs) { + const inv = []; + + for (const tx of txs) { assert(tx instanceof TX); // Don't send if they already have it. @@ -787,8 +786,8 @@ Peer.prototype.announceTX = function announceTX(txs) { // Check the fee filter. if (this.feeRate !== -1) { - let hash = tx.hash('hex'); - let rate = this.options.getRate(hash); + const hash = tx.hash('hex'); + const rate = this.options.getRate(hash); if (rate !== -1 && rate < this.feeRate) continue; } @@ -805,8 +804,6 @@ Peer.prototype.announceTX = function announceTX(txs) { */ Peer.prototype.queueInv = function queueInv(items) { - let hasBlock = false; - if (!this.handshake) return; @@ -816,7 +813,9 @@ Peer.prototype.queueInv = function queueInv(items) { if (!Array.isArray(items)) items = [items]; - for (let item of items) { + let hasBlock = false; + + for (const item of items) { if (item.type === invTypes.BLOCK) hasBlock = true; this.invQueue.push(item); @@ -832,21 +831,22 @@ Peer.prototype.queueInv = function queueInv(items) { */ Peer.prototype.flushInv = function flushInv() { - let queue = this.invQueue.slice(); - let items = []; - if (this.destroyed) return; + const queue = this.invQueue; + if (queue.length === 0) return; - this.invQueue.length = 0; + this.invQueue = []; this.logger.spam('Serving %d inv items to %s.', queue.length, this.hostname()); - for (let item of queue) { + const items = []; + + for (const item of queue) { if (!this.invFilter.added(item.hash, 'hex')) continue; @@ -854,7 +854,7 @@ Peer.prototype.flushInv = function flushInv() { } for (let i = 0; i < items.length; i += 1000) { - let chunk = items.slice(i, i + 1000); + const chunk = items.slice(i, i + 1000); this.send(new packets.InvPacket(chunk)); } }; @@ -874,7 +874,7 @@ Peer.prototype.sendInv = function sendInv(items) { if (!Array.isArray(items)) items = [items]; - for (let item of items) + for (const item of items) this.invFilter.add(item.hash, 'hex'); if (items.length === 0) @@ -884,7 +884,7 @@ Peer.prototype.sendInv = function sendInv(items) { items.length, this.hostname()); for (let i = 0; i < items.length; i += 1000) { - let chunk = items.slice(i, i + 1000); + const chunk = items.slice(i, i + 1000); this.send(new packets.InvPacket(chunk)); } }; @@ -904,7 +904,7 @@ Peer.prototype.sendHeaders = function sendHeaders(items) { if (!Array.isArray(items)) items = [items]; - for (let item of items) + for (const item of items) this.invFilter.add(item.hash()); if (items.length === 0) @@ -914,7 +914,7 @@ Peer.prototype.sendHeaders = function sendHeaders(items) { items.length, this.hostname()); for (let i = 0; i < items.length; i += 2000) { - let chunk = items.slice(i, i + 2000); + const chunk = items.slice(i, i + 2000); this.send(new packets.HeadersPacket(chunk)); } }; @@ -927,8 +927,8 @@ Peer.prototype.sendHeaders = function sendHeaders(items) { */ Peer.prototype.sendCompactBlock = function sendCompactBlock(block) { - let witness = this.compactWitness; - let compact = BIP152.CompactBlock.fromBlock(block, witness); + const witness = this.compactWitness; + const compact = BIP152.CompactBlock.fromBlock(block, witness); this.send(new packets.CmpctBlockPacket(compact, witness)); }; @@ -937,10 +937,10 @@ Peer.prototype.sendCompactBlock = function sendCompactBlock(block) { */ Peer.prototype.sendVersion = function sendVersion() { - let packet = new packets.VersionPacket(); + const packet = new packets.VersionPacket(); packet.version = this.options.version; packet.services = this.options.services; - packet.ts = this.network.now(); + packet.time = this.network.now(); packet.remote = this.address; packet.local.setNull(); packet.local.services = this.options.services; @@ -1021,8 +1021,7 @@ Peer.prototype.sendFeeRate = function sendFeeRate(rate) { */ Peer.prototype.destroy = function destroy() { - let connected = this.connected; - let jobs; + const connected = this.connected; if (this.destroyed) return; @@ -1059,15 +1058,15 @@ Peer.prototype.destroy = function destroy() { this.connectTimeout = null; } - jobs = this.drainQueue; + const jobs = this.drainQueue; this.drainSize = 0; this.drainQueue = []; - for (let job of jobs) + for (const job of jobs) job.reject(new Error('Peer was destroyed.')); - for (let [cmd, entry] of this.responseMap) { + for (const [cmd, entry] of this.responseMap) { this.responseMap.delete(cmd); entry.reject(new Error('Peer was destroyed.')); } @@ -1098,15 +1097,14 @@ Peer.prototype.write = function write(data) { */ Peer.prototype.send = function send(packet) { - let checksum; - if (this.destroyed) throw new Error('Peer is destroyed (send).'); // Used cached hashes as the // packet checksum for speed. + let checksum = null; if (packet.type === packetTypes.TX) { - let tx = packet.tx; + const tx = packet.tx; if (packet.witness) { if (!tx.isCoinbase()) checksum = tx.witnessHash(); @@ -1126,7 +1124,7 @@ Peer.prototype.send = function send(packet) { */ Peer.prototype.sendRaw = function sendRaw(cmd, body, checksum) { - let payload = this.framePacket(cmd, body, checksum); + const payload = this.framePacket(cmd, body, checksum); this.write(payload); }; @@ -1153,7 +1151,7 @@ Peer.prototype.drain = function drain() { */ Peer.prototype.handleDrain = function handleDrain() { - let jobs = this.drainQueue; + const jobs = this.drainQueue; this.drainSize = 0; @@ -1162,7 +1160,7 @@ Peer.prototype.handleDrain = function handleDrain() { this.drainQueue = []; - for (let job of jobs) + for (const job of jobs) job.resolve(); }; @@ -1192,7 +1190,7 @@ Peer.prototype.needsDrain = function needsDrain(size) { */ Peer.prototype.addTimeout = function addTimeout(packet) { - let timeout = Peer.RESPONSE_TIMEOUT; + const timeout = Peer.RESPONSE_TIMEOUT; if (!this.outbound) return; @@ -1230,7 +1228,7 @@ Peer.prototype.fulfill = function fulfill(packet) { case packetTypes.MERKLEBLOCK: case packetTypes.TX: case packetTypes.NOTFOUND: { - let entry = this.response(packetTypes.DATA, packet); + const entry = this.response(packetTypes.DATA, packet); assert(!entry || entry.jobs.length === 0); break; } @@ -1245,11 +1243,11 @@ Peer.prototype.fulfill = function fulfill(packet) { */ Peer.prototype.maybeTimeout = function maybeTimeout() { - let now = util.ms(); + const now = util.ms(); - for (let [key, entry] of this.responseMap) { + for (const [key, entry] of this.responseMap) { if (now > entry.timeout) { - let name = packets.typesByVal[key]; + const name = packets.typesByVal[key]; this.error('Peer is stalling (%s).', name.toLowerCase()); this.destroy(); return; @@ -1274,23 +1272,23 @@ Peer.prototype.maybeTimeout = function maybeTimeout() { } if (this.options.isFull() || !this.syncing) { - for (let ts of this.blockMap.values()) { - if (now > ts + Peer.BLOCK_TIMEOUT) { + for (const time of this.blockMap.values()) { + if (now > time + Peer.BLOCK_TIMEOUT) { this.error('Peer is stalling (block).'); this.destroy(); return; } } - for (let ts of this.txMap.values()) { - if (now > ts + Peer.TX_TIMEOUT) { + for (const time of this.txMap.values()) { + if (now > time + Peer.TX_TIMEOUT) { this.error('Peer is stalling (tx).'); this.destroy(); return; } } - for (let block of this.compactBlocks.values()) { + for (const block of this.compactBlocks.values()) { if (now > block.now + Peer.RESPONSE_TIMEOUT) { this.error('Peer is stalling (blocktxn).'); this.destroy(); @@ -1299,10 +1297,8 @@ Peer.prototype.maybeTimeout = function maybeTimeout() { } } - if (now > this.ts + 60000) { - let mult; - - assert(this.ts !== 0); + if (now > this.time + 60000) { + assert(this.time !== 0); if (this.lastRecv === 0 || this.lastSend === 0) { this.error('Peer is stalling (no message).'); @@ -1316,7 +1312,7 @@ Peer.prototype.maybeTimeout = function maybeTimeout() { return; } - mult = this.version <= common.PONG_VERSION ? 4 : 1; + const mult = this.version <= common.PONG_VERSION ? 4 : 1; if (now > this.lastRecv + Peer.TIMEOUT_INTERVAL * mult) { this.error('Peer is stalling (recv).'); @@ -1341,10 +1337,10 @@ Peer.prototype.maybeTimeout = function maybeTimeout() { */ Peer.prototype.request = function request(type, timeout) { - let entry = this.responseMap.get(type); - if (this.destroyed) - return; + return null; + + let entry = this.responseMap.get(type); if (!entry) { entry = new RequestEntry(); @@ -1364,10 +1360,10 @@ Peer.prototype.request = function request(type, timeout) { */ Peer.prototype.response = function response(type, payload) { - let entry = this.responseMap.get(type); + const entry = this.responseMap.get(type); if (!entry) - return; + return null; this.responseMap.delete(type); @@ -1384,14 +1380,12 @@ Peer.prototype.response = function response(type, payload) { Peer.prototype.wait = function wait(type, timeout) { return new Promise((resolve, reject) => { - let entry; - if (this.destroyed) { reject(new Error('Peer is destroyed (request).')); return; } - entry = this.request(type); + const entry = this.request(type); entry.setTimeout(timeout); entry.addJob(resolve, reject); @@ -1405,18 +1399,16 @@ Peer.prototype.wait = function wait(type, timeout) { */ Peer.prototype.error = function error(err) { - let msg; - if (this.destroyed) return; if (typeof err === 'string') { - msg = util.fmt.apply(util, arguments); + const msg = util.fmt.apply(util, arguments); err = new Error(msg); } if (typeof err.code === 'string' && err.code[0] === 'E') { - msg = err.code; + const msg = err.code; err = new Error(msg); err.code = msg; err.message = `Socket Error: ${msg}`; @@ -1477,9 +1469,9 @@ Peer.prototype.getData = function getData(items) { */ Peer.prototype.getItems = function getItems(type, hashes) { - let items = []; + const items = []; - for (let hash of hashes) + for (const hash of hashes) items.push(new InvItem(type, hash)); if (items.length === 0) @@ -1512,10 +1504,10 @@ Peer.prototype.getTX = function getTX(hashes) { */ Peer.prototype.getFullBlock = function getFullBlock(hash) { - let type = invTypes.BLOCK; - assert(!this.options.spv); + let type = invTypes.BLOCK; + if (this.hasWitness()) type |= InvItem.WITNESS_FLAG; @@ -1555,7 +1547,7 @@ Peer.prototype.readPacket = async function readPacket(packet) { break; } default: { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { this.socket.pause(); await this.handlePacket(packet); @@ -1577,8 +1569,6 @@ Peer.prototype.readPacket = async function readPacket(packet) { */ Peer.prototype.handlePacket = async function handlePacket(packet) { - let entry; - if (this.destroyed) throw new Error('Destroyed peer sent a packet.'); @@ -1599,7 +1589,7 @@ Peer.prototype.handlePacket = async function handlePacket(packet) { this.bip150.reject(new Error('Message before BIP150 auth.')); } - entry = this.fulfill(packet); + const entry = this.fulfill(packet); switch (packet.type) { case packetTypes.VERSION: @@ -1757,8 +1747,8 @@ Peer.prototype.handlePing = async function handlePing(packet) { */ Peer.prototype.handlePong = async function handlePong(packet) { - let nonce = packet.nonce; - let now = util.ms(); + const nonce = packet.nonce; + const now = util.ms(); if (!this.challenge) { this.logger.debug('Peer sent an unsolicited pong (%s).', this.hostname()); @@ -1830,7 +1820,7 @@ Peer.prototype.handleFilterLoad = async function handleFilterLoad(packet) { */ Peer.prototype.handleFilterAdd = async function handleFilterAdd(packet) { - let data = packet.data; + const data = packet.data; if (data.length > consensus.MAX_SCRIPT_PUSH) { this.increaseBan(100); @@ -1865,9 +1855,9 @@ Peer.prototype.handleFilterClear = async function handleFilterClear(packet) { */ Peer.prototype.handleFeeFilter = async function handleFeeFilter(packet) { - let rate = packet.rate; + const rate = packet.rate; - if (!(rate >= 0 && rate <= consensus.MAX_MONEY)) { + if (rate < 0 || rate > consensus.MAX_MONEY) { this.increaseBan(100); return; } @@ -1951,12 +1941,10 @@ Peer.prototype.handleEncack = async function handleEncack(packet) { */ Peer.prototype.handleAuthChallenge = async function handleAuthChallenge(packet) { - let sig; - if (!this.bip150) return; - sig = this.bip150.challenge(packet.hash); + const sig = this.bip150.challenge(packet.hash); this.send(new packets.AuthReplyPacket(sig)); }; @@ -1969,12 +1957,10 @@ Peer.prototype.handleAuthChallenge = async function handleAuthChallenge(packet) */ Peer.prototype.handleAuthReply = async function handleAuthReply(packet) { - let hash; - if (!this.bip150) return; - hash = this.bip150.reply(packet.signature); + const hash = this.bip150.reply(packet.signature); if (hash) this.send(new packets.AuthProposePacket(hash)); @@ -1988,12 +1974,10 @@ Peer.prototype.handleAuthReply = async function handleAuthReply(packet) { */ Peer.prototype.handleAuthPropose = async function handleAuthPropose(packet) { - let hash; - if (!this.bip150) return; - hash = this.bip150.propose(packet.hash); + const hash = this.bip150.propose(packet.hash); this.send(new packets.AuthChallengePacket(hash)); }; @@ -2006,13 +1990,13 @@ Peer.prototype.handleAuthPropose = async function handleAuthPropose(packet) { */ Peer.prototype.sendGetHeaders = function sendGetHeaders(locator, stop) { - let packet = new packets.GetHeadersPacket(locator, stop); - let hash = null; - let end = null; + const packet = new packets.GetHeadersPacket(locator, stop); + let hash = null; if (packet.locator.length > 0) hash = util.revHex(packet.locator[0]); + let end = null; if (stop) end = util.revHex(stop); @@ -2033,14 +2017,14 @@ Peer.prototype.sendGetHeaders = function sendGetHeaders(locator, stop) { * @param {Hash?} stop - Hash to stop at. */ -Peer.prototype.sendGetBlocks = function getBlocks(locator, stop) { - let packet = new packets.GetBlocksPacket(locator, stop); - let hash = null; - let end = null; +Peer.prototype.sendGetBlocks = function sendGetBlocks(locator, stop) { + const packet = new packets.GetBlocksPacket(locator, stop); + let hash = null; if (packet.locator.length > 0) hash = util.revHex(packet.locator[0]); + let end = null; if (stop) end = util.revHex(stop); @@ -2086,7 +2070,7 @@ Peer.prototype.sendMempool = function sendMempool() { */ Peer.prototype.sendReject = function sendReject(code, reason, msg, hash) { - let reject = packets.RejectPacket.fromReason(code, reason, msg, hash); + const reject = packets.RejectPacket.fromReason(code, reason, msg, hash); if (msg) { this.logger.debug('Rejecting %s %s (%s): code=%s reason=%s.', @@ -2459,14 +2443,14 @@ RequestEntry.prototype.setTimeout = function setTimeout(timeout) { }; RequestEntry.prototype.reject = function reject(err) { - for (let job of this.jobs) + for (const job of this.jobs) job.reject(err); this.jobs.length = 0; }; RequestEntry.prototype.resolve = function resolve(result) { - for (let job of this.jobs) + for (const job of this.jobs) job.resolve(result); this.jobs.length = 0; diff --git a/lib/net/pool.js b/lib/net/pool.js index e03a6e129..5b8b3fd1c 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -104,7 +104,6 @@ function Pool(options) { this.headerChain = new List(); this.headerNext = null; this.headerTip = null; - this.headerFails = 0; this.peers = new PeerList(); this.authdb = new BIP150.AuthDB(this.options); @@ -120,16 +119,7 @@ function Pool(options) { this._init(); }; -util.inherits(Pool, AsyncObject); - -/** - * Max number of header chain failures - * before disabling checkpoints. - * @const {Number} - * @default - */ - -Pool.MAX_HEADER_FAILS = 1000; +Object.setPrototypeOf(Pool.prototype, AsyncObject.prototype); /** * Discovery interval for UPNP and DNS seeds. @@ -155,7 +145,7 @@ Pool.prototype._init = function _init() { }); this.server.on('listening', () => { - let data = this.server.address(); + const data = this.server.address(); this.logger.info( 'Pool server listening on %s (port=%d).', data.address, data.port); @@ -229,7 +219,7 @@ Pool.prototype._open = async function _open() { this.logger.info('Pool loaded (maxpeers=%d).', this.options.maxOutbound); if (this.options.bip150) { - let key = secp256k1.publicKeyCreate(this.options.identityKey, true); + const key = secp256k1.publicKeyCreate(this.options.identityKey, true); this.logger.info('Identity public key: %s.', key.toString('hex')); this.logger.info('Identity address: %s.', BIP150.address(key)); } @@ -242,20 +232,18 @@ Pool.prototype._open = async function _open() { */ Pool.prototype.resetChain = function resetChain() { - let tip = this.chain.tip; - if (!this.options.checkpoints) return; this.checkpoints = false; - this.chain.checkpoints = false; this.headerTip = null; this.headerChain.reset(); this.headerNext = null; + const tip = this.chain.tip; + if (tip.height < this.network.lastCheckpoint) { this.checkpoints = true; - this.chain.checkpoints = true; this.headerTip = this.getNextTip(tip.height); this.headerChain.push(new HeaderEntry(tip.hash, tip.height)); this.logger.info( @@ -271,7 +259,7 @@ Pool.prototype.resetChain = function resetChain() { * @returns {Promise} */ -Pool.prototype._close = async function close() { +Pool.prototype._close = async function _close() { await this.disconnect(); }; @@ -282,7 +270,7 @@ Pool.prototype._close = async function close() { */ Pool.prototype.connect = async function connect() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._connect(); } finally { @@ -296,7 +284,7 @@ Pool.prototype.connect = async function connect() { * @returns {Promise} */ -Pool.prototype._connect = async function connect() { +Pool.prototype._connect = async function _connect() { assert(this.loaded, 'Pool is not loaded.'); if (this.connected) @@ -325,7 +313,7 @@ Pool.prototype._connect = async function connect() { */ Pool.prototype.disconnect = async function disconnect() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._disconnect(); } finally { @@ -339,7 +327,7 @@ Pool.prototype.disconnect = async function disconnect() { * @returns {Promise} */ -Pool.prototype._disconnect = async function disconnect() { +Pool.prototype._disconnect = async function _disconnect() { assert(this.loaded, 'Pool is not loaded.'); if (!this.connected) @@ -347,7 +335,7 @@ Pool.prototype._disconnect = async function disconnect() { this.disconnecting = true; - for (let item of this.invMap.values()) + for (const item of this.invMap.values()) item.resolve(); this.peers.destroy(); @@ -366,7 +354,6 @@ Pool.prototype._disconnect = async function disconnect() { } this.checkpoints = false; - this.chain.checkpoints = false; this.headerTip = null; this.headerChain.reset(); this.headerNext = null; @@ -458,19 +445,19 @@ Pool.prototype.discover = async function discover() { */ Pool.prototype.discoverGateway = async function discoverGateway() { - let src = this.options.publicPort; - let dest = this.options.port; - let wan, host; + const src = this.options.publicPort; + const dest = this.options.port; // Pointless if we're not listening. if (!this.options.listen) - return; + return false; // UPNP is always optional, since // it's likely to not work anyway. if (!this.options.upnp) - return; + return false; + let wan; try { this.logger.debug('Discovering internet gateway (upnp).'); wan = await UPNP.discover(); @@ -480,6 +467,7 @@ Pool.prototype.discoverGateway = async function discoverGateway() { return false; } + let host; try { host = await wan.getExternalIP(); } catch (e) { @@ -513,13 +501,13 @@ Pool.prototype.discoverGateway = async function discoverGateway() { */ Pool.prototype.discoverSeeds = async function discoverSeeds(checkPeers) { - let max = Math.min(2, this.options.maxOutbound); - let size = this.hosts.size(); - let total = 0; - if (this.hosts.dnsSeeds.length === 0) return; + const max = Math.min(2, this.options.maxOutbound); + const size = this.hosts.size(); + + let total = 0; for (let peer = this.peers.head(); peer; peer = peer.next) { if (!peer.outbound) continue; @@ -550,8 +538,7 @@ Pool.prototype.discoverSeeds = async function discoverSeeds(checkPeers) { */ Pool.prototype.discoverExternal = async function discoverExternal() { - let port = this.options.publicPort; - let host4, host6; + const port = this.options.publicPort; // Pointless if we're not listening. if (!this.options.listen) @@ -566,6 +553,7 @@ Pool.prototype.discoverExternal = async function discoverExternal() { if (this.hosts.local.size > 0) return; + let host4; try { host4 = await external.getIPv4(); } catch (e) { @@ -576,6 +564,7 @@ Pool.prototype.discoverExternal = async function discoverExternal() { if (host4 && this.hosts.addLocal(host4, port, scores.HTTP)) this.logger.info('External IPv4 found (http): %s.', host4); + let host6; try { host6 = await external.getIPv6(); } catch (e) { @@ -594,29 +583,27 @@ Pool.prototype.discoverExternal = async function discoverExternal() { */ Pool.prototype.handleSocket = function handleSocket(socket) { - let host; - if (!socket.remoteAddress) { this.logger.debug('Ignoring disconnected peer.'); socket.destroy(); return; } - host = IP.normalize(socket.remoteAddress); + const ip = IP.normalize(socket.remoteAddress); if (this.peers.inbound >= this.options.maxInbound) { - this.logger.debug('Ignoring peer: too many inbound (%s).', host); + this.logger.debug('Ignoring peer: too many inbound (%s).', ip); socket.destroy(); return; } - if (this.hosts.isBanned(host)) { - this.logger.debug('Ignoring banned peer (%s).', host); + if (this.hosts.isBanned(ip)) { + this.logger.debug('Ignoring banned peer (%s).', ip); socket.destroy(); return; } - host = IP.toHostname(host, socket.remotePort); + const host = IP.toHostname(ip, socket.remotePort); assert(!this.peers.map[host], 'Port collision.'); @@ -630,8 +617,6 @@ Pool.prototype.handleSocket = function handleSocket(socket) { */ Pool.prototype.addLoader = function addLoader() { - let peer, addr; - if (!this.loaded) return; @@ -650,12 +635,12 @@ Pool.prototype.addLoader = function addLoader() { return; } - addr = this.getHost(); + const addr = this.getHost(); if (!addr) return; - peer = this.createOutbound(addr); + const peer = this.createOutbound(addr); this.logger.info('Adding loader peer (%s).', peer.hostname()); @@ -745,7 +730,7 @@ Pool.prototype.stopSync = function stopSync() { peer.merkleMatches = 0; peer.merkleMap = null; peer.blockTime = -1; - peer.blockMap.reset(); + peer.blockMap.clear(); peer.compactBlocks.clear(); } @@ -761,11 +746,10 @@ Pool.prototype.stopSync = function stopSync() { */ Pool.prototype.resync = async function resync(force) { - let locator; - if (!this.syncing) return; + let locator; try { locator = await this.chain.getLocator(); } catch (e) { @@ -822,8 +806,6 @@ Pool.prototype.isSyncable = function isSyncable(peer) { */ Pool.prototype.sendSync = async function sendSync(peer) { - let locator; - if (peer.syncing) return false; @@ -833,6 +815,7 @@ Pool.prototype.sendSync = async function sendSync(peer) { peer.syncing = true; peer.blockTime = util.ms(); + let locator; try { locator = await this.chain.getLocator(); } catch (e) { @@ -901,7 +884,7 @@ Pool.prototype.sendGetAddr = function sendGetAddr() { */ Pool.prototype.resolveHeaders = function resolveHeaders(peer) { - let items = []; + const items = []; for (let node = this.headerNext; node; node = node.next) { this.headerNext = node.next; @@ -946,7 +929,7 @@ Pool.prototype.resolveHeight = function resolveHeight(hash, height) { */ Pool.prototype.getNextTip = function getNextTip(height) { - for (let next of this.network.checkpoints) { + for (const next of this.network.checkpoints) { if (next.height > height) return new HeaderEntry(next.hash, next.height); } @@ -960,10 +943,10 @@ Pool.prototype.getNextTip = function getNextTip(height) { */ Pool.prototype.announceList = function announceList(peer) { - let blocks = []; - let txs = []; + const blocks = []; + const txs = []; - for (let item of this.invMap.values()) { + for (const item of this.invMap.values()) { switch (item.type) { case invTypes.BLOCK: blocks.push(item.msg); @@ -993,17 +976,17 @@ Pool.prototype.announceList = function announceList(peer) { */ Pool.prototype.getBroadcasted = function getBroadcasted(peer, item) { - let type = item.isTX() ? invTypes.TX : invTypes.BLOCK; - let entry = this.invMap.get(item.hash); + const type = item.isTX() ? invTypes.TX : invTypes.BLOCK; + const entry = this.invMap.get(item.hash); if (!entry) - return; + return null; if (type !== entry.type) { this.logger.debug( 'Peer requested item with the wrong type (%s).', peer.hostname()); - return; + return null; } this.logger.debug( @@ -1028,25 +1011,25 @@ Pool.prototype.getBroadcasted = function getBroadcasted(peer, item) { */ Pool.prototype.getItem = async function getItem(peer, item) { - let entry = this.getBroadcasted(peer, item); + const entry = this.getBroadcasted(peer, item); if (entry) return entry; if (this.options.selfish) - return; + return null; if (item.isTX()) { if (!this.mempool) - return; + return null; return this.mempool.getTX(item.hash); } if (this.chain.options.spv) - return; + return null; if (this.chain.options.prune) - return; + return null; return await this.chain.db.getBlock(item.hash); }; @@ -1061,11 +1044,11 @@ Pool.prototype.getItem = async function getItem(peer, item) { */ Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) { - let block = this.getBroadcasted(peer, item); + const broadcasted = this.getBroadcasted(peer, item); // Check for a broadcasted item first. - if (block) { - peer.send(new packets.BlockPacket(block, witness)); + if (broadcasted) { + peer.send(new packets.BlockPacket(broadcasted, witness)); return true; } @@ -1078,7 +1061,7 @@ Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) { // If we have the same serialization, we // can write the raw binary to the socket. if (witness || !this.options.hasWitness()) { - block = await this.chain.db.getRawBlock(item.hash); + const block = await this.chain.db.getRawBlock(item.hash); if (block) { peer.sendRaw('block', block); @@ -1088,7 +1071,7 @@ Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) { return false; } - block = await this.chain.db.getBlock(item.hash); + const block = await this.chain.db.getBlock(item.hash); if (block) { peer.send(new packets.BlockPacket(block, witness)); @@ -1106,9 +1089,9 @@ Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) { */ Pool.prototype.createOutbound = function createOutbound(addr) { - let cipher = BIP151.ciphers.CHACHAPOLY; - let identity = this.options.identityKey; - let peer = Peer.fromOutbound(this.options, addr); + const cipher = BIP151.ciphers.CHACHAPOLY; + const identity = this.options.identityKey; + const peer = Peer.fromOutbound(this.options, addr); this.hosts.markAttempt(addr.hostname); @@ -1135,9 +1118,9 @@ Pool.prototype.createOutbound = function createOutbound(addr) { */ Pool.prototype.createInbound = function createInbound(socket) { - let cipher = BIP151.ciphers.CHACHAPOLY; - let identity = this.options.identityKey; - let peer = Peer.fromInbound(this.options, socket); + const cipher = BIP151.ciphers.CHACHAPOLY; + const identity = this.options.identityKey; + const peer = Peer.fromInbound(this.options, socket); if (this.options.bip151) peer.setCipher(cipher); @@ -1158,7 +1141,7 @@ Pool.prototype.createInbound = function createInbound(socket) { */ Pool.prototype.uid = function uid() { - let MAX = Number.MAX_SAFE_INTEGER; + const MAX = Number.MAX_SAFE_INTEGER; if (this.id >= MAX - this.peers.size() - 1) this.id = 0; @@ -1350,7 +1333,7 @@ Pool.prototype.handleConnect = async function handleConnect(peer) { Pool.prototype.handleOpen = async function handleOpen(peer) { // Advertise our address. if (!this.options.selfish && this.options.listen) { - let addr = this.hosts.getLocal(peer.address); + const addr = this.hosts.getLocal(peer.address); if (addr) peer.send(new packets.AddrPacket([addr])); } @@ -1409,9 +1392,9 @@ Pool.prototype.handleOpen = async function handleOpen(peer) { */ Pool.prototype.handleClose = async function handleClose(peer, connected) { - let outbound = peer.outbound; - let loader = peer.loader; - let size = peer.blockMap.size; + const outbound = peer.outbound; + const loader = peer.loader; + const size = peer.blockMap.size; this.removePeer(peer); @@ -1472,7 +1455,7 @@ Pool.prototype.handleVersion = async function handleVersion(peer, packet) { packet.services.toString(2), packet.agent); - this.network.time.add(peer.hostname(), packet.ts); + this.network.time.add(peer.hostname(), packet.time); this.nonces.remove(peer.hostname()); if (!peer.outbound && packet.remote.isRoutable()) @@ -1524,9 +1507,6 @@ Pool.prototype.handlePong = async function handlePong(peer, packet) { */ Pool.prototype.handleGetAddr = async function handleGetAddr(peer, packet) { - let items = []; - let addrs; - if (this.options.selfish) return; @@ -1539,9 +1519,10 @@ Pool.prototype.handleGetAddr = async function handleGetAddr(peer, packet) { peer.sentAddr = true; - addrs = this.hosts.toArray(); + const addrs = this.hosts.toArray(); + const items = []; - for (let addr of addrs) { + for (const addr of addrs) { if (!peer.addrFilter.added(addr.hostname, 'ascii')) continue; @@ -1571,11 +1552,11 @@ Pool.prototype.handleGetAddr = async function handleGetAddr(peer, packet) { */ Pool.prototype.handleAddr = async function handleAddr(peer, packet) { - let addrs = packet.items; - let now = this.network.now(); - let services = this.options.getRequiredServices(); + const addrs = packet.items; + const now = this.network.now(); + const services = this.options.getRequiredServices(); - for (let addr of addrs) { + for (const addr of addrs) { peer.addrFilter.add(addr.hostname, 'ascii'); if (!addr.isRoutable()) @@ -1584,8 +1565,8 @@ Pool.prototype.handleAddr = async function handleAddr(peer, packet) { if (!addr.hasServices(services)) continue; - if (addr.ts <= 100000000 || addr.ts > now + 10 * 60) - addr.ts = now - 5 * 24 * 60 * 60; + if (addr.time <= 100000000 || addr.time > now + 10 * 60) + addr.time = now - 5 * 24 * 60 * 60; if (addr.port === 0) continue; @@ -1612,7 +1593,7 @@ Pool.prototype.handleAddr = async function handleAddr(peer, packet) { */ Pool.prototype.handleInv = async function handleInv(peer, packet) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._handleInv(peer, packet); } finally { @@ -1628,18 +1609,19 @@ Pool.prototype.handleInv = async function handleInv(peer, packet) { * @param {InvPacket} packet */ -Pool.prototype._handleInv = async function handleInv(peer, packet) { - let items = packet.items; - let blocks = []; - let txs = []; - let unknown = -1; +Pool.prototype._handleInv = async function _handleInv(peer, packet) { + const items = packet.items; if (items.length > 50000) { peer.increaseBan(100); return; } - for (let item of items) { + const blocks = []; + const txs = []; + let unknown = -1; + + for (const item of items) { switch (item.type) { case invTypes.BLOCK: blocks.push(item.hash); @@ -1681,9 +1663,6 @@ Pool.prototype._handleInv = async function handleInv(peer, packet) { */ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) { - let items = []; - let hash, exists; - assert(hashes.length > 0); if (!this.syncing) @@ -1691,7 +1670,7 @@ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) { // Always keep track of the peer's best hash. if (!peer.loader || this.chain.synced) { - hash = hashes[hashes.length - 1]; + const hash = hashes[hashes.length - 1]; peer.bestHash = hash; } @@ -1711,8 +1690,11 @@ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) { hashes.length, peer.hostname()); + const items = []; + let exists; + for (let i = 0; i < hashes.length; i++) { - let hash = hashes[i]; + const hash = hashes[i]; // Resolve orphan chain. if (this.chain.hasOrphan(hash)) { @@ -1722,7 +1704,7 @@ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) { } // Request the block if we don't have it. - if (!(await this.hasBlock(hash))) { + if (!await this.hasBlock(hash)) { items.push(hash); continue; } @@ -1745,7 +1727,7 @@ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) { // Attempt to update the peer's best height // with the last existing hash we know of. if (exists && this.chain.synced) { - let height = await this.chain.db.getHeight(exists); + const height = await this.chain.db.getHeight(exists); if (height !== -1) peer.bestHeight = height; } @@ -1779,12 +1761,7 @@ Pool.prototype.handleTXInv = async function handleTXInv(peer, hashes) { */ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { - let items = packet.items; - let notFound = []; - let txs = 0; - let blocks = 0; - let compact = 0; - let unknown = -1; + const items = packet.items; if (items.length > 50000) { this.logger.warning('Peer sent inv with >50k items (%s).', peer.hostname()); @@ -1793,9 +1770,15 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { return; } - for (let item of items) { + const notFound = []; + let txs = 0; + let blocks = 0; + let compact = 0; + let unknown = -1; + + for (const item of items) { if (item.isTX()) { - let tx = await this.getItem(peer, item); + const tx = await this.getItem(peer, item); if (!tx) { notFound.push(item); @@ -1822,7 +1805,7 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { switch (item.type) { case invTypes.BLOCK: case invTypes.WITNESS_BLOCK: { - let result = await this.sendBlock(peer, item, item.hasWitness()); + const result = await this.sendBlock(peer, item, item.hasWitness()); if (!result) { notFound.push(item); continue; @@ -1832,8 +1815,6 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { } case invTypes.FILTERED_BLOCK: case invTypes.WITNESS_FILTERED_BLOCK: { - let block; - if (!this.options.bip37) { this.logger.debug( 'Peer requested a merkleblock without bip37 enabled (%s).', @@ -1847,18 +1828,18 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { continue; } - block = await this.getItem(peer, item); + const block = await this.getItem(peer, item); if (!block) { notFound.push(item); continue; } - block = block.toMerkle(peer.spvFilter); + const merkle = block.toMerkle(peer.spvFilter); - peer.send(new packets.MerkleBlockPacket(block)); + peer.send(new packets.MerkleBlockPacket(merkle)); - for (let tx of block.txs) { + for (const tx of merkle.txs) { peer.send(new packets.TXPacket(tx, item.hasWitness())); txs++; } @@ -1868,12 +1849,11 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { break; } case invTypes.CMPCT_BLOCK: { - let height = await this.chain.db.getHeight(item.hash); - let block; + const height = await this.chain.db.getHeight(item.hash); // Fallback to full block. if (height < this.chain.tip.height - 10) { - let result = await this.sendBlock(peer, item, peer.compactWitness); + const result = await this.sendBlock(peer, item, peer.compactWitness); if (!result) { notFound.push(item); continue; @@ -1882,7 +1862,7 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { break; } - block = await this.getItem(peer, item); + const block = await this.getItem(peer, item); if (!block) { notFound.push(item); @@ -1945,9 +1925,9 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) { */ Pool.prototype.handleNotFound = async function handleNotFound(peer, packet) { - let items = packet.items; + const items = packet.items; - for (let item of items) { + for (const item of items) { if (!this.resolveItem(peer, item)) { this.logger.warning( 'Peer sent notfound for unrequested item: %s (%s).', @@ -1967,9 +1947,6 @@ Pool.prototype.handleNotFound = async function handleNotFound(peer, packet) { */ Pool.prototype.handleGetBlocks = async function handleGetBlocks(peer, packet) { - let blocks = []; - let hash; - if (!this.chain.synced) return; @@ -1982,11 +1959,13 @@ Pool.prototype.handleGetBlocks = async function handleGetBlocks(peer, packet) { if (this.chain.options.prune) return; - hash = await this.chain.findLocator(packet.locator); + let hash = await this.chain.findLocator(packet.locator); if (hash) hash = await this.chain.db.getNextHash(hash); + const blocks = []; + while (hash) { blocks.push(new InvItem(invTypes.BLOCK, hash)); @@ -2013,9 +1992,6 @@ Pool.prototype.handleGetBlocks = async function handleGetBlocks(peer, packet) { */ Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet) { - let headers = []; - let hash, entry; - if (!this.chain.synced) return; @@ -2028,6 +2004,7 @@ Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet) if (this.chain.options.prune) return; + let hash; if (packet.locator.length > 0) { hash = await this.chain.findLocator(packet.locator); if (hash) @@ -2036,9 +2013,12 @@ Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet) hash = packet.stop; } + let entry; if (hash) entry = await this.chain.db.getEntry(hash); + const headers = []; + while (entry) { headers.push(entry.toHeaders()); @@ -2064,7 +2044,7 @@ Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet) */ Pool.prototype.handleHeaders = async function handleHeaders(peer, packet) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._handleHeaders(peer, packet); } finally { @@ -2082,10 +2062,8 @@ Pool.prototype.handleHeaders = async function handleHeaders(peer, packet) { * @returns {Promise} */ -Pool.prototype._handleHeaders = async function handleHeaders(peer, packet) { - let headers = packet.items; - let checkpoint = false; - let node; +Pool.prototype._handleHeaders = async function _handleHeaders(peer, packet) { + const headers = packet.items; if (!this.checkpoints) return; @@ -2106,10 +2084,13 @@ Pool.prototype._handleHeaders = async function handleHeaders(peer, packet) { assert(this.headerChain.size > 0); - for (let header of headers) { - let last = this.headerChain.tail; - let hash = header.hash('hex'); - let height = last.height + 1; + let checkpoint = false; + let node = null; + + for (const header of headers) { + const last = this.headerChain.tail; + const hash = header.hash('hex'); + const height = last.height + 1; if (!header.verify()) { this.logger.warning( @@ -2124,17 +2105,7 @@ Pool.prototype._handleHeaders = async function handleHeaders(peer, packet) { this.logger.warning( 'Peer sent a bad header chain (%s).', peer.hostname()); - - if (++this.headerFails < Pool.MAX_HEADER_FAILS) { - peer.destroy(); - return; - } - - this.logger.warning( - 'Switching to getblocks (%s).', - peer.hostname()); - - await this.switchSync(peer); + peer.destroy(); return; } @@ -2145,17 +2116,7 @@ Pool.prototype._handleHeaders = async function handleHeaders(peer, packet) { this.logger.warning( 'Peer sent an invalid checkpoint (%s).', peer.hostname()); - - if (++this.headerFails < Pool.MAX_HEADER_FAILS) { - peer.destroy(); - return; - } - - this.logger.warning( - 'Switching to getblocks (%s).', - peer.hostname()); - - await this.switchSync(peer); + peer.destroy(); return; } checkpoint = true; @@ -2210,7 +2171,7 @@ Pool.prototype.handleSendHeaders = async function handleSendHeaders(peer, packet */ Pool.prototype.handleBlock = async function handleBlock(peer, packet) { - let flags = chainCommon.flags.DEFAULT_FLAGS; + const flags = chainCommon.flags.DEFAULT_FLAGS; if (this.options.spv) { this.logger.warning( @@ -2219,7 +2180,7 @@ Pool.prototype.handleBlock = async function handleBlock(peer, packet) { return; } - return await this.addBlock(peer, packet.block, flags); + await this.addBlock(peer, packet.block, flags); }; /** @@ -2232,8 +2193,8 @@ Pool.prototype.handleBlock = async function handleBlock(peer, packet) { */ Pool.prototype.addBlock = async function addBlock(peer, block, flags) { - let hash = block.hash('hex'); - let unlock = await this.locker.lock(hash); + const hash = block.hash('hex'); + const unlock = await this.locker.lock(hash); try { return await this._addBlock(peer, block, flags); } finally { @@ -2250,13 +2211,12 @@ Pool.prototype.addBlock = async function addBlock(peer, block, flags) { * @returns {Promise} */ -Pool.prototype._addBlock = async function addBlock(peer, block, flags) { - let hash = block.hash('hex'); - let entry; - +Pool.prototype._addBlock = async function _addBlock(peer, block, flags) { if (!this.syncing) return; + const hash = block.hash('hex'); + if (!this.resolveBlock(peer, hash)) { this.logger.warning( 'Received unrequested block: %s (%s).', @@ -2267,6 +2227,7 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) { peer.blockTime = util.ms(); + let entry; try { entry = await this.chain.add(block, flags, peer.id); } catch (err) { @@ -2280,8 +2241,6 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) { // Block was orphaned. if (!entry) { - let height; - if (this.checkpoints) { this.logger.warning( 'Peer sent orphan block with getheaders (%s).', @@ -2292,7 +2251,7 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) { // During a getblocks sync, peers send // their best tip frequently. We can grab // the height commitment from the coinbase. - height = block.getCoinbaseHeight(); + const height = block.getCoinbaseHeight(); if (height !== -1) { peer.bestHash = hash; @@ -2328,8 +2287,6 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) { */ Pool.prototype.resolveChain = async function resolveChain(peer, hash) { - let node = this.headerChain.head; - if (!this.checkpoints) return; @@ -2339,6 +2296,8 @@ Pool.prototype.resolveChain = async function resolveChain(peer, hash) { if (peer.destroyed) throw new Error('Peer was destroyed (header chain resolution).'); + const node = this.headerChain.head; + assert(node); if (hash !== node.hash) { @@ -2392,7 +2351,6 @@ Pool.prototype.switchSync = async function switchSync(peer, hash) { assert(this.checkpoints); this.checkpoints = false; - this.chain.checkpoints = false; this.headerTip = null; this.headerChain.reset(); this.headerNext = null; @@ -2410,7 +2368,7 @@ Pool.prototype.switchSync = async function switchSync(peer, hash) { */ Pool.prototype.handleBadOrphan = function handleBadOrphan(msg, err, id) { - let peer = this.peers.find(id); + const peer = this.peers.find(id); if (!peer) { this.logger.warning( @@ -2436,10 +2394,10 @@ Pool.prototype.handleBadOrphan = function handleBadOrphan(msg, err, id) { Pool.prototype.logStatus = function logStatus(block) { if (this.chain.height % 20 === 0) { this.logger.debug('Status:' - + ' ts=%s height=%d progress=%s' + + ' time=%s height=%d progress=%s' + ' orphans=%d active=%d' + ' target=%s peers=%d', - util.date(block.ts), + util.date(block.time), this.chain.height, (this.chain.getProgress() * 100).toFixed(2) + '%', this.chain.orphanMap.size, @@ -2466,8 +2424,8 @@ Pool.prototype.logStatus = function logStatus(block) { */ Pool.prototype.handleTX = async function handleTX(peer, packet) { - let hash = packet.tx.hash('hex'); - let unlock = await this.locker.lock(hash); + const hash = packet.tx.hash('hex'); + const unlock = await this.locker.lock(hash); try { return await this._handleTX(peer, packet); } finally { @@ -2484,12 +2442,11 @@ Pool.prototype.handleTX = async function handleTX(peer, packet) { * @returns {Promise} */ -Pool.prototype._handleTX = async function handleTX(peer, packet) { - let tx = packet.tx; - let hash = tx.hash('hex'); - let flags = chainCommon.flags.VERIFY_NONE; - let block = peer.merkleBlock; - let missing; +Pool.prototype._handleTX = async function _handleTX(peer, packet) { + const tx = packet.tx; + const hash = tx.hash('hex'); + const flags = chainCommon.flags.VERIFY_NONE; + const block = peer.merkleBlock; if (block) { assert(peer.merkleMatches > 0); @@ -2506,7 +2463,7 @@ Pool.prototype._handleTX = async function handleTX(peer, packet) { peer.merkleMap.add(hash); - block.addTX(tx); + block.txs.push(tx); if (--peer.merkleMatches === 0) { peer.merkleBlock = null; @@ -2533,6 +2490,7 @@ Pool.prototype._handleTX = async function handleTX(peer, packet) { return; } + let missing; try { missing = await this.mempool.addTX(tx, peer.id); } catch (err) { @@ -2562,8 +2520,6 @@ Pool.prototype._handleTX = async function handleTX(peer, packet) { */ Pool.prototype.handleReject = async function handleReject(peer, packet) { - let entry; - this.logger.warning( 'Received reject (%s): msg=%s code=%s reason=%s hash=%s.', peer.hostname(), @@ -2575,7 +2531,7 @@ Pool.prototype.handleReject = async function handleReject(peer, packet) { if (!packet.hash) return; - entry = this.invMap.get(packet.hash); + const entry = this.invMap.get(packet.hash); if (!entry) return; @@ -2592,8 +2548,6 @@ Pool.prototype.handleReject = async function handleReject(peer, packet) { */ Pool.prototype.handleMempool = async function handleMempool(peer, packet) { - let items = []; - if (!this.mempool) return; @@ -2611,7 +2565,9 @@ Pool.prototype.handleMempool = async function handleMempool(peer, packet) { return; } - for (let hash of this.mempool.map.keys()) + const items = []; + + for (const hash of this.mempool.map.keys()) items.push(new InvItem(invTypes.TX, hash)); this.logger.debug( @@ -2666,8 +2622,8 @@ Pool.prototype.handleFilterClear = async function handleFilterClear(peer, packet */ Pool.prototype.handleMerkleBlock = async function handleMerkleBlock(peer, packet) { - let hash = packet.block.hash('hex'); - let unlock = await this.locker.lock(hash); + const hash = packet.block.hash('hex'); + const unlock = await this.locker.lock(hash); try { return await this._handleMerkleBlock(peer, packet); } finally { @@ -2683,11 +2639,7 @@ Pool.prototype.handleMerkleBlock = async function handleMerkleBlock(peer, packet * @param {MerkleBlockPacket} block */ -Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packet) { - let block = packet.block; - let hash = block.hash('hex'); - let flags = chainCommon.flags.VERIFY_NONE; - +Pool.prototype._handleMerkleBlock = async function _handleMerkleBlock(peer, packet) { if (!this.syncing) return; @@ -2700,6 +2652,9 @@ Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packe return; } + const block = packet.block; + const hash = block.hash('hex'); + if (!peer.blockMap.has(hash)) { this.logger.warning( 'Peer sent an unrequested merkleblock (%s).', @@ -2724,14 +2679,17 @@ Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packe return; } - if (block.tree.matches.length === 0) { + const tree = block.getTree(); + + if (tree.matches.length === 0) { + const flags = chainCommon.flags.VERIFY_NONE; await this._addBlock(peer, block, flags); return; } peer.merkleBlock = block; peer.merkleTime = util.ms(); - peer.merkleMatches = block.tree.matches.length; + peer.merkleMatches = tree.matches.length; peer.merkleMap = new Set(); }; @@ -2768,11 +2726,9 @@ Pool.prototype.handleSendCmpct = async function handleSendCmpct(peer, packet) { */ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet) { - let block = packet.block; - let hash = block.hash('hex'); - let witness = peer.compactWitness; - let flags = chainCommon.flags.VERIFY_BODY; - let result; + const block = packet.block; + const hash = block.hash('hex'); + const witness = peer.compactWitness; if (!this.syncing) return; @@ -2833,6 +2789,7 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet) return; } + let result; try { result = block.init(); } catch (e) { @@ -2852,12 +2809,13 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet) return; } - result = block.fillMempool(witness, this.mempool); + const full = block.fillMempool(witness, this.mempool); - if (result) { + if (full) { this.logger.debug( 'Received full compact block %s (%s).', block.rhash(), peer.hostname()); + const flags = chainCommon.flags.VERIFY_BODY; await this.addBlock(peer, block.toBlock(), flags); return; } @@ -2893,8 +2851,7 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet) */ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet) { - let req = packet.request; - let res, item, block, height; + const req = packet.request; if (this.chain.options.spv) return; @@ -2905,9 +2862,9 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet if (this.options.selfish) return; - item = new InvItem(invTypes.BLOCK, req.hash); + const item = new InvItem(invTypes.BLOCK, req.hash); - block = await this.getItem(peer, item); + const block = await this.getItem(peer, item); if (!block) { this.logger.debug( @@ -2917,7 +2874,7 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet return; } - height = await this.chain.db.getHeight(req.hash); + const height = await this.chain.db.getHeight(req.hash); if (height < this.chain.tip.height - 15) { this.logger.debug( @@ -2931,7 +2888,7 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet block.rhash(), peer.hostname()); - res = BIP152.TXResponse.fromBlock(block, req); + const res = BIP152.TXResponse.fromBlock(block, req); peer.send(new packets.BlockTxnPacket(res, peer.compactWitness)); }; @@ -2945,9 +2902,9 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet */ Pool.prototype.handleBlockTxn = async function handleBlockTxn(peer, packet) { - let res = packet.response; - let block = peer.compactBlocks.get(res.hash); - let flags = chainCommon.flags.VERIFY_BODY; + const res = packet.response; + const block = peer.compactBlocks.get(res.hash); + const flags = chainCommon.flags.VERIFY_BODY; if (!block) { this.logger.debug( @@ -3059,14 +3016,12 @@ Pool.prototype.handleUnknown = async function handleUnknown(peer, packet) { */ Pool.prototype.addInbound = function addInbound(socket) { - let peer; - if (!this.loaded) { socket.destroy(); return; } - peer = this.createInbound(socket); + const peer = this.createInbound(socket); this.logger.info('Added inbound peer (%s).', peer.hostname()); @@ -3079,24 +3034,23 @@ Pool.prototype.addInbound = function addInbound(socket) { */ Pool.prototype.getHost = function getHost() { - let services = this.options.getRequiredServices(); - let now = this.network.now(); - - for (let addr of this.hosts.nodes) { + for (const addr of this.hosts.nodes) { if (this.peers.has(addr.hostname)) continue; return addr; } + const services = this.options.getRequiredServices(); + const now = this.network.now(); + for (let i = 0; i < 100; i++) { - let entry = this.hosts.getHost(); - let addr; + const entry = this.hosts.getHost(); if (!entry) break; - addr = entry.addr; + const addr = entry.addr; if (this.peers.has(addr.hostname)) continue; @@ -3121,6 +3075,8 @@ Pool.prototype.getHost = function getHost() { return entry.addr; } + + return null; }; /** @@ -3130,8 +3086,6 @@ Pool.prototype.getHost = function getHost() { */ Pool.prototype.addOutbound = function addOutbound() { - let peer, addr; - if (!this.loaded) return; @@ -3143,12 +3097,12 @@ Pool.prototype.addOutbound = function addOutbound() { if (!this.peers.load) return; - addr = this.getHost(); + const addr = this.getHost(); if (!addr) return; - peer = this.createOutbound(addr); + const peer = this.createOutbound(addr); this.peers.add(peer); @@ -3161,7 +3115,7 @@ Pool.prototype.addOutbound = function addOutbound() { */ Pool.prototype.fillOutbound = function fillOutbound() { - let need = this.options.maxOutbound - this.peers.outbound; + const need = this.options.maxOutbound - this.peers.outbound; if (!this.peers.load) this.addLoader(); @@ -3201,13 +3155,13 @@ Pool.prototype.refill = function refill() { Pool.prototype.removePeer = function removePeer(peer) { this.peers.remove(peer); - for (let hash of peer.blockMap.keys()) + for (const hash of peer.blockMap.keys()) this.resolveBlock(peer, hash); - for (let hash of peer.txMap.keys()) + for (const hash of peer.txMap.keys()) this.resolveTX(peer, hash); - for (let hash of peer.compactBlocks.keys()) { + for (const hash of peer.compactBlocks.keys()) { assert(this.compactBlocks.has(hash)); this.compactBlocks.delete(hash); } @@ -3221,7 +3175,7 @@ Pool.prototype.removePeer = function removePeer(peer) { */ Pool.prototype.ban = function ban(addr) { - let peer = this.peers.get(addr.hostname); + const peer = this.peers.get(addr.hostname); this.logger.debug('Banning peer (%s).', addr.hostname); @@ -3318,7 +3272,7 @@ Pool.prototype.sendFilterLoad = function sendFilterLoad() { */ Pool.prototype.watchAddress = function watchAddress(address) { - let hash = Address.getHash(address); + const hash = Address.getHash(address); this.watch(hash); }; @@ -3341,8 +3295,8 @@ Pool.prototype.watchOutpoint = function watchOutpoint(outpoint) { */ Pool.prototype.resolveOrphan = async function resolveOrphan(peer, orphan) { - let locator = await this.chain.getLocator(); - let root = this.chain.getOrphanRoot(orphan); + const locator = await this.chain.getLocator(); + const root = this.chain.getOrphanRoot(orphan); assert(root); @@ -3359,7 +3313,7 @@ Pool.prototype.resolveOrphan = async function resolveOrphan(peer, orphan) { */ Pool.prototype.getHeaders = async function getHeaders(peer, tip, stop) { - let locator = await this.chain.getLocator(tip); + const locator = await this.chain.getLocator(tip); peer.sendGetHeaders(locator, stop); }; @@ -3373,7 +3327,7 @@ Pool.prototype.getHeaders = async function getHeaders(peer, tip, stop) { */ Pool.prototype.getBlocks = async function getBlocks(peer, tip, stop) { - let locator = await this.chain.getLocator(tip); + const locator = await this.chain.getLocator(tip); peer.sendGetBlocks(locator, stop); }; @@ -3384,9 +3338,6 @@ Pool.prototype.getBlocks = async function getBlocks(peer, tip, stop) { */ Pool.prototype.getBlock = function getBlock(peer, hashes) { - let now = util.ms(); - let items = []; - if (!this.loaded) return; @@ -3396,7 +3347,10 @@ Pool.prototype.getBlock = function getBlock(peer, hashes) { if (peer.destroyed) throw new Error('Peer is destroyed (getdata).'); - for (let hash of hashes) { + let now = util.ms(); + const items = []; + + for (const hash of hashes) { if (this.blockMap.has(hash)) continue; @@ -3428,9 +3382,6 @@ Pool.prototype.getBlock = function getBlock(peer, hashes) { */ Pool.prototype.getTX = function getTX(peer, hashes) { - let now = util.ms(); - let items = []; - if (!this.loaded) return; @@ -3440,7 +3391,10 @@ Pool.prototype.getTX = function getTX(peer, hashes) { if (peer.destroyed) throw new Error('Peer is destroyed (getdata).'); - for (let hash of hashes) { + let now = util.ms(); + const items = []; + + for (const hash of hashes) { if (this.txMap.has(hash)) continue; @@ -3522,9 +3476,9 @@ Pool.prototype.hasTX = function hasTX(hash) { */ Pool.prototype.ensureTX = function ensureTX(peer, hashes) { - let items = []; + const items = []; - for (let hash of hashes) { + for (const hash of hashes) { if (this.hasTX(hash)) continue; @@ -3596,7 +3550,7 @@ Pool.prototype.resolveItem = function resolveItem(peer, item) { */ Pool.prototype.broadcast = function broadcast(msg) { - let hash = msg.hash('hex'); + const hash = msg.hash('hex'); let item = this.invMap.get(hash); if (item) { @@ -3765,15 +3719,14 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) { if (options.host != null) { assert(typeof options.host === 'string'); - let raw = IP.toBuffer(options.host); + const raw = IP.toBuffer(options.host); this.host = IP.toString(raw); if (IP.isRoutable(raw)) this.publicHost = this.host; } if (options.port != null) { - assert(typeof options.port === 'number'); - assert(options.port > 0 && options.port <= 0xffff); + assert(util.isU16(options.port)); this.port = options.port; this.publicPort = options.port; } @@ -3784,8 +3737,7 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) { } if (options.publicPort != null) { - assert(typeof options.publicPort === 'number'); - assert(options.publicPort > 0 && options.publicPort <= 0xffff); + assert(util.isU16(options.publicPort)); this.publicPort = options.publicPort; } @@ -3946,12 +3898,12 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) { this.listen = false; if (options.services != null) { - assert(util.isUInt32(options.services)); + assert(util.isU32(options.services)); this.services = options.services; } if (options.requiredServices != null) { - assert(util.isUInt32(options.requiredServices)); + assert(util.isU32(options.requiredServices)); this.requiredServices = options.requiredServices; } @@ -4041,12 +3993,10 @@ PoolOptions.prototype.hasNonce = function hasNonce(nonce) { */ PoolOptions.prototype.getRate = function getRate(hash) { - let entry; - if (!this.mempool) return -1; - entry = this.mempool.getEntry(hash); + const entry = this.mempool.getEntry(hash); if (!entry) return -1; @@ -4062,7 +4012,7 @@ PoolOptions.prototype.getRate = function getRate(hash) { * @returns {net.Socket} */ -PoolOptions.prototype._createSocket = function createSocket(port, host) { +PoolOptions.prototype._createSocket = function _createSocket(port, host) { return tcp.createSocket(port, host, this.proxy); }; @@ -4073,7 +4023,7 @@ PoolOptions.prototype._createSocket = function createSocket(port, host) { * @returns {String[]} */ -PoolOptions.prototype._resolve = function resolve(name) { +PoolOptions.prototype._resolve = function _resolve(name) { if (this.onion) return dns.lookup(name, this.proxy); @@ -4225,14 +4175,12 @@ PeerList.prototype.destroy = function destroy() { */ function BroadcastItem(pool, msg) { - let item; - if (!(this instanceof BroadcastItem)) return new BroadcastItem(pool, msg); assert(!msg.mutable, 'Cannot broadcast mutable item.'); - item = msg.toInv(); + const item = msg.toInv(); this.pool = pool; this.hash = item.hash; @@ -4241,7 +4189,7 @@ function BroadcastItem(pool, msg) { this.jobs = []; } -util.inherits(BroadcastItem, EventEmitter); +Object.setPrototypeOf(BroadcastItem.prototype, EventEmitter.prototype); /** * Add a job to be executed on ack, timeout, or reject. @@ -4323,7 +4271,7 @@ BroadcastItem.prototype.cleanup = function cleanup() { BroadcastItem.prototype.reject = function reject(err) { this.cleanup(); - for (let job of this.jobs) + for (const job of this.jobs) job.reject(err); this.jobs.length = 0; @@ -4336,7 +4284,7 @@ BroadcastItem.prototype.reject = function reject(err) { BroadcastItem.prototype.resolve = function resolve() { this.cleanup(); - for (let job of this.jobs) + for (const job of this.jobs) job.resolve(false); this.jobs.length = 0; @@ -4351,7 +4299,7 @@ BroadcastItem.prototype.handleAck = function handleAck(peer) { setTimeout(() => { this.emit('ack', peer); - for (let job of this.jobs) + for (const job of this.jobs) job.resolve(true); this.jobs.length = 0; @@ -4366,7 +4314,7 @@ BroadcastItem.prototype.handleAck = function handleAck(peer) { BroadcastItem.prototype.handleReject = function handleReject(peer) { this.emit('reject', peer); - for (let job of this.jobs) + for (const job of this.jobs) job.resolve(false); this.jobs.length = 0; @@ -4378,8 +4326,8 @@ BroadcastItem.prototype.handleReject = function handleReject(peer) { */ BroadcastItem.prototype.inspect = function inspect() { - let type = this.type === invTypes.TX ? 'tx' : 'block'; - let hash = util.revHex(this.hash); + const type = this.type === invTypes.TX ? 'tx' : 'block'; + const hash = util.revHex(this.hash); return ``; }; @@ -4395,29 +4343,29 @@ function NonceList() { } NonceList.prototype.alloc = function alloc(hostname) { - let nonce, key; - for (;;) { - nonce = util.nonce(); - key = nonce.toString('hex'); - if (!this.map.has(key)) { - this.map.set(key, hostname); - assert(!this.hosts.has(hostname)); - this.hosts.set(hostname, key); - break; - } - } + const nonce = util.nonce(); + const key = nonce.toString('hex'); + + if (this.map.has(key)) + continue; - return nonce; + this.map.set(key, hostname); + + assert(!this.hosts.has(hostname)); + this.hosts.set(hostname, key); + + return nonce; + } }; NonceList.prototype.has = function has(nonce) { - let key = nonce.toString('hex'); + const key = nonce.toString('hex'); return this.map.has(key); }; NonceList.prototype.remove = function remove(hostname) { - let key = this.hosts.get(hostname); + const key = this.hosts.get(hostname); if (!key) return false; diff --git a/lib/net/proxysocket.js b/lib/net/proxysocket.js index db4d6249b..80f91641f 100644 --- a/lib/net/proxysocket.js +++ b/lib/net/proxysocket.js @@ -36,7 +36,7 @@ function ProxySocket(uri) { this._init(); } -util.inherits(ProxySocket, EventEmitter); +Object.setPrototypeOf(ProxySocket.prototype, EventEmitter.prototype); ProxySocket.prototype._init = function _init() { this.socket.on('info', (info) => { @@ -83,7 +83,7 @@ ProxySocket.prototype._init = function _init() { }); this.socket.on('tcp error', (e) => { - let err = new Error(e.message); + const err = new Error(e.message); err.code = e.code; this.emit('error', err); }); @@ -101,8 +101,6 @@ ProxySocket.prototype._init = function _init() { }; ProxySocket.prototype.connect = function connect(port, host) { - let nonce = 0; - this.remoteAddress = host; this.remotePort = port; @@ -116,14 +114,17 @@ ProxySocket.prototype.connect = function connect(port, host) { return; } + let nonce = 0; + if (this.info.pow) { - let pow = new BufferWriter(); + const bw = new BufferWriter(); + + bw.writeU32(nonce); + bw.writeBytes(this.snonce); + bw.writeU32(port); + bw.writeString(host, 'ascii'); - pow.writeU32(nonce); - pow.writeBytes(this.snonce); - pow.writeU32(port); - pow.writeString(host, 'ascii'); - pow = pow.render(); + const pow = bw.render(); util.log( 'Solving proof of work to create socket (%d, %s) -- please wait.', @@ -140,7 +141,7 @@ ProxySocket.prototype.connect = function connect(port, host) { this.socket.emit('tcp connect', port, host, nonce); - for (let chunk of this.sendBuffer) + for (const chunk of this.sendBuffer) this.write(chunk); this.sendBuffer.length = 0; @@ -185,12 +186,12 @@ ProxySocket.prototype.pause = function pause() { }; ProxySocket.prototype.resume = function resume() { - let recv = this.recvBuffer; + const recv = this.recvBuffer; this.paused = false; this.recvBuffer = []; - for (let data of recv) { + for (const data of recv) { this.bytesRead += data.length; this.emit('data', data); } @@ -204,7 +205,7 @@ ProxySocket.prototype.destroy = function destroy() { }; ProxySocket.connect = function connect(uri, port, host) { - let socket = new ProxySocket(uri); + const socket = new ProxySocket(uri); socket.connect(port, host); return socket; }; diff --git a/lib/net/socks.js b/lib/net/socks.js index 86852dbe0..e0282fa5e 100644 --- a/lib/net/socks.js +++ b/lib/net/socks.js @@ -42,7 +42,7 @@ function SOCKS() { this.proxied = false; } -util.inherits(SOCKS, EventEmitter); +Object.setPrototypeOf(SOCKS.prototype, EventEmitter.prototype); SOCKS.states = { INIT: 0, @@ -55,7 +55,7 @@ SOCKS.states = { RESOLVE_DONE: 7 }; -SOCKS.statesByVal = util.revMap(SOCKS.states); +SOCKS.statesByVal = util.reverse(SOCKS.states); SOCKS.errors = [ '', @@ -71,8 +71,6 @@ SOCKS.errors = [ ]; SOCKS.prototype.error = function error(err) { - let msg; - if (this.destroyed) return; @@ -82,7 +80,7 @@ SOCKS.prototype.error = function error(err) { return; } - msg = util.fmt.apply(util, arguments); + const msg = util.fmt.apply(util, arguments); this.emit('error', new Error(msg)); this.destroy(); }; @@ -111,7 +109,7 @@ SOCKS.prototype.destroy = function destroy() { SOCKS.prototype.startTimeout = function startTimeout() { this.timeout = setTimeout(() => { - let state = SOCKS.statesByVal[this.state]; + const state = SOCKS.statesByVal[this.state]; this.timeout = null; this.error('SOCKS request timed out (state=%s).', state); }, 8000); @@ -210,7 +208,7 @@ SOCKS.prototype.handleError = function handleError(err) { SOCKS.prototype.handleClose = function handleClose() { if (this.state !== this.target) { - let state = SOCKS.statesByVal[this.state]; + const state = SOCKS.statesByVal[this.state]; this.error('SOCKS request destroyed (state=%s).', state); return; } @@ -298,9 +296,8 @@ SOCKS.prototype.handleHandshake = function handleHandshake(data) { }; SOCKS.prototype.sendAuth = function sendAuth() { - let user = this.username; - let pass = this.password; - let ulen, plen, size, packet; + const user = this.username; + const pass = this.password; if (!user) { this.error('No username passed for SOCKS auth.'); @@ -312,17 +309,19 @@ SOCKS.prototype.sendAuth = function sendAuth() { return; } - ulen = Buffer.byteLength(user, 'ascii'); - plen = Buffer.byteLength(pass, 'ascii'); - size = 3 + ulen + plen; + const ulen = Buffer.byteLength(user, 'ascii'); + const plen = Buffer.byteLength(pass, 'ascii'); + const size = 3 + ulen + plen; + + const bw = new StaticWriter(size); + + bw.writeU8(0x01); + bw.writeU8(ulen); + bw.writeString(user, 'ascii'); + bw.writeU8(plen); + bw.writeString(pass, 'ascii'); - packet = new StaticWriter(size); - packet.writeU8(0x01); - packet.writeU8(ulen); - packet.writeString(user, 'ascii'); - packet.writeU8(plen); - packet.writeString(pass, 'ascii'); - packet = packet.render(); + const packet = bw.render(); this.state = SOCKS.states.AUTH; this.socket.write(packet); @@ -364,9 +363,9 @@ SOCKS.prototype.auth = function auth() { }; SOCKS.prototype.sendProxy = function sendProxy() { - let host = this.destHost; - let port = this.destPort; - let ip, len, type, name, packet; + const host = this.destHost; + const port = this.destPort; + let ip, len, type, name; switch (IP.getStringType(host)) { case IP.types.IPV4: @@ -388,28 +387,26 @@ SOCKS.prototype.sendProxy = function sendProxy() { break; } - packet = new StaticWriter(6 + len); + const bw = new StaticWriter(6 + len); - packet.writeU8(0x05); - packet.writeU8(0x01); - packet.writeU8(0x00); - packet.writeU8(type); + bw.writeU8(0x05); + bw.writeU8(0x01); + bw.writeU8(0x00); + bw.writeU8(type); if (type === 0x03) - packet.writeU8(name.length); + bw.writeU8(name.length); - packet.writeBytes(name); - packet.writeU16BE(port); + bw.writeBytes(name); + bw.writeU16BE(port); - packet = packet.render(); + const packet = bw.render(); this.state = SOCKS.states.PROXY; this.socket.write(packet); }; SOCKS.prototype.handleProxy = function handleProxy(data) { - let addr; - if (data.length < 6) { this.error('Bad packet size for SOCKS connect.'); return; @@ -421,7 +418,7 @@ SOCKS.prototype.handleProxy = function handleProxy(data) { } if (data[1] !== 0x00) { - let msg = this.getError(data[1]); + const msg = this.getError(data[1]); this.error('SOCKS connect error: %s.', msg); return; } @@ -431,6 +428,7 @@ SOCKS.prototype.handleProxy = function handleProxy(data) { return; } + let addr; try { addr = parseAddr(data, 3); } catch (e) { @@ -447,26 +445,26 @@ SOCKS.prototype.handleProxy = function handleProxy(data) { }; SOCKS.prototype.sendResolve = function sendResolve() { - let name = this.name; - let len = Buffer.byteLength(name, 'utf8'); - let packet = new StaticWriter(7 + len); - - packet.writeU8(0x05); - packet.writeU8(0xf0); - packet.writeU8(0x00); - packet.writeU8(0x03); - packet.writeU8(len); - packet.writeString(name, 'utf8'); - packet.writeU16BE(0); - packet = packet.render(); + const name = this.name; + const len = Buffer.byteLength(name, 'utf8'); + + const bw = new StaticWriter(7 + len); + + bw.writeU8(0x05); + bw.writeU8(0xf0); + bw.writeU8(0x00); + bw.writeU8(0x03); + bw.writeU8(len); + bw.writeString(name, 'utf8'); + bw.writeU16BE(0); + + const packet = bw.render(); this.state = SOCKS.states.RESOLVE; this.socket.write(packet); }; SOCKS.prototype.handleResolve = function handleResolve(data) { - let addr; - if (data.length < 6) { this.error('Bad packet size for tor resolve.'); return; @@ -478,7 +476,7 @@ SOCKS.prototype.handleResolve = function handleResolve(data) { } if (data[1] !== 0x00) { - let msg = this.getError(data[1]); + const msg = this.getError(data[1]); this.error('Tor resolve error: %s (%s).', msg, this.name); return; } @@ -488,6 +486,7 @@ SOCKS.prototype.handleResolve = function handleResolve(data) { return; } + let addr; try { addr = parseAddr(data, 3); } catch (e) { @@ -507,7 +506,7 @@ SOCKS.prototype.handleResolve = function handleResolve(data) { }; SOCKS.resolve = function resolve(options) { - let socks = new SOCKS(); + const socks = new SOCKS(); return new Promise((resolve, reject) => { socks.resolve(options); socks.on('resolve', resolve); @@ -516,7 +515,7 @@ SOCKS.resolve = function resolve(options) { }; SOCKS.proxy = function proxy(options) { - let socks = new SOCKS(); + const socks = new SOCKS(); return new Promise((resolve, reject) => { socks.proxy(options); socks.on('proxy', resolve); @@ -554,14 +553,12 @@ function Proxy(host, port, user, pass) { this.ops = []; } -util.inherits(Proxy, EventEmitter); +Object.setPrototypeOf(Proxy.prototype, EventEmitter.prototype); Proxy.prototype.connect = async function connect(port, host) { - let options, socket; - assert(!this.socket, 'Already connected.'); - options = { + const options = { host: this.host, port: this.port, username: this.username, @@ -570,6 +567,7 @@ Proxy.prototype.connect = async function connect(port, host) { destPort: port }; + let socket; try { socket = await SOCKS.proxy(options); } catch (e) { @@ -602,7 +600,7 @@ Proxy.prototype.connect = async function connect(port, host) { this.emit('timeout'); }); - for (let op of this.ops) + for (const op of this.ops) op.call(this); this.ops.length = 0; @@ -664,7 +662,7 @@ Proxy.prototype.resume = function resume() { Proxy.prototype.destroy = function destroy() { if (!this.socket) return; - return this.socket.destroy(); + this.socket.destroy(); }; /* @@ -672,24 +670,23 @@ Proxy.prototype.destroy = function destroy() { */ function parseProxy(host) { - let index = host.indexOf('@'); - let addr, left, right, parts; + const index = host.indexOf('@'); if (index === -1) { - let addr = IP.fromHostname(host, 1080); + const addr = IP.fromHostname(host, 1080); return { host: addr.host, port: addr.port }; } - left = host.substring(0, index); - right = host.substring(index + 1); + const left = host.substring(0, index); + const right = host.substring(index + 1); - parts = left.split(':'); + const parts = left.split(':'); assert(parts.length > 1, 'Bad username and password.'); - addr = IP.fromHostname(right, 1080); + const addr = IP.fromHostname(right, 1080); return { host: addr.host, @@ -700,26 +697,27 @@ function parseProxy(host) { } function parseAddr(data, offset) { - let br = new BufferReader(data); - let type, len, host, port; + const br = new BufferReader(data); if (br.left() < offset + 2) throw new Error('Bad SOCKS address length.'); br.seek(offset); - type = br.readU8(); + const type = br.readU8(); + let host, port; switch (type) { - case 0x01: + case 0x01: { if (br.left() < 6) throw new Error('Bad SOCKS ipv4 length.'); host = IP.toString(br.readBytes(4)); port = br.readU16BE(); break; - case 0x03: - len = br.readU8(); + } + case 0x03: { + const len = br.readU8(); if (br.left() < len + 2) throw new Error('Bad SOCKS domain length.'); @@ -727,15 +725,18 @@ function parseAddr(data, offset) { host = br.readString(len, 'utf8'); port = br.readU16BE(); break; - case 0x04: + } + case 0x04: { if (br.left() < 18) throw new Error('Bad SOCKS ipv6 length.'); host = IP.toString(br.readBytes(16)); port = br.readU16BE(); break; - default: + } + default: { throw new Error(`Unknown SOCKS address type: ${type}.`); + } } return { @@ -750,21 +751,20 @@ function parseAddr(data, offset) { */ exports.connect = function connect(proxy, destPort, destHost) { - let addr = parseProxy(proxy); - let host = addr.host; - let port = addr.port; - let user = addr.username; - let pass = addr.password; - let socket; + const addr = parseProxy(proxy); + const host = addr.host; + const port = addr.port; + const user = addr.username; + const pass = addr.password; - socket = new Proxy(host, port, user, pass); + const socket = new Proxy(host, port, user, pass); socket.connect(destPort, destHost); return socket; }; exports.resolve = function resolve(proxy, name) { - let addr = parseProxy(proxy); + const addr = parseProxy(proxy); return SOCKS.resolve({ host: addr.host, port: addr.port, diff --git a/lib/net/tcp-browser.js b/lib/net/tcp-browser.js index 1bff94263..4bdd7644d 100644 --- a/lib/net/tcp-browser.js +++ b/lib/net/tcp-browser.js @@ -15,7 +15,7 @@ tcp.createSocket = function createSocket(port, host, proxy) { }; tcp.createServer = function createServer() { - let server = new EventEmitter(); + const server = new EventEmitter(); server.listen = async function listen(port, host) { server.emit('listening'); diff --git a/lib/net/tcp.js b/lib/net/tcp.js index f2c1b558e..2866e5539 100644 --- a/lib/net/tcp.js +++ b/lib/net/tcp.js @@ -4,6 +4,8 @@ * https://github.com/bcoin-org/bcoin */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; const EventEmitter = require('events'); @@ -36,8 +38,8 @@ tcp.createSocket = function createSocket(port, host, proxy) { */ tcp.createServer = function createServer() { - let server = new net.Server(); - let ee = new EventEmitter(); + const server = new net.Server(); + const ee = new EventEmitter(); ee.listen = function listen(port, host) { return new Promise((resolve, reject) => { @@ -59,13 +61,14 @@ tcp.createServer = function createServer() { return server.address(); }; - ee.__defineGetter__('maxConnections', function() { - return server.maxConnections; - }); - - ee.__defineSetter__('maxConnections', function(value) { - server.maxConnections = value; - return server.maxConnections; + Object.defineProperty(ee, 'maxConnections', { + get() { + return server.maxConnections; + }, + set(value) { + server.maxConnections = value; + return server.maxConnections; + } }); server.on('listening', () => { diff --git a/lib/net/upnp.js b/lib/net/upnp.js index f435385d1..7a8293ca1 100644 --- a/lib/net/upnp.js +++ b/lib/net/upnp.js @@ -69,7 +69,7 @@ UPNP.RESPONSE_TIMEOUT = 1000; */ UPNP.prototype.cleanupJob = function cleanupJob() { - let job = this.job; + const job = this.job; assert(this.socket); assert(this.job); @@ -91,7 +91,7 @@ UPNP.prototype.cleanupJob = function cleanupJob() { */ UPNP.prototype.rejectJob = function rejectJob(err) { - let job = this.cleanupJob(); + const job = this.cleanupJob(); job.reject(err); }; @@ -102,7 +102,7 @@ UPNP.prototype.rejectJob = function rejectJob(err) { */ UPNP.prototype.resolveJob = function resolveJob(result) { - let job = this.cleanupJob(); + const job = this.cleanupJob(); job.resolve(result); }; @@ -137,7 +137,7 @@ UPNP.prototype.stopTimeout = function stopTimeout() { */ UPNP.prototype.discover = async function discover() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._discover(); } finally { @@ -151,23 +151,22 @@ UPNP.prototype.discover = async function discover() { * @returns {Promise} Location string. */ -UPNP.prototype._discover = async function discover() { - let socket = dgram.createSocket('udp4'); - let msg; +UPNP.prototype._discover = async function _discover() { + const socket = dgram.createSocket('udp4'); socket.on('error', (err) => { this.rejectJob(err); }); socket.on('message', (data, rinfo) => { - let msg = data.toString('utf8'); + const msg = data.toString('utf8'); this.handleMsg(msg); }); this.socket = socket; this.startTimeout(); - msg = '' + const msg = '' + 'M-SEARCH * HTTP/1.1\r\n' + `HOST: ${this.host}:${this.port}\r\n` + 'MAN: ssdp:discover\r\n' @@ -189,11 +188,10 @@ UPNP.prototype._discover = async function discover() { */ UPNP.prototype.handleMsg = async function handleMsg(msg) { - let headers; - if (!this.socket) return; + let headers; try { headers = UPNP.parseHeader(msg); } catch (e) { @@ -217,25 +215,24 @@ UPNP.prototype.handleMsg = async function handleMsg(msg) { */ UPNP.prototype.resolve = async function resolve(location, targets) { - let host = parseHost(location); - let res, xml, services, service; + const host = parseHost(location); if (!targets) targets = UPNP.WAN_SERVICES; - res = await request({ + const res = await request({ method: 'GET', uri: location, timeout: UPNP.RESPONSE_TIMEOUT, expect: 'xml' }); - xml = XMLElement.fromRaw(res.body); + const xml = XMLElement.fromRaw(res.body); - services = parseServices(xml); + const services = parseServices(xml); assert(services.length > 0, 'No services found.'); - service = extractServices(services, targets); + const service = extractServices(services, targets); assert(service, 'No service found.'); assert(service.serviceId, 'No service ID found.'); assert(service.serviceId.length > 0, 'No service ID found.'); @@ -261,27 +258,25 @@ UPNP.prototype.resolve = async function resolve(location, targets) { */ UPNP.parseHeader = function parseHeader(str) { - let lines = str.split(/\r?\n/); - let headers = {}; + const lines = str.split(/\r?\n/); + const headers = Object.create(null); for (let line of lines) { - let index, left, right; - line = line.trim(); if (line.length === 0) continue; - index = line.indexOf(':'); + const index = line.indexOf(':'); if (index === -1) { - left = line.toLowerCase(); + const left = line.toLowerCase(); headers[left] = ''; continue; } - left = line.substring(0, index); - right = line.substring(index + 1); + let left = line.substring(0, index); + let right = line.substring(index + 1); left = left.trim(); right = right.trim(); @@ -304,9 +299,9 @@ UPNP.parseHeader = function parseHeader(str) { */ UPNP.discover = async function discover(host, port, gateway, targets) { - let upnp = new UPNP(host, port, gateway); - let location = await upnp.discover(); - let service = await upnp.resolve(location, targets); + const upnp = new UPNP(host, port, gateway); + const location = await upnp.discover(); + const service = await upnp.resolve(location, targets); return new UPNPService(service); }; @@ -337,10 +332,10 @@ function UPNPService(options) { */ UPNPService.prototype.createRequest = function createRequest(action, args) { - let type = JSON.stringify(this.serviceType); + const type = JSON.stringify(this.serviceType); let params = ''; - for (let [key, value] of args) { + for (const [key, value] of args) { params += `<${key}>`; if (value != null) params += value; @@ -369,26 +364,25 @@ UPNPService.prototype.createRequest = function createRequest(action, args) { */ UPNPService.prototype.soapRequest = async function soapRequest(action, args) { - let type = this.serviceType; - let req = this.createRequest(action, args); - let res, xml, err; + const type = this.serviceType; + const req = this.createRequest(action, args); - res = await request({ + const res = await request({ method: 'POST', uri: this.controlURL, timeout: UPNP.RESPONSE_TIMEOUT, expect: 'xml', headers: { 'Content-Type': 'text/xml; charset="utf-8"', - 'Content-Length': Buffer.byteLength(req, 'utf8') + '', + 'Content-Length': Buffer.byteLength(req, 'utf8').toString(10), 'Connection': 'close', 'SOAPAction': JSON.stringify(`${type}#${action}`) }, body: req }); - xml = XMLElement.fromRaw(res.body); - err = findError(xml); + const xml = XMLElement.fromRaw(res.body); + const err = findError(xml); if (err) throw err; @@ -402,9 +396,9 @@ UPNPService.prototype.soapRequest = async function soapRequest(action, args) { */ UPNPService.prototype.getExternalIP = async function getExternalIP() { - let action = 'GetExternalIPAddress'; - let xml = await this.soapRequest(action, []); - let ip = findIP(xml); + const action = 'GetExternalIPAddress'; + const xml = await this.soapRequest(action, []); + const ip = findIP(xml); if (!ip) throw new Error('Could not find external IP.'); @@ -421,14 +415,13 @@ UPNPService.prototype.getExternalIP = async function getExternalIP() { */ UPNPService.prototype.addPortMapping = async function addPortMapping(remote, src, dest) { - let action = 'AddPortMapping'; - let local = IP.getPrivate(); - let xml, child; + const action = 'AddPortMapping'; + const local = IP.getPrivate(); if (local.length === 0) throw new Error('Cannot determine local IP.'); - xml = await this.soapRequest(action, [ + const xml = await this.soapRequest(action, [ ['NewRemoteHost', remote], ['NewExternalPort', src], ['NewProtocol', 'TCP'], @@ -439,7 +432,7 @@ UPNPService.prototype.addPortMapping = async function addPortMapping(remote, src ['NewLeaseDuration', 0] ]); - child = xml.find('AddPortMappingResponse'); + const child = xml.find('AddPortMappingResponse'); if (!child) throw new Error('Port mapping failed.'); @@ -455,16 +448,15 @@ UPNPService.prototype.addPortMapping = async function addPortMapping(remote, src */ UPNPService.prototype.removePortMapping = async function removePortMapping(remote, port) { - let action = 'DeletePortMapping'; - let xml, child; + const action = 'DeletePortMapping'; - xml = await this.soapRequest(action, [ + const xml = await this.soapRequest(action, [ ['NewRemoteHost', remote], ['NewExternalPort', port], ['NewProtocol', 'TCP'] ]); - child = xml.find('DeletePortMappingResponse'); + const child = xml.find('DeletePortMappingResponse'); if (!child) throw new Error('Port unmapping failed.'); @@ -492,16 +484,17 @@ function XMLElement(name) { */ XMLElement.fromRaw = function fromRaw(xml) { - let sentinel = new XMLElement(''); + const sentinel = new XMLElement(''); + const stack = [sentinel]; + let current = sentinel; - let stack = []; let decl = false; - let m; - stack.push(sentinel); + while (xml.length > 0) { + let m; - while (xml.length) { - if (m = /^<\?xml[^<>]*\?>/i.exec(xml)) { + m = /^<\?xml[^<>]*\?>/i.exec(xml); + if (m) { xml = xml.substring(m[0].length); assert(current === sentinel, 'XML declaration inside element.'); assert(!decl, 'XML declaration seen twice.'); @@ -509,13 +502,14 @@ XMLElement.fromRaw = function fromRaw(xml) { continue; } - if (m = /^<([\w:]+)[^<>]*?(\/?)>/i.exec(xml)) { - let name = m[1]; - let trailing = m[2] === '/'; - let element = new XMLElement(name); - + m = /^<([\w:]+)[^<>]*?(\/?)>/i.exec(xml); + if (m) { xml = xml.substring(m[0].length); + const name = m[1]; + const trailing = m[2] === '/'; + const element = new XMLElement(name); + if (trailing) { current.add(element); continue; @@ -528,14 +522,15 @@ XMLElement.fromRaw = function fromRaw(xml) { continue; } - if (m = /^<\/([\w:]+)[^<>]*>/i.exec(xml)) { - let name = m[1]; - let element; - + m = /^<\/([\w:]+)[^<>]*>/i.exec(xml); + if (m) { xml = xml.substring(m[0].length); + const name = m[1]; + assert(stack.length !== 1, 'No start tag.'); - element = stack.pop(); + + const element = stack.pop(); assert(element.name === name, 'Tag mismatch.'); current = stack[stack.length - 1]; @@ -546,9 +541,10 @@ XMLElement.fromRaw = function fromRaw(xml) { continue; } - if (m = /^([^<]+)/i.exec(xml)) { - let text = m[1]; + m = /^([^<]+)/i.exec(xml); + if (m) { xml = xml.substring(m[0].length); + const text = m[1]; current.text = text.trim(); continue; } @@ -590,7 +586,7 @@ XMLElement.prototype.collect = function collect(name) { */ XMLElement.prototype._collect = function _collect(name, result) { - for (let child of this.children) { + for (const child of this.children) { if (child.type === name) { result.push(child); continue; @@ -618,6 +614,8 @@ XMLElement.prototype.find = function find(name) { if (child) return child; } + + return null; }; /* @@ -625,19 +623,19 @@ XMLElement.prototype.find = function find(name) { */ function parseServices(el) { - let children = el.collect('service'); - let services = []; + const children = el.collect('service'); + const services = []; - for (let child of children) + for (const child of children) services.push(parseService(child)); return services; } function parseService(el) { - let service = {}; + const service = Object.create(null); - for (let child of el.children) { + for (const child of el.children) { if (child.children.length > 0) continue; @@ -648,43 +646,47 @@ function parseService(el) { } function findService(services, name) { - for (let service of services) { + for (const service of services) { if (service.serviceType === name) return service; } + + return null; } function extractServices(services, targets) { - for (let name of targets) { - let service = findService(services, name); + for (const name of targets) { + const service = findService(services, name); if (service) return service; } + + return null; } function findIP(el) { - let child = el.find('NewExternalIPAddress'); + const child = el.find('NewExternalIPAddress'); if (!child) - return; + return null; return IP.normalize(child.text); } function findError(el) { - let child = el.find('UPnPError'); - let code = -1; - let desc = 'Unknown'; - let ccode, cdesc; + const child = el.find('UPnPError'); if (!child) - return; + return null; - ccode = child.find('errorCode'); - cdesc = child.find('errorDescription'); + let code = -1; + const ccode = child.find('errorCode'); if (ccode && /^\d+$/.test(ccode.text)) - code = +ccode.text; + code = parseInt(ccode.text, 10); + + let desc = 'Unknown'; + const cdesc = child.find('errorDescription'); if (cdesc) desc = cdesc.text; @@ -697,7 +699,7 @@ function findError(el) { */ function parseHost(uri) { - let {protocol, host} = url.parse(uri); + const {protocol, host} = url.parse(uri); assert(protocol === 'http:' || protocol === 'https:', 'Bad URL for location.'); diff --git a/lib/node/config.js b/lib/node/config.js index af227a22b..549fffb9c 100644 --- a/lib/node/config.js +++ b/lib/node/config.js @@ -7,9 +7,10 @@ 'use strict'; const assert = require('assert'); -const path = require('path'); +const Path = require('path'); const os = require('os'); const fs = require('../utils/fs'); +const util = require('../utils/util'); const HOME = os.homedir ? os.homedir() : '/'; /** @@ -28,13 +29,14 @@ function Config(module) { this.module = module; this.network = 'main'; - this.prefix = path.join(HOME, `.${module}`); + this.prefix = Path.join(HOME, `.${module}`); this.options = Object.create(null); this.data = Object.create(null); this.env = Object.create(null); this.args = Object.create(null); this.argv = []; + this.pass = []; this.query = Object.create(null); this.hash = Object.create(null); } @@ -45,16 +47,9 @@ function Config(module) { */ Config.alias = { - conf: {}, - env: { - 'seed': 'seeds', - 'node': 'nodes' - }, - arg: { - 'seed': 'seeds', - 'node': 'nodes', - 'n': 'network' - } + 'seed': 'seeds', + 'node': 'nodes', + 'n': 'network' }; /** @@ -63,10 +58,8 @@ Config.alias = { */ Config.prototype.inject = function inject(options) { - let keys = Object.keys(options); - - for (let key of keys) { - let value = options[key]; + for (const key of Object.keys(options)) { + const value = options[key]; switch (key) { case 'hash': @@ -110,13 +103,12 @@ Config.prototype.load = function load(options) { */ Config.prototype.open = function open(file) { - let path, text; - if (fs.unsupported) return; - path = this.getFile(file); + const path = this.getFile(file); + let text; try { text = fs.readFileSync(path, 'utf8'); } catch (e) { @@ -143,7 +135,8 @@ Config.prototype.set = function set(key, value) { if (value == null) return; - key = key.toLowerCase().replace(/-/g, ''); + key = key.replace(/-/g, ''); + key = key.toLowerCase(); this.options[key] = value; }; @@ -164,7 +157,8 @@ Config.prototype.has = function has(key) { assert(typeof key === 'string', 'Key must be a string.'); - key = key.toLowerCase().replace(/-/g, ''); + key = key.replace(/-/g, ''); + key = key.toLowerCase(); if (this.hash[key] != null) return true; @@ -195,15 +189,13 @@ Config.prototype.has = function has(key) { */ Config.prototype.get = function get(key, fallback) { - let keys, value; - if (fallback === undefined) fallback = null; if (Array.isArray(key)) { - keys = key; - for (let key of keys) { - value = this.get(key); + const keys = key; + for (const key of keys) { + const value = this.get(key); if (value !== null) return value; } @@ -212,14 +204,20 @@ Config.prototype.get = function get(key, fallback) { if (typeof key === 'number') { assert(key >= 0, 'Index must be positive.'); + if (key >= this.argv.length) return fallback; - return this.argv[key]; + + if (this.argv[key] != null) + return this.argv[key]; + + return fallback; } assert(typeof key === 'string', 'Key must be a string.'); - key = key.toLowerCase().replace(/-/g, ''); + key = key.replace(/-/g, ''); + key = key.toLowerCase(); if (this.hash[key] != null) return this.hash[key]; @@ -242,6 +240,21 @@ Config.prototype.get = function get(key, fallback) { return fallback; }; +/** + * Get a value's type. + * @param {String} key + * @returns {String} + */ + +Config.prototype.typeOf = function typeOf(key) { + const value = this.get(key); + + if (value === null) + return 'null'; + + return typeof value; +}; + /** * Get a config option (as a string). * @param {String} key @@ -250,7 +263,7 @@ Config.prototype.get = function get(key, fallback) { */ Config.prototype.str = function str(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -259,19 +272,19 @@ Config.prototype.str = function str(key, fallback) { return fallback; if (typeof value !== 'string') - throw new Error(`${key} must be a string.`); + throw new Error(`${fmt(key)} must be a string.`); return value; }; /** - * Get a config option (as a number). + * Get a config option (as an integer). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Config.prototype.num = function num(key, fallback) { +Config.prototype.int = function int(key, fallback) { let value = this.get(key); if (fallback === undefined) @@ -282,17 +295,43 @@ Config.prototype.num = function num(key, fallback) { if (typeof value !== 'string') { if (typeof value !== 'number') - throw new Error(`${key} must be a positive integer.`); + throw new Error(`${fmt(key)} must be an int.`); + + if (!Number.isSafeInteger(value)) + throw new Error(`${fmt(key)} must be an int.`); + return value; } - if (!/^\d+$/.test(value)) - throw new Error(`${key} must be a positive integer.`); + if (!/^\-?\d+$/.test(value)) + throw new Error(`${fmt(key)} must be an int.`); value = parseInt(value, 10); - if (!isFinite(value)) - throw new Error(`${key} must be a positive integer.`); + if (!Number.isSafeInteger(value)) + throw new Error(`${fmt(key)} must be an int.`); + + return value; +}; + +/** + * Get a config option (as a unsigned integer). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Config.prototype.uint = function uint(key, fallback) { + const value = this.int(key); + + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; + + if (value < 0) + throw new Error(`${fmt(key)} must be a uint.`); return value; }; @@ -304,7 +343,7 @@ Config.prototype.num = function num(key, fallback) { * @returns {Number|null} */ -Config.prototype.flt = function flt(key, fallback) { +Config.prototype.float = function float(key, fallback) { let value = this.get(key); if (fallback === undefined) @@ -315,30 +354,37 @@ Config.prototype.flt = function flt(key, fallback) { if (typeof value !== 'string') { if (typeof value !== 'number') - throw new Error(`${key} must be a float.`); + throw new Error(`${fmt(key)} must be a float.`); + + if (!isFinite(value)) + throw new Error(`${fmt(key)} must be a float.`); + return value; } - if (!/^\d*(?:\.\d*)?$/.test(value)) - throw new Error(`${key} must be a float.`); + if (!/^\-?\d*(?:\.\d*)?$/.test(value)) + throw new Error(`${fmt(key)} must be a float.`); + + if (!/\d/.test(value)) + throw new Error(`${fmt(key)} must be a float.`); value = parseFloat(value); if (!isFinite(value)) - throw new Error(`${key} must be a float.`); + throw new Error(`${fmt(key)} must be a float.`); return value; }; /** - * Get a value (as a satoshi number or btc string). + * Get a config option (as a positive float). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Config.prototype.amt = function amt(key, fallback) { - let value = this.get(key); +Config.prototype.ufloat = function ufloat(key, fallback) { + const value = this.float(key); if (fallback === undefined) fallback = null; @@ -346,24 +392,55 @@ Config.prototype.amt = function amt(key, fallback) { if (value === null) return fallback; - if (typeof value !== 'string') { - if (typeof value !== 'number') - throw new Error(`${key} must be an amount.`); - return value; + if (value < 0) + throw new Error(`${fmt(key)} must be a positive float.`); + + return value; +}; + +/** + * Get a value (as a fixed number). + * @param {String} key + * @param {Number?} exp + * @param {Object?} fallback + * @returns {Number|null} + */ + +Config.prototype.fixed = function fixed(key, exp, fallback) { + const value = this.float(key); + + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; + + try { + return util.fromFloat(value, exp || 0); + } catch (e) { + throw new Error(`${fmt(key)} must be a fixed number.`); } +}; - if (!/^\d+(\.\d{0,8})?$/.test(value)) - throw new Error(`${key} must be an amount.`); +/** + * Get a value (as a positive fixed number). + * @param {String} key + * @param {Number?} exp + * @param {Object?} fallback + * @returns {Number|null} + */ - value = parseFloat(value); +Config.prototype.ufixed = function ufixed(key, exp, fallback) { + const value = this.fixed(key, exp); - if (!isFinite(value)) - throw new Error(`${key} must be an amount.`); + if (fallback === undefined) + fallback = null; - value *= 1e8; + if (value === null) + return fallback; - if (value % 1 !== 0 || value < 0 || value > 0x1fffffffffffff) - throw new Error(`${key} must be an amount (uint64).`); + if (value < 0) + throw new Error(`${fmt(key)} must be a positive fixed number.`); return value; }; @@ -376,7 +453,7 @@ Config.prototype.amt = function amt(key, fallback) { */ Config.prototype.bool = function bool(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -384,9 +461,18 @@ Config.prototype.bool = function bool(key, fallback) { if (value === null) return fallback; + // Bitcoin Core compat. + if (typeof value === 'number') { + if (value === 1) + return true; + + if (value === 0) + return false; + } + if (typeof value !== 'string') { if (typeof value !== 'boolean') - throw new Error(`${key} must be a boolean.`); + throw new Error(`${fmt(key)} must be a boolean.`); return value; } @@ -396,7 +482,7 @@ Config.prototype.bool = function bool(key, fallback) { if (value === 'false' || value === '0') return false; - throw new Error(`${key} must be a boolean.`); + throw new Error(`${fmt(key)} must be a boolean.`); }; /** @@ -406,9 +492,11 @@ Config.prototype.bool = function bool(key, fallback) { * @returns {Buffer|null} */ -Config.prototype.buf = function buf(key, fallback) { - let value = this.get(key); - let data; +Config.prototype.buf = function buf(key, fallback, enc) { + const value = this.get(key); + + if (!enc) + enc = 'hex'; if (fallback === undefined) fallback = null; @@ -418,14 +506,14 @@ Config.prototype.buf = function buf(key, fallback) { if (typeof value !== 'string') { if (!Buffer.isBuffer(value)) - throw new Error(`${key} must be a buffer.`); + throw new Error(`${fmt(key)} must be a buffer.`); return value; } - data = Buffer.from(value, 'hex'); + const data = Buffer.from(value, enc); - if (data.length !== value.length / 2) - throw new Error(`${key} must be a hex string.`); + if (data.length !== Buffer.byteLength(value, enc)) + throw new Error(`${fmt(key)} must be a ${enc} string.`); return data; }; @@ -438,8 +526,7 @@ Config.prototype.buf = function buf(key, fallback) { */ Config.prototype.array = function array(key, fallback) { - let value = this.get(key); - let result, parts; + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -449,14 +536,14 @@ Config.prototype.array = function array(key, fallback) { if (typeof value !== 'string') { if (!Array.isArray(value)) - throw new Error(`${key} must be an array.`); + throw new Error(`${fmt(key)} must be an array.`); return value; } - parts = value.trim().split(/\s*,\s*/); - result = []; + const parts = value.trim().split(/\s*,\s*/); + const result = []; - for (let part of parts) { + for (const part of parts) { if (part.length === 0) continue; @@ -474,7 +561,7 @@ Config.prototype.array = function array(key, fallback) { */ Config.prototype.obj = function obj(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -482,8 +569,8 @@ Config.prototype.obj = function obj(key, fallback) { if (value === null) return fallback; - if (!value || typeof value !== 'object') - throw new Error(`${key} must be an object.`); + if (typeof value !== 'object') + throw new Error(`${fmt(key)} must be an object.`); return value; }; @@ -496,7 +583,7 @@ Config.prototype.obj = function obj(key, fallback) { */ Config.prototype.func = function func(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -504,8 +591,8 @@ Config.prototype.func = function func(key, fallback) { if (value === null) return fallback; - if (!value || typeof value !== 'function') - throw new Error(`${key} must be a function.`); + if (typeof value !== 'function') + throw new Error(`${fmt(key)} must be a function.`); return value; }; @@ -517,7 +604,7 @@ Config.prototype.func = function func(key, fallback) { * @returns {String|null} */ -Config.prototype.path = function _path(key, fallback) { +Config.prototype.path = function path(key, fallback) { let value = this.str(key); if (fallback === undefined) @@ -528,16 +615,16 @@ Config.prototype.path = function _path(key, fallback) { switch (value[0]) { case '~': // home dir - value = path.join(HOME, value.substring(1)); + value = Path.join(HOME, value.substring(1)); break; case '@': // prefix - value = path.join(this.prefix, value.substring(1)); + value = Path.join(this.prefix, value.substring(1)); break; default: // cwd break; } - return path.normalize(value); + return Path.normalize(value); }; /** @@ -548,7 +635,7 @@ Config.prototype.path = function _path(key, fallback) { */ Config.prototype.mb = function mb(key, fallback) { - let value = this.num(key); + const value = this.uint(key); if (fallback === undefined) fallback = null; @@ -584,24 +671,24 @@ Config.prototype.getNetwork = function getNetwork() { Config.prototype.getPrefix = function getPrefix() { let prefix = this.str('prefix'); - let network; if (prefix) { if (prefix[0] === '~') - prefix = path.join(HOME, prefix.substring(1)); + prefix = Path.join(HOME, prefix.substring(1)); return prefix; } - prefix = path.join(HOME, `.${this.module}`); - network = this.str('network'); + prefix = Path.join(HOME, `.${this.module}`); + + const network = this.str('network'); if (network) { assert(isAlpha(network), 'Bad network.'); if (network !== 'main') - prefix = path.join(prefix, network); + prefix = Path.join(prefix, network); } - return path.normalize(prefix); + return Path.normalize(prefix); }; /** @@ -612,12 +699,12 @@ Config.prototype.getPrefix = function getPrefix() { */ Config.prototype.getFile = function getFile(file) { - let name = this.str('config'); + const name = this.str('config'); if (name) return name; - return path.join(this.prefix, file); + return Path.join(this.prefix, file); }; /** @@ -639,7 +726,7 @@ Config.prototype.ensure = function ensure() { */ Config.prototype.location = function location(file) { - return path.join(this.prefix, file); + return Path.join(this.prefix, file); }; /** @@ -649,50 +736,71 @@ Config.prototype.location = function location(file) { */ Config.prototype.parseConfig = function parseConfig(text) { - let parts; - assert(typeof text === 'string', 'Config must be text.'); - text = text.trim(); - parts = text.split(/\n+/); + if (text.charCodeAt(0) === 0xfeff) + text = text.substring(1); + + text = text.replace(/\r\n/g, '\n'); + text = text.replace(/\r/g, '\n'); + text = text.replace(/\\\n/g, ''); + + let colons = true; + let seen = false; + let num = 0; - for (let line of parts) { - let key, value, eq, col, alias; + for (const chunk of text.split('\n')) { + const line = chunk.trim(); - line = line.trim(); + num += 1; if (line.length === 0) continue; - if (/^\s*#/.test(line)) + if (line[0] === '#') continue; - eq = line.indexOf('='); - col = line.indexOf(':'); + const equal = line.indexOf('='); + const colon = line.indexOf(':'); + + let index = -1; + + if (colon !== -1 && (colon < equal || equal === -1)) { + if (seen && !colons) + throw new Error(`Expected '=' on line ${num}: "${line}".`); - if (col !== -1 && (col < eq || eq === -1)) - eq = col; + index = colon; + seen = true; + colons = true; + } else if (equal !== -1) { + if (seen && colons) + throw new Error(`Expected ':' on line ${num}: "${line}".`); - if (eq === -1) { - key = line.trim(); - value = ''; + index = equal; + seen = true; + colons = false; } else { - key = line.substring(0, eq).trim(); - value = line.substring(eq + 1).trim(); + const symbol = colons ? ':' : '='; + throw new Error(`Expected '${symbol}' on line ${num}: "${line}".`); } - key = key.replace(/\-/g, '').toLowerCase(); + let key = line.substring(0, index).trim(); - alias = Config.alias.conf[key]; - if (alias) - key = alias; + key = key.replace(/\-/g, ''); - if (key.length === 0) - continue; + if (!isLowerKey(key)) + throw new Error(`Invalid option on line ${num}: ${key}.`); + + const value = line.substring(index + 1).trim(); if (value.length === 0) continue; + const alias = Config.alias[key]; + + if (alias) + key = alias; + this.data[key] = value; } }; @@ -704,74 +812,116 @@ Config.prototype.parseConfig = function parseConfig(text) { */ Config.prototype.parseArg = function parseArg(argv) { - let key; - if (!argv || typeof argv !== 'object') argv = process.argv; assert(Array.isArray(argv)); + let last = null; + let pass = false; + for (let i = 2; i < argv.length; i++) { - let arg = argv[i]; - let value, alias, equals; + const arg = argv[i]; assert(typeof arg === 'string'); + if (arg === '--') { + pass = true; + continue; + } + + if (pass) { + this.pass.push(arg); + continue; + } + + if (arg.length === 0) { + last = null; + continue; + } + if (arg.indexOf('--') === 0) { - // e.g. --opt - arg = arg.split('='); - key = arg[0]; + const index = arg.indexOf('='); + + let key = null; + let value = null; + let empty = false; - if (arg.length > 1) { + if (index !== -1) { // e.g. --opt=val - value = arg.slice(1).join('=').trim(); - equals = true; + key = arg.substring(2, index); + value = arg.substring(index + 1); + last = null; + empty = false; } else { + // e.g. --opt + key = arg.substring(2); value = 'true'; - equals = false; + last = null; + empty = true; } key = key.replace(/\-/g, ''); - if (key.length === 0) - continue; + if (!isLowerKey(key)) + throw new Error(`Invalid argument: --${key}.`); if (value.length === 0) continue; - alias = Config.alias.arg[key]; - if (alias) - key = alias; + // Do not allow one-letter aliases. + if (key.length > 1) { + const alias = Config.alias[key]; + if (alias) + key = alias; + } this.args[key] = value; + if (empty) + last = key; + continue; } if (arg[0] === '-') { // e.g. -abc - arg = arg.substring(1); + last = null; + + for (let j = 1; j < arg.length; j++) { + let key = arg[j]; + + if ((key < 'a' || key > 'z') + && (key < 'A' || key > 'Z') + && (key < '0' || key > '9') + && key !== '?') { + throw new Error(`Invalid argument: -${key}.`); + } + + const alias = Config.alias[key]; - for (key of arg) { - alias = Config.alias.arg[key]; if (alias) key = alias; + this.args[key] = 'true'; - equals = false; + + last = key; } continue; } // e.g. foo - value = arg.trim(); + const value = arg; - if (value.length === 0) + if (value.length === 0) { + last = null; continue; + } - if (key && !equals) { - this.args[key] = value; - key = null; + if (last) { + this.args[last] = value; + last = null; } else { this.argv.push(value); } @@ -787,7 +937,6 @@ Config.prototype.parseArg = function parseArg(argv) { Config.prototype.parseEnv = function parseEnv(env) { let prefix = this.module; - let keys; prefix = prefix.toUpperCase(); prefix = prefix.replace(/-/g, '_'); @@ -798,30 +947,31 @@ Config.prototype.parseEnv = function parseEnv(env) { assert(env && typeof env === 'object'); - keys = Object.keys(env); + for (let key of Object.keys(env)) { + const value = env[key]; - for (let key of keys) { - let value, alias; + assert(typeof value === 'string'); - if (key.indexOf(prefix) !== 0) + if (!util.startsWith(key, prefix)) continue; - assert(typeof env[key] === 'string'); - - value = env[key].trim(); - key = key.substring(prefix.length); - key = key.replace(/_/g, '').toLowerCase(); + key = key.replace(/_/g, ''); - if (key.length === 0) + if (!isUpperKey(key)) continue; if (value.length === 0) continue; - alias = Config.alias.env[key]; - if (alias) - key = alias; + key = key.toLowerCase(); + + // Do not allow one-letter aliases. + if (key.length > 1) { + const alias = Config.alias[key]; + if (alias) + key = alias; + } this.env[key] = value; } @@ -874,34 +1024,35 @@ Config.prototype.parseHash = function parseHash(hash) { */ Config.prototype.parseForm = function parseForm(query, map) { - let parts; - assert(typeof query === 'string'); if (query.length === 0) return; - if (query[0] === '?' || query[0] === '#') - query = query.substring(1); + let ch = '?'; - parts = query.split('&'); + if (map === this.hash) + ch = '#'; - for (let pair of parts) { - let index = pair.indexOf('='); - let key, value, alias; + if (query[0] === ch) + query = query.substring(1); - if (index === -1) { - key = pair; - value = ''; - } else { + for (const pair of query.split('&')) { + const index = pair.indexOf('='); + + let key, value; + if (index !== -1) { key = pair.substring(0, index); value = pair.substring(index + 1); + } else { + key = pair; + value = 'true'; } key = unescape(key); - key = key.replace(/\-/g, '').toLowerCase(); + key = key.replace(/\-/g, ''); - if (key.length === 0) + if (!isLowerKey(key)) continue; value = unescape(value); @@ -909,7 +1060,8 @@ Config.prototype.parseForm = function parseForm(query, map) { if (value.length === 0) continue; - alias = Config.alias.env[key]; + const alias = Config.alias[key]; + if (alias) key = alias; @@ -921,6 +1073,16 @@ Config.prototype.parseForm = function parseForm(query, map) { * Helpers */ +function fmt(key) { + if (Array.isArray(key)) + key = key[0]; + + if (typeof key === 'number') + return `Argument #${key}`; + + return key; +} + function unescape(str) { try { str = decodeURIComponent(str); @@ -933,13 +1095,25 @@ function unescape(str) { } function isAlpha(str) { - if (typeof str !== 'string') + return /^[a-z0-9]+$/.test(str); +} + +function isKey(key) { + return /^[a-zA-Z0-9]+$/.test(key); +} + +function isLowerKey(key) { + if (!isKey(key)) return false; - if (!/^[a-z0-9]+$/.test(str)) + return !/[A-Z]/.test(key); +} + +function isUpperKey(key) { + if (!isKey(key)) return false; - return true; + return !/[a-z]/.test(key); } /* diff --git a/lib/node/fullnode.js b/lib/node/fullnode.js index d66cd5bb7..7be094159 100644 --- a/lib/node/fullnode.js +++ b/lib/node/fullnode.js @@ -7,8 +7,6 @@ 'use strict'; -const util = require('../utils/util'); -const Node = require('./node'); const Chain = require('../blockchain/chain'); const Fees = require('../mempool/fees'); const Mempool = require('../mempool/mempool'); @@ -16,6 +14,7 @@ const Pool = require('../net/pool'); const Miner = require('../mining/miner'); const HTTPServer = require('../http/server'); const RPC = require('../http/rpc'); +const Node = require('./node'); /** * Respresents a fullnode complete with a @@ -54,7 +53,7 @@ function FullNode(options) { workers: this.workers, db: this.config.str('db'), prefix: this.config.prefix, - maxFiles: this.config.num('max-files'), + maxFiles: this.config.uint('max-files'), cacheSize: this.config.mb('cache-size'), forceFlags: this.config.bool('force-flags'), bip91: this.config.bool('bip91'), @@ -62,7 +61,7 @@ function FullNode(options) { prune: this.config.bool('prune'), checkpoints: this.config.bool('checkpoints'), coinCache: this.config.mb('coin-cache'), - entryCache: this.config.num('entry-cache'), + entryCache: this.config.uint('entry-cache'), indexTX: this.config.bool('index-tx'), indexAddress: this.config.bool('index-address') }); @@ -83,7 +82,7 @@ function FullNode(options) { persistent: this.config.bool('persistent-mempool'), maxSize: this.config.mb('mempool-size'), limitFree: this.config.bool('limit-free'), - limitFreeRelay: this.config.num('limit-free-relay'), + limitFreeRelay: this.config.uint('limit-free-relay'), requireStandard: this.config.bool('require-standard'), rejectAbsurdFees: this.config.bool('reject-absurd-fees'), replaceByFee: this.config.bool('replace-by-fee'), @@ -103,8 +102,8 @@ function FullNode(options) { bip151: this.config.bool('bip151'), bip150: this.config.bool('bip150'), identityKey: this.config.buf('identity-key'), - maxOutbound: this.config.num('max-outbound'), - maxInbound: this.config.num('max-inbound'), + maxOutbound: this.config.uint('max-outbound'), + maxInbound: this.config.uint('max-inbound'), proxy: this.config.str('proxy'), onion: this.config.bool('onion'), upnp: this.config.bool('upnp'), @@ -112,9 +111,9 @@ function FullNode(options) { nodes: this.config.array('nodes'), only: this.config.array('only'), publicHost: this.config.str('public-host'), - publicPort: this.config.num('public-port'), + publicPort: this.config.uint('public-port'), host: this.config.str('host'), - port: this.config.num('port'), + port: this.config.uint('port'), listen: this.config.bool('listen'), persistent: this.config.bool('persistent') }); @@ -129,9 +128,9 @@ function FullNode(options) { address: this.config.array('coinbase-address'), coinbaseFlags: this.config.str('coinbase-flags'), preverify: this.config.bool('preverify'), - maxWeight: this.config.num('max-weight'), - reservedWeight: this.config.num('reserved-weight'), - reservedSigops: this.config.num('reserved-sigops') + maxWeight: this.config.uint('max-weight'), + reservedWeight: this.config.uint('reserved-weight'), + reservedSigops: this.config.uint('reserved-sigops') }); // RPC needs access to the node. @@ -148,7 +147,7 @@ function FullNode(options) { keyFile: this.config.path('ssl-key'), certFile: this.config.path('ssl-cert'), host: this.config.str('http-host'), - port: this.config.num('http-port'), + port: this.config.uint('http-port'), apiKey: this.config.str('api-key'), noAuth: this.config.bool('no-auth') }); @@ -157,7 +156,7 @@ function FullNode(options) { this._init(); } -util.inherits(FullNode, Node); +Object.setPrototypeOf(FullNode.prototype, Node.prototype); /** * Initialize the node. @@ -217,7 +216,7 @@ FullNode.prototype._init = function _init() { * @returns {Promise} */ -FullNode.prototype._open = async function open() { +FullNode.prototype._open = async function _open() { await this.chain.open(); await this.mempool.open(); await this.miner.open(); @@ -237,7 +236,7 @@ FullNode.prototype._open = async function open() { * @returns {Promise} */ -FullNode.prototype._close = async function close() { +FullNode.prototype._close = async function _close() { if (this.http) await this.http.close(); @@ -379,16 +378,16 @@ FullNode.prototype.getBlock = function getBlock(hash) { * @returns {Promise} - Returns {@link Coin}. */ -FullNode.prototype.getCoin = function getCoin(hash, index) { - let coin = this.mempool.getCoin(hash, index); +FullNode.prototype.getCoin = async function getCoin(hash, index) { + const coin = this.mempool.getCoin(hash, index); if (coin) - return Promise.resolve(coin); + return coin; if (this.mempool.isSpent(hash, index)) - return Promise.resolve(); + return null; - return this.chain.db.getCoin(hash, index); + return await this.chain.db.getCoin(hash, index); }; /** @@ -399,13 +398,12 @@ FullNode.prototype.getCoin = function getCoin(hash, index) { */ FullNode.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) { - let mempool = this.mempool.getCoinsByAddress(addrs); - let chain = await this.chain.db.getCoinsByAddress(addrs); - let out = []; - let coin; + const mempool = this.mempool.getCoinsByAddress(addrs); + const chain = await this.chain.db.getCoinsByAddress(addrs); + const out = []; - for (coin of chain) { - let spent = this.mempool.isSpent(coin.hash, coin.index); + for (const coin of chain) { + const spent = this.mempool.isSpent(coin.hash, coin.index); if (spent) continue; @@ -413,7 +411,7 @@ FullNode.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) { out.push(coin); } - for (coin of mempool) + for (const coin of mempool) out.push(coin); return out; @@ -426,9 +424,9 @@ FullNode.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) { * @returns {Promise} - Returns {@link TXMeta}[]. */ -FullNode.prototype.getMetaByAddress = async function getTXByAddress(addrs) { - let mempool = this.mempool.getMetaByAddress(addrs); - let chain = await this.chain.db.getMetaByAddress(addrs); +FullNode.prototype.getMetaByAddress = async function getMetaByAddress(addrs) { + const mempool = this.mempool.getMetaByAddress(addrs); + const chain = await this.chain.db.getMetaByAddress(addrs); return chain.concat(mempool); }; @@ -439,7 +437,7 @@ FullNode.prototype.getMetaByAddress = async function getTXByAddress(addrs) { */ FullNode.prototype.getMeta = async function getMeta(hash) { - let meta = this.mempool.getMeta(hash); + const meta = this.mempool.getMeta(hash); if (meta) return meta; @@ -467,10 +465,10 @@ FullNode.prototype.getMetaView = async function getMetaView(meta) { */ FullNode.prototype.getTXByAddress = async function getTXByAddress(addrs) { - let mtxs = await this.getMetaByAddress(addrs); - let out = []; + const mtxs = await this.getMetaByAddress(addrs); + const out = []; - for (let mtx of mtxs) + for (const mtx of mtxs) out.push(mtx.tx); return out; @@ -483,9 +481,11 @@ FullNode.prototype.getTXByAddress = async function getTXByAddress(addrs) { */ FullNode.prototype.getTX = async function getTX(hash) { - let mtx = await this.getMeta(hash); + const mtx = await this.getMeta(hash); + if (!mtx) - return; + return null; + return mtx.tx; }; diff --git a/lib/node/logger.js b/lib/node/logger.js index 2cf5dab0e..189d5fffb 100644 --- a/lib/node/logger.js +++ b/lib/node/logger.js @@ -33,7 +33,7 @@ function Logger(options) { this.closing = false; this.filename = null; this.stream = null; - this.contexts = {}; + this.contexts = Object.create(null); this.locker = new Lock(); if (options) @@ -45,7 +45,7 @@ function Logger(options) { * @const {Boolean} */ -Logger.HAS_TTY = !!(process.stdout && process.stdout.isTTY); +Logger.HAS_TTY = Boolean(process.stdout && process.stdout.isTTY); /** * Maximum file size. @@ -161,7 +161,7 @@ Logger.prototype.set = function set(options) { */ Logger.prototype.open = async function open() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._open(); } finally { @@ -175,7 +175,7 @@ Logger.prototype.open = async function open() { * @returns {Promise} */ -Logger.prototype._open = async function open() { +Logger.prototype._open = async function _open() { if (!this.filename) { this.closed = false; return; @@ -206,7 +206,7 @@ Logger.prototype._open = async function open() { */ Logger.prototype.close = async function close() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._close(); } finally { @@ -220,7 +220,7 @@ Logger.prototype.close = async function close() { * @returns {Promise} */ -Logger.prototype._close = async function close() { +Logger.prototype._close = async function _close() { if (this.timer != null) { co.clearTimeout(this.timer); this.timer = null; @@ -253,9 +253,6 @@ Logger.prototype._close = async function close() { */ Logger.prototype.truncate = async function truncate() { - let maxSize = Logger.MAX_FILE_SIZE; - let stat, data, fd; - if (!this.filename) return; @@ -264,6 +261,7 @@ Logger.prototype.truncate = async function truncate() { assert(!this.stream); + let stat; try { stat = await fs.stat(this.filename); } catch (e) { @@ -272,14 +270,16 @@ Logger.prototype.truncate = async function truncate() { throw e; } + const maxSize = Logger.MAX_FILE_SIZE; + if (stat.size <= maxSize + (maxSize / 10)) return; this.debug('Truncating log file to %d bytes.', maxSize); - fd = await fs.open(this.filename, 'r+'); + const fd = await fs.open(this.filename, 'r+'); + const data = Buffer.allocUnsafe(maxSize); - data = Buffer.allocUnsafe(maxSize); await fs.read(fd, data, 0, maxSize, stat.size - maxSize); await fs.ftruncate(fd, maxSize); await fs.write(fd, data, 0, maxSize, 0); @@ -310,7 +310,7 @@ Logger.prototype.handleError = function handleError(err) { */ Logger.prototype.reopen = async function reopen() { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._reopen(); } finally { @@ -325,7 +325,7 @@ Logger.prototype.reopen = async function reopen() { * @returns {Promise} */ -Logger.prototype._reopen = async function reopen() { +Logger.prototype._reopen = async function _reopen() { if (this.stream) return; @@ -377,7 +377,7 @@ Logger.prototype.setFile = function setFile(filename) { */ Logger.prototype.setLevel = function setLevel(name) { - let level = Logger.levels[name.toUpperCase()]; + const level = Logger.levels[name.toUpperCase()]; assert(level != null, 'Invalid log level.'); this.level = level; }; @@ -389,13 +389,15 @@ Logger.prototype.setLevel = function setLevel(name) { */ Logger.prototype.error = function error(...args) { - let err = args[0]; - if (this.level < Logger.levels.ERROR) return; - if (err instanceof Error) - return this.logError(Logger.levels.ERROR, null, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.ERROR, null, err); + return; + } this.log(Logger.levels.ERROR, null, args); }; @@ -407,13 +409,15 @@ Logger.prototype.error = function error(...args) { */ Logger.prototype.warning = function warning(...args) { - let err = args[0]; - if (this.level < Logger.levels.WARNING) return; - if (err instanceof Error) - return this.logError(Logger.levels.WARNING, null, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.WARNING, null, err); + return; + } this.log(Logger.levels.WARNING, null, args); }; @@ -425,13 +429,15 @@ Logger.prototype.warning = function warning(...args) { */ Logger.prototype.info = function info(...args) { - let err = args[0]; - if (this.level < Logger.levels.INFO) return; - if (err instanceof Error) - return this.logError(Logger.levels.INFO, null, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.INFO, null, err); + return; + } this.log(Logger.levels.INFO, null, args); }; @@ -443,13 +449,15 @@ Logger.prototype.info = function info(...args) { */ Logger.prototype.debug = function debug(...args) { - let err = args[0]; - if (this.level < Logger.levels.DEBUG) return; - if (err instanceof Error) - return this.logError(Logger.levels.DEBUG, null, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.DEBUG, null, err); + return; + } this.log(Logger.levels.DEBUG, null, args); }; @@ -461,13 +469,15 @@ Logger.prototype.debug = function debug(...args) { */ Logger.prototype.spam = function spam(...args) { - let err = args[0]; - if (this.level < Logger.levels.SPAM) return; - if (err instanceof Error) - return this.logError(Logger.levels.SPAM, null, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.SPAM, null, err); + return; + } this.log(Logger.levels.SPAM, null, args); }; @@ -497,15 +507,15 @@ Logger.prototype.log = function log(level, module, args) { * @returns {LoggerContext} */ -Logger.prototype.context = function _context(module) { - let context = this.contexts[module]; +Logger.prototype.context = function context(module) { + let ctx = this.contexts[module]; - if (!context) { - context = new LoggerContext(this, module); - this.contexts[module] = context; + if (!ctx) { + ctx = new LoggerContext(this, module); + this.contexts[module] = ctx; } - return context; + return ctx; }; /** @@ -516,17 +526,15 @@ Logger.prototype.context = function _context(module) { */ Logger.prototype.writeConsole = function writeConsole(level, module, args) { - let name = Logger.levelsByVal[level]; - let msg = ''; - let color; + const name = Logger.levelsByVal[level]; assert(name, 'Invalid log level.'); if (!this.console) - return; + return false; if (!process.stdout) { - msg += `[${name}] `; + let msg = `[${name}] `; if (module) msg += `(${module}) `; @@ -539,18 +547,24 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) { msg += util.format(args, false); - return level === Logger.levels.ERROR - ? console.error(msg) - : console.log(msg); + if (level === Logger.levels.ERROR) { + console.error(msg); + return true; + } + + console.log(msg); + + return true; } + let msg; if (this.colors) { - color = Logger.styles[level]; + const color = Logger.styles[level]; assert(color); - msg += `\x1b[${color}m[${name}]\x1b[m `; + msg = `\x1b[${color}m[${name}]\x1b[m `; } else { - msg += `[${name}] `; + msg = `[${name}] `; } if (module) @@ -572,8 +586,7 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) { */ Logger.prototype.writeStream = function writeStream(level, module, args) { - let name = Logger.prefixByVal[level]; - let msg = ''; + const name = Logger.prefixByVal[level]; assert(name, 'Invalid log level.'); @@ -583,7 +596,7 @@ Logger.prototype.writeStream = function writeStream(level, module, args) { if (this.closing) return; - msg += `[${name}:${util.date()}] `; + let msg = `[${name}:${util.date()}] `; if (module) msg += `(${module}) `; @@ -604,8 +617,6 @@ Logger.prototype.writeStream = function writeStream(level, module, args) { */ Logger.prototype.logError = function logError(level, module, err) { - let msg; - if (this.closed) return; @@ -614,7 +625,7 @@ Logger.prototype.logError = function logError(level, module, err) { console.error(err); } - msg = (err.message + '').replace(/^ *Error: */, ''); + let msg = String(err.message).replace(/^ *Error: */, ''); if (level !== Logger.levels.ERROR) msg = `Error: ${msg}`; @@ -633,7 +644,7 @@ Logger.prototype.logError = function logError(level, module, err) { */ Logger.prototype.memory = function memory(module) { - let mem = util.memoryUsage(); + const mem = util.memoryUsage(); this.log(Logger.levels.DEBUG, module, [ 'Memory: rss=%dmb, js-heap=%d/%dmb native-heap=%dmb', @@ -705,13 +716,15 @@ LoggerContext.prototype.setLevel = function setLevel(name) { */ LoggerContext.prototype.error = function error(...args) { - let err = args[0]; - if (this.logger.level < Logger.levels.ERROR) return; - if (err instanceof Error) - return this.logError(Logger.levels.ERROR, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.ERROR, err); + return; + } this.log(Logger.levels.ERROR, args); }; @@ -723,13 +736,15 @@ LoggerContext.prototype.error = function error(...args) { */ LoggerContext.prototype.warning = function warning(...args) { - let err = args[0]; - if (this.logger.level < Logger.levels.WARNING) return; - if (err instanceof Error) - return this.logError(Logger.levels.WARNING, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.WARNING, err); + return; + } this.log(Logger.levels.WARNING, args); }; @@ -741,13 +756,15 @@ LoggerContext.prototype.warning = function warning(...args) { */ LoggerContext.prototype.info = function info(...args) { - let err = args[0]; - if (this.logger.level < Logger.levels.INFO) return; - if (err instanceof Error) - return this.logError(Logger.levels.INFO, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.INFO, err); + return; + } this.log(Logger.levels.INFO, args); }; @@ -759,13 +776,15 @@ LoggerContext.prototype.info = function info(...args) { */ LoggerContext.prototype.debug = function debug(...args) { - let err = args[0]; - if (this.logger.level < Logger.levels.DEBUG) return; - if (err instanceof Error) - return this.logError(Logger.levels.DEBUG, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.DEBUG, err); + return; + } this.log(Logger.levels.DEBUG, args); }; @@ -777,13 +796,15 @@ LoggerContext.prototype.debug = function debug(...args) { */ LoggerContext.prototype.spam = function spam(...args) { - let err = args[0]; - if (this.logger.level < Logger.levels.SPAM) return; - if (err instanceof Error) - return this.logError(Logger.levels.SPAM, err); + const err = args[0]; + + if (err instanceof Error) { + this.logError(Logger.levels.SPAM, err); + return; + } this.log(Logger.levels.SPAM, args); }; @@ -841,9 +862,16 @@ Logger.global = new Logger(); function openStream(filename) { return new Promise((resolve, reject) => { - let stream = fs.createWriteStream(filename, { flags: 'a' }); + const stream = fs.createWriteStream(filename, { flags: 'a' }); - let onError = (err) => { + const cleanup = () => { + /* eslint-disable */ + stream.removeListener('error', onError); + stream.removeListener('open', onOpen); + /* eslint-enable */ + }; + + const onError = (err) => { try { stream.close(); } catch (e) { @@ -853,16 +881,11 @@ function openStream(filename) { reject(err); }; - let onOpen = () => { + const onOpen = () => { cleanup(); resolve(stream); }; - let cleanup = () => { - stream.removeListener('error', onError); - stream.removeListener('open', onOpen); - }; - stream.once('error', onError); stream.once('open', onOpen); }); @@ -870,21 +893,23 @@ function openStream(filename) { function closeStream(stream) { return new Promise((resolve, reject) => { - let onError = (err) => { + const cleanup = () => { + /* eslint-disable */ + stream.removeListener('error', onError); + stream.removeListener('close', onClose); + /* eslint-enable */ + }; + + const onError = (err) => { cleanup(); reject(err); }; - let onClose = () => { + const onClose = () => { cleanup(); resolve(stream); }; - let cleanup = () => { - stream.removeListener('error', onError); - stream.removeListener('close', onClose); - }; - stream.removeAllListeners('error'); stream.removeAllListeners('close'); stream.once('error', onError); diff --git a/lib/node/node.js b/lib/node/node.js index 6221653e2..4615be3e3 100644 --- a/lib/node/node.js +++ b/lib/node/node.js @@ -42,7 +42,7 @@ function Node(options) { this.network = Network.get(this.config.network); this.startTime = -1; this.bound = []; - this.plugins = {}; + this.plugins = Object.create(null); this.stack = []; this.logger = null; @@ -59,7 +59,7 @@ function Node(options) { this.init(); } -util.inherits(Node, AsyncObject); +Object.setPrototypeOf(Node.prototype, AsyncObject.prototype); /** * Initialize options. @@ -69,7 +69,7 @@ util.inherits(Node, AsyncObject); Node.prototype.initOptions = function initOptions() { let logger = new Logger(); - let config = this.config; + const config = this.config; if (config.has('logger')) logger = config.obj('logger'); @@ -87,8 +87,8 @@ Node.prototype.initOptions = function initOptions() { this.workers = new WorkerPool({ enabled: config.bool('workers'), - size: config.num('workers-size'), - timeout: config.num('workers-timeout'), + size: config.uint('workers-size'), + timeout: config.uint('workers-timeout'), file: config.str('worker-file') }); }; @@ -214,7 +214,7 @@ Node.prototype.handlePreclose = async function handlePreclose() { */ Node.prototype.handleClose = async function handleClose() { - for (let [obj, event, listener] of this.bound) + for (const [obj, event, listener] of this.bound) obj.removeListener(event, listener); this.bound.length = 0; @@ -267,14 +267,12 @@ Node.prototype.uptime = function uptime() { */ Node.prototype.use = function use(plugin) { - let instance; - assert(plugin, 'Plugin must be an object.'); assert(typeof plugin.init === 'function', '`init` must be a function.'); assert(!this.loaded, 'Cannot add plugin after node is loaded.'); - instance = plugin.init(this); + const instance = plugin.init(this); assert(!instance.open || typeof instance.open === 'function', '`open` must be a function.'); @@ -354,7 +352,7 @@ Node.prototype.get = function get(name) { return this.http; } - return this.plugins[name]; + return this.plugins[name] || null; }; /** @@ -365,7 +363,7 @@ Node.prototype.get = function get(name) { */ Node.prototype.require = function require(name) { - let plugin = this.get(name); + const plugin = this.get(name); assert(plugin, `${name} is not loaded.`); return plugin; }; @@ -376,8 +374,8 @@ Node.prototype.require = function require(name) { */ Node.prototype.loadPlugins = function loadPlugins() { - let plugins = this.config.array('plugins', []); - let loader = this.config.func('loader'); + const plugins = this.config.array('plugins', []); + const loader = this.config.func('loader'); for (let plugin of plugins) { if (typeof plugin === 'string') { @@ -394,7 +392,7 @@ Node.prototype.loadPlugins = function loadPlugins() { */ Node.prototype.openPlugins = async function openPlugins() { - for (let plugin of this.stack) { + for (const plugin of this.stack) { if (plugin.open) await plugin.open(); } @@ -406,7 +404,7 @@ Node.prototype.openPlugins = async function openPlugins() { */ Node.prototype.closePlugins = async function closePlugins() { - for (let plugin of this.stack) { + for (const plugin of this.stack) { if (plugin.close) await plugin.close(); } diff --git a/lib/node/spvnode.js b/lib/node/spvnode.js index 8401fec88..eb96fc9d4 100644 --- a/lib/node/spvnode.js +++ b/lib/node/spvnode.js @@ -7,13 +7,12 @@ 'use strict'; -const util = require('../utils/util'); const Lock = require('../utils/lock'); -const Node = require('./node'); const Chain = require('../blockchain/chain'); const Pool = require('../net/pool'); const HTTPServer = require('../http/server'); const RPC = require('../http/rpc'); +const Node = require('./node'); /** * Create an spv node which only maintains @@ -49,9 +48,9 @@ function SPVNode(options) { logger: this.logger, db: this.config.str('db'), prefix: this.config.prefix, - maxFiles: this.config.num('max-files'), + maxFiles: this.config.uint('max-files'), cacheSize: this.config.mb('cache-size'), - entryCache: this.config.num('entry-cache'), + entryCache: this.config.uint('entry-cache'), forceFlags: this.config.bool('force-flags'), checkpoints: this.config.bool('checkpoints'), bip91: this.config.bool('bip91'), @@ -73,7 +72,7 @@ function SPVNode(options) { bip151: this.config.bool('bip151'), bip150: this.config.bool('bip150'), identityKey: this.config.buf('identity-key'), - maxOutbound: this.config.num('max-outbound'), + maxOutbound: this.config.uint('max-outbound'), persistent: this.config.bool('persistent'), selfish: true, listen: false @@ -91,7 +90,7 @@ function SPVNode(options) { keyFile: this.config.path('ssl-key'), certFile: this.config.path('ssl-cert'), host: this.config.str('http-host'), - port: this.config.num('http-port'), + port: this.config.uint('http-port'), apiKey: this.config.str('api-key'), noAuth: this.config.bool('no-auth') }); @@ -104,7 +103,7 @@ function SPVNode(options) { this._init(); } -util.inherits(SPVNode, Node); +Object.setPrototypeOf(SPVNode.prototype, Node.prototype); /** * Initialize the node. @@ -161,7 +160,7 @@ SPVNode.prototype._init = function _init() { * @returns {Promise} */ -SPVNode.prototype._open = async function open(callback) { +SPVNode.prototype._open = async function _open(callback) { await this.chain.open(); await this.pool.open(); @@ -179,7 +178,7 @@ SPVNode.prototype._open = async function open(callback) { * @returns {Promise} */ -SPVNode.prototype._close = async function close() { +SPVNode.prototype._close = async function _close() { if (this.http) await this.http.close(); @@ -199,8 +198,8 @@ SPVNode.prototype._close = async function close() { */ SPVNode.prototype.scan = async function scan(start, filter, iter) { - let unlock = await this.scanLock.lock(); - let height = this.chain.height; + const unlock = await this.scanLock.lock(); + const height = this.chain.height; try { await this.chain.replay(start); @@ -237,7 +236,7 @@ SPVNode.prototype.watchUntil = function watchUntil(height, iter) { */ SPVNode.prototype.watchBlock = async function watchBlock(entry, block) { - let unlock = await this.watchLock.lock(); + const unlock = await this.watchLock.lock(); try { if (entry.height < this.rescanJob.height) { await this.rescanJob.iter(entry, block.txs); diff --git a/lib/primitives/abstractblock.js b/lib/primitives/abstractblock.js index c7a0c1ebb..298c90be8 100644 --- a/lib/primitives/abstractblock.js +++ b/lib/primitives/abstractblock.js @@ -10,6 +10,7 @@ const assert = require('assert'); const util = require('../utils/util'); const digest = require('../crypto/digest'); +const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); const InvItem = require('./invitem'); const encoding = require('../utils/encoding'); @@ -26,11 +27,9 @@ const consensus = require('../protocol/consensus'); * number will never be negative. * @property {Hash} prevBlock - Previous block hash. * @property {Hash} merkleRoot - Merkle root hash. - * @property {Number} ts - Timestamp. + * @property {Number} time - Timestamp. * @property {Number} bits * @property {Number} nonce - * @property {TX[]} txs - Transaction vector. - * @property {ReversedHash} rhash - Reversed block hash (uint256le). */ function AbstractBlock() { @@ -40,28 +39,16 @@ function AbstractBlock() { this.version = 1; this.prevBlock = encoding.NULL_HASH; this.merkleRoot = encoding.NULL_HASH; - this.ts = 0; + this.time = 0; this.bits = 0; this.nonce = 0; - this.txs = null; this.mutable = false; this._hash = null; this._hhash = null; - this._size = -1; - this._witness = -1; } -/** - * Memory flag. - * @const {Boolean} - * @default - * @memberof AbstractBlock# - */ - -AbstractBlock.prototype.memory = false; - /** * Inject properties from options object. * @private @@ -70,22 +57,22 @@ AbstractBlock.prototype.memory = false; AbstractBlock.prototype.parseOptions = function parseOptions(options) { assert(options, 'Block data is required.'); - assert(util.isNumber(options.version)); + assert(util.isU32(options.version)); assert(typeof options.prevBlock === 'string'); assert(typeof options.merkleRoot === 'string'); - assert(util.isNumber(options.ts)); - assert(util.isNumber(options.bits)); - assert(util.isNumber(options.nonce)); + assert(util.isU32(options.time)); + assert(util.isU32(options.bits)); + assert(util.isU32(options.nonce)); this.version = options.version; this.prevBlock = options.prevBlock; this.merkleRoot = options.merkleRoot; - this.ts = options.ts; + this.time = options.time; this.bits = options.bits; this.nonce = options.nonce; if (options.mutable != null) - this.mutable = !!options.mutable; + this.mutable = Boolean(options.mutable); return this; }; @@ -98,51 +85,47 @@ AbstractBlock.prototype.parseOptions = function parseOptions(options) { AbstractBlock.prototype.parseJSON = function parseJSON(json) { assert(json, 'Block data is required.'); - assert(util.isNumber(json.version)); + assert(util.isU32(json.version)); assert(typeof json.prevBlock === 'string'); assert(typeof json.merkleRoot === 'string'); - assert(util.isNumber(json.ts)); - assert(util.isNumber(json.bits)); - assert(util.isNumber(json.nonce)); + assert(util.isU32(json.time)); + assert(util.isU32(json.bits)); + assert(util.isU32(json.nonce)); this.version = json.version; this.prevBlock = util.revHex(json.prevBlock); this.merkleRoot = util.revHex(json.merkleRoot); - this.ts = json.ts; + this.time = json.time; this.bits = json.bits; this.nonce = json.nonce; return this; }; +/** + * Test whether the block is a memblock. + * @returns {Boolean} + */ + +AbstractBlock.prototype.isMemory = function isMemory() { + return false; +}; + /** * Clear any cached values (abstract). - * @param {Boolean?} all - Clear transactions. */ -AbstractBlock.prototype._refresh = function refresh(all) { +AbstractBlock.prototype._refresh = function _refresh() { this._hash = null; this._hhash = null; - this._size = -1; - this._witness = -1; - - if (!all) - return; - - if (!this.txs) - return; - - for (let tx of this.txs) - tx.refresh(); }; /** * Clear any cached values. - * @param {Boolean?} all - Clear transactions. */ -AbstractBlock.prototype.refresh = function refresh(all) { - return this._refresh(all); +AbstractBlock.prototype.refresh = function refresh() { + return this._refresh(); }; /** @@ -151,26 +134,26 @@ AbstractBlock.prototype.refresh = function refresh(all) { * @returns {Hash|Buffer} hash */ -AbstractBlock.prototype.hash = function _hash(enc) { - let hash = this._hash; +AbstractBlock.prototype.hash = function hash(enc) { + let h = this._hash; - if (!hash) { - hash = digest.hash256(this.abbr()); + if (!h) { + h = digest.hash256(this.toHead()); if (!this.mutable) - this._hash = hash; + this._hash = h; } if (enc === 'hex') { let hex = this._hhash; if (!hex) { - hex = hash.toString('hex'); + hex = h.toString('hex'); if (!this.mutable) this._hhash = hex; } - hash = hex; + h = hex; } - return hash; + return h; }; /** @@ -178,8 +161,18 @@ AbstractBlock.prototype.hash = function _hash(enc) { * @returns {Buffer} */ -AbstractBlock.prototype.abbr = function abbr() { - return this.writeAbbr(new StaticWriter(80)).render(); +AbstractBlock.prototype.toHead = function toHead() { + return this.writeHead(new StaticWriter(80)).render(); +}; + +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + +AbstractBlock.prototype.fromHead = function fromHead(data) { + return this.readHead(new BufferReader(data)); }; /** @@ -187,11 +180,11 @@ AbstractBlock.prototype.abbr = function abbr() { * @param {BufferWriter} bw */ -AbstractBlock.prototype.writeAbbr = function writeAbbr(bw) { +AbstractBlock.prototype.writeHead = function writeHead(bw) { bw.writeU32(this.version); bw.writeHash(this.prevBlock); bw.writeHash(this.merkleRoot); - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU32(this.bits); bw.writeU32(this.nonce); return bw; @@ -202,11 +195,11 @@ AbstractBlock.prototype.writeAbbr = function writeAbbr(bw) { * @param {BufferReader} br */ -AbstractBlock.prototype.parseAbbr = function parseAbbr(br) { +AbstractBlock.prototype.readHead = function readHead(br) { this.version = br.readU32(); this.prevBlock = br.readHash('hex'); this.merkleRoot = br.readHash('hex'); - this.ts = br.readU32(); + this.time = br.readU32(); this.bits = br.readU32(); this.nonce = br.readU32(); return this; diff --git a/lib/primitives/address.js b/lib/primitives/address.js index b24b39cdf..8d0ea10c0 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -57,7 +57,7 @@ Address.types = { * @const {RevMap} */ -Address.typesByVal = util.revMap(Address.types); +Address.typesByVal = util.reverse(Address.types); /** * Inject properties from options object. @@ -119,6 +119,21 @@ Address.prototype.isNull = function isNull() { return true; }; +/** + * Test equality against another address. + * @param {Address} addr + * @returns {Boolean} + */ + +Address.prototype.equals = function equals(addr) { + assert(addr instanceof Address); + + return this.network === addr.network + && this.type === addr.type + && this.version === addr.version + && this.hash.equals(addr.hash); +}; + /** * Get the address type as a string. * @returns {String} @@ -135,13 +150,12 @@ Address.prototype.getType = function getType() { */ Address.prototype.getPrefix = function getPrefix(network) { - let prefixes; - if (!network) network = this.network; network = Network.get(network); - prefixes = network.addressPrefix; + + const prefixes = network.addressPrefix; switch (this.type) { case Address.types.PUBKEYHASH: @@ -183,9 +197,9 @@ Address.prototype.getSize = function getSize() { */ Address.prototype.toRaw = function toRaw(network) { - let size = this.getSize(); - let bw = new StaticWriter(size); - let prefix = this.getPrefix(network); + const size = this.getSize(); + const bw = new StaticWriter(size); + const prefix = this.getPrefix(network); assert(prefix !== -1, 'Not a valid address prefix.'); @@ -221,9 +235,8 @@ Address.prototype.toBase58 = function toBase58(network) { */ Address.prototype.toBech32 = function toBech32(network) { - let version = this.version; - let hash = this.hash; - let hrp; + const version = this.version; + const hash = this.hash; assert(version !== -1, 'Cannot convert non-program address to bech32.'); @@ -232,7 +245,8 @@ Address.prototype.toBech32 = function toBech32(network) { network = this.network; network = Network.get(network); - hrp = network.addressPrefix.bech32; + + const hrp = network.addressPrefix.bech32; return bech32.encode(hrp, version, hash); }; @@ -246,18 +260,21 @@ Address.prototype.toBech32 = function toBech32(network) { */ Address.prototype.fromString = function fromString(addr, network) { - let hrp; - assert(typeof addr === 'string'); + assert(addr.length > 0); + assert(addr.length <= 100); + // If the address is mixed case, + // it can only ever be base58. + if (isMixedCase(addr)) + return this.fromBase58(addr, network); + + // Otherwise, it's most likely bech32. try { - hrp = addr.substring(0, 2).toLowerCase(); - network = Network.fromBech32(hrp, network); + return this.fromBech32(addr, network); } catch (e) { return this.fromBase58(addr, network); } - - return this.fromBech32(addr, network); }; /** @@ -304,17 +321,18 @@ Address.prototype.inspect = function inspect() { */ Address.prototype.fromRaw = function fromRaw(data, network) { - let br = new BufferReader(data, true); - let version = -1; - let prefix, type, hash; + const br = new BufferReader(data, true); if (data.length > 40) throw new Error('Address is too long.'); - prefix = br.readU8(); + const prefix = br.readU8(); + network = Network.fromAddress(prefix, network); - type = Address.getType(prefix, network); + const type = Address.getType(prefix, network); + + let version = -1; if (data.length > 25) { version = br.readU8(); @@ -322,7 +340,7 @@ Address.prototype.fromRaw = function fromRaw(data, network) { throw new Error('Address version padding is non-zero.'); } - hash = br.readBytes(br.left() - 4); + const hash = br.readBytes(br.left() - 4); br.verifyChecksum(); @@ -378,12 +396,12 @@ Address.fromBase58 = function fromBase58(data, network) { */ Address.prototype.fromBech32 = function fromBech32(data, network) { - let type = Address.types.WITNESS; - let addr; + const type = Address.types.WITNESS; assert(typeof data === 'string'); - addr = bech32.decode(data); + const addr = bech32.decode(data); + network = Network.fromBech32(addr.hrp, network); return this.fromHash(addr.hash, type, addr.version, network); @@ -408,45 +426,39 @@ Address.fromBech32 = function fromBech32(data, network) { */ Address.prototype.fromScript = function fromScript(script) { - if (script.isPubkey()) { - this.hash = digest.hash160(script.get(0)); + const pk = script.getPubkey(); + + if (pk) { + this.hash = digest.hash160(pk); this.type = Address.types.PUBKEYHASH; this.version = -1; return this; } - if (script.isPubkeyhash()) { - this.hash = script.get(2); + const pkh = script.getPubkeyhash(); + + if (pkh) { + this.hash = pkh; this.type = Address.types.PUBKEYHASH; this.version = -1; return this; } - if (script.isScripthash()) { - this.hash = script.get(1); + const sh = script.getScripthash(); + + if (sh) { + this.hash = sh; this.type = Address.types.SCRIPTHASH; this.version = -1; return this; } - if (script.isWitnessPubkeyhash()) { - this.hash = script.get(1); - this.type = Address.types.WITNESS; - this.version = 0; - return this; - } - - if (script.isWitnessScripthash()) { - this.hash = script.get(1); - this.type = Address.types.WITNESS; - this.version = 0; - return this; - } + const program = script.getProgram(); - if (script.isWitnessMasthash()) { - this.hash = script.get(1); + if (program && !program.isMalformed()) { + this.hash = program.data; this.type = Address.types.WITNESS; - this.version = 1; + this.version = program.version; return this; } @@ -457,6 +469,8 @@ Address.prototype.fromScript = function fromScript(script) { this.version = -1; return this; } + + return null; }; /** @@ -466,21 +480,27 @@ Address.prototype.fromScript = function fromScript(script) { */ Address.prototype.fromWitness = function fromWitness(witness) { + const [, pk] = witness.getPubkeyhashInput(); + // We're pretty much screwed here // since we can't get the version. - if (witness.isPubkeyhashInput()) { - this.hash = digest.hash160(witness.get(1)); + if (pk) { + this.hash = digest.hash160(pk); this.type = Address.types.WITNESS; this.version = 0; return this; } - if (witness.isScripthashInput()) { - this.hash = digest.sha256(witness.get(witness.length - 1)); + const redeem = witness.getScripthashInput(); + + if (redeem) { + this.hash = digest.sha256(redeem); this.type = Address.types.WITNESS; this.version = 0; return this; } + + return null; }; /** @@ -490,19 +510,25 @@ Address.prototype.fromWitness = function fromWitness(witness) { */ Address.prototype.fromInputScript = function fromInputScript(script) { - if (script.isPubkeyhashInput()) { - this.hash = digest.hash160(script.get(1)); + const [, pk] = script.getPubkeyhashInput(); + + if (pk) { + this.hash = digest.hash160(pk); this.type = Address.types.PUBKEYHASH; this.version = -1; return this; } - if (script.isScripthashInput()) { - this.hash = digest.hash160(script.get(script.length - 1)); + const redeem = script.getScripthashInput(); + + if (redeem) { + this.hash = digest.hash160(redeem); this.type = Address.types.SCRIPTHASH; this.version = -1; return this; } + + return null; }; /** @@ -570,8 +596,8 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) { network = Network.get(network); assert(Buffer.isBuffer(hash)); - assert(util.isNumber(type)); - assert(util.isNumber(version)); + assert(util.isU8(type)); + assert(util.isI8(version)); assert(type >= Address.types.PUBKEYHASH && type <= Address.types.WITNESS, 'Not a valid address type.'); @@ -620,7 +646,7 @@ Address.fromHash = function fromHash(hash, type, version, network) { */ Address.prototype.fromPubkeyhash = function fromPubkeyhash(hash, network) { - let type = Address.types.PUBKEYHASH; + const type = Address.types.PUBKEYHASH; assert(hash.length === 20, 'P2PKH must be 20 bytes.'); return this.fromHash(hash, type, -1, network); }; @@ -645,7 +671,7 @@ Address.fromPubkeyhash = function fromPubkeyhash(hash, network) { */ Address.prototype.fromScripthash = function fromScripthash(hash, network) { - let type = Address.types.SCRIPTHASH; + const type = Address.types.SCRIPTHASH; assert(hash && hash.length === 20, 'P2SH must be 20 bytes.'); return this.fromHash(hash, type, -1, network); }; @@ -670,7 +696,7 @@ Address.fromScripthash = function fromScripthash(hash, network) { */ Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) { - let type = Address.types.WITNESS; + const type = Address.types.WITNESS; assert(hash && hash.length === 20, 'P2WPKH must be 20 bytes.'); return this.fromHash(hash, type, 0, network); }; @@ -695,7 +721,7 @@ Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) { */ Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash, network) { - let type = Address.types.WITNESS; + const type = Address.types.WITNESS; assert(hash && hash.length === 32, 'P2WPKH must be 32 bytes.'); return this.fromHash(hash, type, 0, network); }; @@ -721,7 +747,7 @@ Address.fromWitnessScripthash = function fromWitnessScripthash(hash, network) { */ Address.prototype.fromProgram = function fromProgram(version, hash, network) { - let type = Address.types.WITNESS; + const type = Address.types.WITNESS; assert(version >= 0, 'Bad version for witness program.'); @@ -821,11 +847,11 @@ Address.prototype.isUnknown = function isUnknown() { */ Address.getHash = function getHash(data, enc, network) { - let hash; - if (!data) throw new Error('Object is not an address.'); + let hash; + if (typeof data === 'string') { if (data.length === 40 || data.length === 64) return enc === 'hex' ? data : Buffer.from(data, 'hex'); @@ -859,7 +885,7 @@ Address.getHash = function getHash(data, enc, network) { */ Address.getType = function getType(prefix, network) { - let prefixes = network.addressPrefix; + const prefixes = network.addressPrefix; switch (prefix) { case prefixes.pubkeyhash: return Address.types.PUBKEYHASH; @@ -873,6 +899,35 @@ Address.getType = function getType(prefix, network) { } }; +/* + * Helpers + */ + +function isMixedCase(str) { + let lower = false; + let upper = false; + + for (let i = 0; i < str.length; i++) { + const ch = str.charCodeAt(i); + + if (ch >= 0x30 && ch <= 0x39) + continue; + + if (ch & 32) { + assert(ch >= 0x61 && ch <= 0x7a); + lower = true; + } else { + assert(ch >= 0x41 && ch <= 0x5a); + upper = true; + } + + if (lower && upper) + return true; + } + + return false; +} + /* * Expose */ diff --git a/lib/primitives/block.js b/lib/primitives/block.js index 5eb721531..7e20bcb46 100644 --- a/lib/primitives/block.js +++ b/lib/primitives/block.js @@ -45,7 +45,7 @@ function Block(options) { this.fromOptions(options); } -util.inherits(Block, AbstractBlock); +Object.setPrototypeOf(Block.prototype, AbstractBlock.prototype); /** * Inject properties from options object. @@ -58,8 +58,10 @@ Block.prototype.fromOptions = function fromOptions(options) { if (options.txs) { assert(Array.isArray(options.txs)); - for (let tx of options.txs) - this.addTX(tx); + for (const tx of options.txs) { + assert(tx instanceof TX); + this.txs.push(tx); + } } }; @@ -79,8 +81,17 @@ Block.fromOptions = function fromOptions(options) { */ Block.prototype.refresh = function refresh(all) { + this._refresh(); + this._raw = null; - this._refresh(all); + this._size = -1; + this._witness = -1; + + if (!all) + return; + + for (const tx of this.txs) + tx.refresh(); }; /** @@ -109,12 +120,10 @@ Block.prototype.toNormal = function toNormal() { */ Block.prototype.toWriter = function toWriter(bw) { - let raw; - if (this.mutable) return this.writeWitness(bw); - raw = this.frame(); + const raw = this.frame(); bw.writeBytes(raw.data); return bw; @@ -141,25 +150,23 @@ Block.prototype.toNormalWriter = function toNormalWriter(bw) { */ Block.prototype.frame = function frame() { - let raw; - if (this.mutable) { assert(!this._raw); return this.frameWitness(); } if (this._raw) { - assert(this._size > 0); + assert(this._size >= 0); assert(this._witness >= 0); - raw = new RawBlock(this._size, this._witness); + const raw = new RawBlock(this._size, this._witness); raw.data = this._raw; return raw; } - raw = this.frameWitness(); + const raw = this.frameWitness(); this._raw = raw.data; - this._size = raw.total; + this._size = raw.size; this._witness = raw.witness; return raw; @@ -167,7 +174,7 @@ Block.prototype.frame = function frame() { /** * Calculate real size and size of the witness bytes. - * @returns {Object} Contains `total` and `witness`. + * @returns {Object} Contains `size` and `witness`. */ Block.prototype.getSizes = function getSizes() { @@ -182,7 +189,7 @@ Block.prototype.getSizes = function getSizes() { */ Block.prototype.getVirtualSize = function getVirtualSize() { - let scale = consensus.WITNESS_SCALE_FACTOR; + const scale = consensus.WITNESS_SCALE_FACTOR; return (this.getWeight() + scale - 1) / scale | 0; }; @@ -192,9 +199,9 @@ Block.prototype.getVirtualSize = function getVirtualSize() { */ Block.prototype.getWeight = function getWeight() { - let sizes = this.getSizes(); - let base = sizes.total - sizes.witness; - return base * (consensus.WITNESS_SCALE_FACTOR - 1) + sizes.total; + const raw = this.getSizes(); + const base = raw.size - raw.witness; + return base * (consensus.WITNESS_SCALE_FACTOR - 1) + raw.size; }; /** @@ -203,7 +210,7 @@ Block.prototype.getWeight = function getWeight() { */ Block.prototype.getSize = function getSize() { - return this.getSizes().total; + return this.getSizes().size; }; /** @@ -212,8 +219,8 @@ Block.prototype.getSize = function getSize() { */ Block.prototype.getBaseSize = function getBaseSize() { - let sizes = this.getSizes(); - return sizes.total - sizes.witness; + const raw = this.getSizes(); + return raw.size - raw.witness; }; /** @@ -226,7 +233,7 @@ Block.prototype.hasWitness = function hasWitness() { if (this._witness !== -1) return this._witness !== 0; - for (let tx of this.txs) { + for (const tx of this.txs) { if (tx.hasWitness()) return true; } @@ -234,16 +241,6 @@ Block.prototype.hasWitness = function hasWitness() { return false; }; -/** - * Add a transaction to the block's tx vector. - * @param {TX} tx - * @returns {Number} - */ - -Block.prototype.addTX = function addTX(tx) { - return this.txs.push(tx) - 1; -}; - /** * Test the block's transaction vector against a hash. * @param {Hash} hash @@ -262,7 +259,7 @@ Block.prototype.hasTX = function hasTX(hash) { Block.prototype.indexOf = function indexOf(hash) { for (let i = 0; i < this.txs.length; i++) { - let tx = this.txs[i]; + const tx = this.txs[i]; if (tx.hash('hex') === hash) return i; } @@ -278,13 +275,12 @@ Block.prototype.indexOf = function indexOf(hash) { */ Block.prototype.createMerkleRoot = function createMerkleRoot(enc) { - let leaves = []; - let root, malleated; + const leaves = []; - for (let tx of this.txs) + for (const tx of this.txs) leaves.push(tx.hash()); - [root, malleated] = merkle.createRoot(leaves); + const [root, malleated] = merkle.createRoot(leaves); if (malleated) return null; @@ -309,25 +305,24 @@ Block.prototype.createWitnessNonce = function createWitnessNonce() { */ Block.prototype.createCommitmentHash = function createCommitmentHash(enc) { - let nonce = this.getWitnessNonce(); - let leaves = []; - let root, hash; + const nonce = this.getWitnessNonce(); + const leaves = []; assert(nonce, 'No witness nonce present.'); leaves.push(encoding.ZERO_HASH); for (let i = 1; i < this.txs.length; i++) { - let tx = this.txs[i]; + const tx = this.txs[i]; leaves.push(tx.witnessHash()); } - [root] = merkle.createRoot(leaves); + const [root] = merkle.createRoot(leaves); // Note: malleation check ignored here. // assert(!malleated); - hash = digest.root256(root, nonce); + const hash = digest.root256(root, nonce); return enc === 'hex' ? hash.toString('hex') @@ -353,17 +348,15 @@ Block.prototype.getMerkleRoot = function getMerkleRoot(enc) { */ Block.prototype.getWitnessNonce = function getWitnessNonce() { - let coinbase, input; - if (this.txs.length === 0) return null; - coinbase = this.txs[0]; + const coinbase = this.txs[0]; if (coinbase.inputs.length !== 1) return null; - input = coinbase.inputs[0]; + const input = coinbase.inputs[0]; if (input.witness.items.length !== 1) return null; @@ -382,17 +375,16 @@ Block.prototype.getWitnessNonce = function getWitnessNonce() { */ Block.prototype.getCommitmentHash = function getCommitmentHash(enc) { - let coinbase, hash; - if (this.txs.length === 0) return null; - coinbase = this.txs[0]; + const coinbase = this.txs[0]; + let hash; for (let i = coinbase.outputs.length - 1; i >= 0; i--) { - let output = coinbase.outputs[i]; + const output = coinbase.outputs[i]; if (output.script.isCommitment()) { - hash = output.script.getCommitmentHash(); + hash = output.script.getCommitment(); break; } } @@ -412,7 +404,7 @@ Block.prototype.getCommitmentHash = function getCommitmentHash(enc) { */ Block.prototype.verifyBody = function verifyBody() { - let [valid] = this.checkBody(); + const [valid] = this.checkBody(); return valid; }; @@ -423,12 +415,8 @@ Block.prototype.verifyBody = function verifyBody() { */ Block.prototype.checkBody = function checkBody() { - let sigops = 0; - let scale = consensus.WITNESS_SCALE_FACTOR; - let root; - // Check merkle root. - root = this.createMerkleRoot('hex'); + const root = this.createMerkleRoot('hex'); // If the merkle is mutated, // we have duplicate txs. @@ -450,16 +438,18 @@ Block.prototype.checkBody = function checkBody() { return [false, 'bad-cb-missing', 100]; // Test all transactions. + const scale = consensus.WITNESS_SCALE_FACTOR; + let sigops = 0; + for (let i = 0; i < this.txs.length; i++) { - let tx = this.txs[i]; - let valid, reason, score; + const tx = this.txs[i]; // The rest of the txs must not be coinbases. if (i > 0 && tx.isCoinbase()) return [false, 'bad-cb-multiple', 100]; // Sanity checks. - [valid, reason, score] = tx.checkSanity(); + const [valid, reason, score] = tx.checkSanity(); if (!valid) return [valid, reason, score]; @@ -479,15 +469,13 @@ Block.prototype.checkBody = function checkBody() { */ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() { - let coinbase; - if (this.version < 2) return -1; if (this.txs.length === 0) return -1; - coinbase = this.txs[0]; + const coinbase = this.txs[0]; if (coinbase.inputs.length === 0) return -1; @@ -513,12 +501,12 @@ Block.prototype.getClaimed = function getClaimed() { */ Block.prototype.getPrevout = function getPrevout() { - let prevout = {}; + const prevout = Object.create(null); for (let i = 1; i < this.txs.length; i++) { - let tx = this.txs[i]; + const tx = this.txs[i]; - for (let input of tx.inputs) + for (const input of tx.inputs) prevout[input.prevout.hash] = true; } @@ -544,20 +532,20 @@ Block.prototype.inspect = function inspect() { */ Block.prototype.format = function format(view, height) { - let commitmentHash = this.getCommitmentHash('hex'); + const commitmentHash = this.getCommitmentHash('hex'); return { hash: this.rhash(), height: height != null ? height : -1, size: this.getSize(), virtualSize: this.getVirtualSize(), - date: util.date(this.ts), + date: util.date(this.time), version: util.hex32(this.version), prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), commitmentHash: commitmentHash ? util.revHex(commitmentHash) : null, - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce, txs: this.txs.map((tx, i) => { @@ -595,7 +583,7 @@ Block.prototype.getJSON = function getJSON(network, view, height) { version: this.version, prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce, txs: this.txs.map((tx, i) => { @@ -616,7 +604,7 @@ Block.prototype.fromJSON = function fromJSON(json) { this.parseJSON(json); - for (let tx of json.txs) + for (const tx of json.txs) this.txs.push(TX.fromJSON(tx)); return this; @@ -639,19 +627,17 @@ Block.fromJSON = function fromJSON(json) { */ Block.prototype.fromReader = function fromReader(br) { - let witness = 0; - let count; - br.start(); - this.parseAbbr(br); + this.readHead(br); - count = br.readVarint(); + const count = br.readVarint(); + let witness = 0; for (let i = 0; i < count; i++) { - let tx = TX.fromReader(br); + const tx = TX.fromReader(br); witness += tx._witness; - this.addTX(tx); + this.txs.push(tx); } if (!this.mutable) { @@ -718,14 +704,12 @@ Block.prototype.toMerkle = function toMerkle(filter) { */ Block.prototype.writeNormal = function writeNormal(bw) { - this.writeAbbr(bw); + this.writeHead(bw); bw.writeVarint(this.txs.length); - for (let i = 0; i < this.txs.length; i++) { - let tx = this.txs[i]; + for (const tx of this.txs) tx.toNormalWriter(bw); - } return bw; }; @@ -739,14 +723,12 @@ Block.prototype.writeNormal = function writeNormal(bw) { */ Block.prototype.writeWitness = function writeWitness(bw) { - this.writeAbbr(bw); + this.writeHead(bw); bw.writeVarint(this.txs.length); - for (let i = 0; i < this.txs.length; i++) { - let tx = this.txs[i]; + for (const tx of this.txs) tx.toWriter(bw); - } return bw; }; @@ -760,11 +742,11 @@ Block.prototype.writeWitness = function writeWitness(bw) { */ Block.prototype.frameNormal = function frameNormal() { - let sizes = this.getNormalSizes(); - let bw = new StaticWriter(sizes.total); + const raw = this.getNormalSizes(); + const bw = new StaticWriter(raw.size); this.writeNormal(bw); - sizes.data = bw.render(); - return sizes; + raw.data = bw.render(); + return raw; }; /** @@ -775,11 +757,11 @@ Block.prototype.frameNormal = function frameNormal() { */ Block.prototype.frameWitness = function frameWitness() { - let sizes = this.getWitnessSizes(); - let bw = new StaticWriter(sizes.total); + const raw = this.getWitnessSizes(); + const bw = new StaticWriter(raw.size); this.writeWitness(bw); - sizes.data = bw.render(); - return sizes; + raw.data = bw.render(); + return raw; }; /** @@ -802,10 +784,8 @@ Block.prototype.getNormalSizes = function getNormalSizes() { size += 80; size += encoding.sizeVarint(this.txs.length); - for (let i = 0; i < this.txs.length; i++) { - let tx = this.txs[i]; + for (const tx of this.txs) size += tx.getBaseSize(); - } return new RawBlock(size, 0); }; @@ -822,11 +802,10 @@ Block.prototype.getWitnessSizes = function getWitnessSizes() { size += 80; size += encoding.sizeVarint(this.txs.length); - for (let i = 0; i < this.txs.length; i++) { - let tx = this.txs[i]; - let sizes = tx.getSizes(); - size += sizes.total; - witness += sizes.witness; + for (const tx of this.txs) { + const raw = tx.getSizes(); + size += raw.size; + witness += raw.witness; } return new RawBlock(size, witness); @@ -848,9 +827,9 @@ Block.isBlock = function isBlock(obj) { * Helpers */ -function RawBlock(total, witness) { +function RawBlock(size, witness) { this.data = null; - this.total = total; + this.size = size; this.witness = witness; } diff --git a/lib/primitives/coin.js b/lib/primitives/coin.js index 230a82382..f4c5101ad 100644 --- a/lib/primitives/coin.js +++ b/lib/primitives/coin.js @@ -49,7 +49,7 @@ function Coin(options) { this.fromOptions(options); } -util.inherits(Coin, Output); +Object.setPrototypeOf(Coin.prototype, Output.prototype); /** * Inject options into coin. @@ -61,13 +61,13 @@ Coin.prototype.fromOptions = function fromOptions(options) { assert(options, 'Coin data is required.'); if (options.version != null) { - assert(util.isUInt32(options.version), 'Version must be a uint32.'); + assert(util.isU32(options.version), 'Version must be a uint32.'); this.version = options.version; } if (options.height != null) { if (options.height !== -1) { - assert(util.isUInt32(options.height), 'Height must be a uint32.'); + assert(util.isU32(options.height), 'Height must be a uint32.'); this.height = options.height; } else { this.height = -1; @@ -75,7 +75,7 @@ Coin.prototype.fromOptions = function fromOptions(options) { } if (options.value != null) { - assert(util.isUInt53(options.value), 'Value must be a uint53.'); + assert(util.isU64(options.value), 'Value must be a uint64.'); this.value = options.value; } @@ -94,7 +94,7 @@ Coin.prototype.fromOptions = function fromOptions(options) { } if (options.index != null) { - assert(util.isUInt32(options.index), 'Index must be a uint32.'); + assert(util.isU32(options.index), 'Index must be a uint32.'); this.index = options.index; } @@ -163,7 +163,7 @@ Coin.prototype.toKey = function toKey() { Coin.prototype.fromKey = function fromKey(key) { assert(key.length > 64); this.hash = key.slice(0, 64); - this.index = +key.slice(64); + this.index = parseInt(key.slice(64), 10); return this; }; @@ -262,10 +262,10 @@ Coin.prototype.getJSON = function getJSON(network, minimal) { Coin.prototype.fromJSON = function fromJSON(json) { assert(json, 'Coin data required.'); - assert(util.isUInt32(json.version), 'Version must be a uint32.'); - assert(json.height === -1 || util.isUInt32(json.height), + assert(util.isU32(json.version), 'Version must be a uint32.'); + assert(json.height === -1 || util.isU32(json.height), 'Height must be a uint32.'); - assert(util.isUInt53(json.value), 'Value must be a uint53.'); + assert(util.isU64(json.value), 'Value must be a uint64.'); assert(typeof json.coinbase === 'boolean', 'Coinbase must be a boolean.'); this.version = json.version; @@ -277,7 +277,7 @@ Coin.prototype.fromJSON = function fromJSON(json) { if (json.hash != null) { assert(typeof json.hash === 'string', 'Hash must be a string.'); assert(json.hash.length === 64, 'Hash must be a string.'); - assert(util.isUInt32(json.index), 'Index must be a uint32.'); + assert(util.isU32(json.index), 'Index must be a uint32.'); this.hash = util.revHex(json.hash); this.index = json.index; } @@ -317,7 +317,7 @@ Coin.prototype.toWriter = function toWriter(bw) { bw.writeU32(this.version); bw.writeU32(height); - bw.write64(this.value); + bw.writeI64(this.value); bw.writeVarBytes(this.script.toRaw()); bw.writeU8(this.coinbase ? 1 : 0); @@ -330,7 +330,7 @@ Coin.prototype.toWriter = function toWriter(bw) { */ Coin.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -343,7 +343,7 @@ Coin.prototype.toRaw = function toRaw() { Coin.prototype.fromReader = function fromReader(br) { this.version = br.readU32(); this.height = br.readU32(); - this.value = br.read64(); + this.value = br.readI64(); this.script.fromRaw(br.readVarBytes()); this.coinbase = br.readU8() === 1; diff --git a/lib/primitives/headers.js b/lib/primitives/headers.js index 7599ad911..ecbda8898 100644 --- a/lib/primitives/headers.js +++ b/lib/primitives/headers.js @@ -30,7 +30,7 @@ function Headers(options) { this.parseOptions(options); } -util.inherits(Headers, AbstractBlock); +Object.setPrototypeOf(Headers.prototype, AbstractBlock.prototype); /** * Do non-contextual verification on the headers. @@ -58,7 +58,7 @@ Headers.prototype.getSize = function getSize() { */ Headers.prototype.toWriter = function toWriter(bw) { - this.writeAbbr(bw); + this.writeHead(bw); bw.writeVarint(0); return bw; }; @@ -69,7 +69,7 @@ Headers.prototype.toWriter = function toWriter(bw) { */ Headers.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -80,7 +80,7 @@ Headers.prototype.toRaw = function toRaw() { */ Headers.prototype.fromReader = function fromReader(br) { - this.parseAbbr(br); + this.readHead(br); br.readVarint(); return this; }; @@ -118,36 +118,6 @@ Headers.fromRaw = function fromRaw(data, enc) { return new Headers().fromRaw(data); }; -/** - * Inject properties from buffer reader. - * @private - * @param {BufferReader} br - */ - -Headers.prototype.fromAbbrReader = function fromAbbrReader(br) { - return this.parseAbbr(br); -}; - -/** - * Inject properties from serialized data. - * @private - * @param {Buffer} data - */ - -Headers.prototype.fromAbbr = function fromAbbr(data) { - return this.fromAbbrReader(new BufferReader(data)); -}; - -/** - * Instantiate headers from buffer reader. - * @param {BufferReader} br - * @returns {Headers} - */ - -Headers.fromAbbrReader = function fromAbbrReader(br) { - return new Headers().fromAbbrReader(br); -}; - /** * Instantiate headers from serialized data. * @param {Buffer} data @@ -155,10 +125,10 @@ Headers.fromAbbrReader = function fromAbbrReader(br) { * @returns {Headers} */ -Headers.fromAbbr = function fromAbbr(data, enc) { +Headers.fromHead = function fromHead(data, enc) { if (typeof data === 'string') data = Buffer.from(data, enc); - return new Headers().fromAbbr(data); + return new Headers().fromHead(data); }; /** @@ -168,8 +138,15 @@ Headers.fromAbbr = function fromAbbr(data, enc) { */ Headers.fromEntry = function fromEntry(entry) { - let headers = new Headers(entry); + const headers = new Headers(); + headers.version = entry.version; + headers.prevBlock = entry.prevBlock; + headers.merkleRoot = entry.merkleRoot; + headers.time = entry.time; + headers.bits = entry.bits; + headers.nonce = entry.nonce; headers._hash = Buffer.from(entry.hash, 'hex'); + headers._hhash = entry.hash; return headers; }; @@ -189,7 +166,7 @@ Headers.prototype.toHeaders = function toHeaders() { */ Headers.fromBlock = function fromBlock(block) { - let headers = new Headers(block); + const headers = new Headers(block); headers._hash = block._hash; headers._hhash = block._hhash; return headers; @@ -223,7 +200,7 @@ Headers.prototype.getJSON = function getJSON(network, view, height) { version: this.version, prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce }; @@ -272,11 +249,11 @@ Headers.prototype.format = function format(view, height) { return { hash: this.rhash(), height: height != null ? height : -1, - date: util.date(this.ts), + date: util.date(this.time), version: util.hex32(this.version), prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce }; @@ -291,7 +268,7 @@ Headers.prototype.format = function format(view, height) { Headers.isHeaders = function isHeaders(obj) { return obj && !obj.txs - && typeof obj.abbr === 'function' + && typeof obj.toHead === 'function' && typeof obj.toBlock !== 'function'; }; diff --git a/lib/primitives/input.js b/lib/primitives/input.js index 95ddb04eb..1a272533c 100644 --- a/lib/primitives/input.js +++ b/lib/primitives/input.js @@ -55,7 +55,7 @@ Input.prototype.fromOptions = function fromOptions(options) { this.script.fromOptions(options.script); if (options.sequence != null) { - assert(util.isUInt32(options.sequence), 'Sequence must be a uint32.'); + assert(util.isU32(options.sequence), 'Sequence must be a uint32.'); this.sequence = options.sequence; } @@ -81,7 +81,7 @@ Input.fromOptions = function fromOptions(options) { */ Input.prototype.clone = function clone() { - let input = new Input(); + const input = new Input(); input.prevout = this.prevout; input.script.inject(this.script); input.sequence = this.sequence; @@ -89,6 +89,28 @@ Input.prototype.clone = function clone() { return input; }; +/** + * Test equality against another input. + * @param {Input} input + * @returns {Boolean} + */ + +Input.prototype.equals = function equals(input) { + assert(Input.isInput(input)); + return this.prevout.equals(input.prevout); +}; + +/** + * Compare against another input (BIP69). + * @param {Input} input + * @returns {Number} + */ + +Input.prototype.compare = function compare(input) { + assert(Input.isInput(input)); + return this.prevout.compare(input.prevout); +}; + /** * Get the previous output script type as a string. * Will "guess" based on the input script and/or @@ -98,14 +120,14 @@ Input.prototype.clone = function clone() { */ Input.prototype.getType = function getType(coin) { - let type; - if (this.isCoinbase()) return 'coinbase'; if (coin) return coin.getType(); + let type; + if (this.witness.items.length > 0) type = this.witness.getInputType(); else @@ -122,10 +144,8 @@ Input.prototype.getType = function getType(coin) { */ Input.prototype.getRedeem = function getRedeem(coin) { - let redeem, prev; - if (this.isCoinbase()) - return; + return null; if (!coin) { if (this.witness.isScripthashInput()) @@ -134,10 +154,11 @@ Input.prototype.getRedeem = function getRedeem(coin) { if (this.script.isScripthashInput()) return this.script.getRedeem(); - return; + return null; } - prev = coin.script; + let prev = coin.script; + let redeem = null; if (prev.isScripthash()) { prev = this.script.getRedeem(); @@ -159,17 +180,15 @@ Input.prototype.getRedeem = function getRedeem(coin) { */ Input.prototype.getSubtype = function getSubtype(coin) { - let redeem, type; - if (this.isCoinbase()) - return; + return null; - redeem = this.getRedeem(coin); + const redeem = this.getRedeem(coin); if (!redeem) - return; + return null; - type = redeem.getType(); + const type = redeem.getType(); return Script.typesByVal[type].toLowerCase(); }; @@ -184,7 +203,7 @@ Input.prototype.getSubtype = function getSubtype(coin) { Input.prototype.getAddress = function getAddress(coin) { if (this.isCoinbase()) - return; + return null; if (coin) return coin.getAddress(); @@ -202,9 +221,11 @@ Input.prototype.getAddress = function getAddress(coin) { */ Input.prototype.getHash = function getHash(enc) { - let addr = this.getAddress(); + const addr = this.getAddress(); + if (!addr) - return; + return null; + return addr.getHash(enc); }; @@ -285,10 +306,9 @@ Input.prototype.toJSON = function toJSON(network, coin) { */ Input.prototype.getJSON = function getJSON(network, coin) { - let addr; - network = Network.get(network); + let addr; if (!coin) { addr = this.getAddress(); if (addr) @@ -313,7 +333,7 @@ Input.prototype.getJSON = function getJSON(network, coin) { Input.prototype.fromJSON = function fromJSON(json) { assert(json, 'Input data is required.'); - assert(util.isUInt32(json.sequence), 'Sequence must be a uint32.'); + assert(util.isU32(json.sequence), 'Sequence must be a uint32.'); this.prevout.fromJSON(json.prevout); this.script.fromJSON(json.script); this.witness.fromJSON(json.witness); @@ -347,7 +367,7 @@ Input.prototype.getSize = function getSize() { */ Input.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -490,11 +510,7 @@ Input.fromTX = function fromTX(tx, index) { */ Input.isInput = function isInput(obj) { - return obj - && typeof obj.prevout === 'object' - && typeof obj.script === 'object' - && typeof obj.witness === 'object' - && typeof obj.getAddress === 'function'; + return obj instanceof Input; }; /* diff --git a/lib/primitives/invitem.js b/lib/primitives/invitem.js index 397ccb7e6..74d9a0663 100644 --- a/lib/primitives/invitem.js +++ b/lib/primitives/invitem.js @@ -51,7 +51,7 @@ InvItem.types = { * @const {RevMap} */ -InvItem.typesByVal = util.revMap(InvItem.types); +InvItem.typesByVal = util.reverse(InvItem.types); /** * Witness bit for inv types. diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index 604a6eb7f..b7d9830b1 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -58,13 +58,11 @@ function KeyRing(options, network) { */ KeyRing.prototype.fromOptions = function fromOptions(options, network) { - let key = toKey(options); - let script = options.script; - let compressed = options.compressed; - if (!network) network = options.network; + let key = toKey(options); + if (Buffer.isBuffer(key)) return this.fromKey(key, network); @@ -86,10 +84,13 @@ KeyRing.prototype.fromOptions = function fromOptions(options, network) { this.nested = options.nested; } + const script = options.script; + const compress = options.compressed; + if (script) - return this.fromScript(key, script, compressed, network); + return this.fromScript(key, script, compress, network); - this.fromKey(key, compressed, network); + return this.fromKey(key, compress, network); }; /** @@ -121,22 +122,22 @@ KeyRing.prototype.refresh = function refresh() { * Inject data from private key. * @private * @param {Buffer} key - * @param {Boolean?} compressed + * @param {Boolean?} compress * @param {(NetworkType|Network)?} network */ -KeyRing.prototype.fromPrivate = function fromPrivate(key, compressed, network) { +KeyRing.prototype.fromPrivate = function fromPrivate(key, compress, network) { assert(Buffer.isBuffer(key), 'Private key must be a buffer.'); assert(secp256k1.privateKeyVerify(key), 'Not a valid private key.'); - if (typeof compressed !== 'boolean') { - network = compressed; - compressed = null; + if (typeof compress !== 'boolean') { + network = compress; + compress = null; } this.network = Network.get(network); this.privateKey = key; - this.publicKey = secp256k1.publicKeyCreate(key, compressed !== false); + this.publicKey = secp256k1.publicKeyCreate(key, compress !== false); return this; }; @@ -144,13 +145,13 @@ KeyRing.prototype.fromPrivate = function fromPrivate(key, compressed, network) { /** * Instantiate keyring from a private key. * @param {Buffer} key - * @param {Boolean?} compressed + * @param {Boolean?} compress * @param {(NetworkType|Network)?} network * @returns {KeyRing} */ -KeyRing.fromPrivate = function fromPrivate(key, compressed, network) { - return new KeyRing().fromPrivate(key, compressed, network); +KeyRing.fromPrivate = function fromPrivate(key, compress, network) { + return new KeyRing().fromPrivate(key, compress, network); }; /** @@ -171,31 +172,31 @@ KeyRing.prototype.fromPublic = function fromPublic(key, network) { /** * Generate a keyring. * @private + * @param {Boolean?} compress * @param {(Network|NetworkType)?} network * @returns {KeyRing} */ -KeyRing.prototype.generate = function generate(compressed, network) { - let key; - - if (typeof compressed !== 'boolean') { - network = compressed; - compressed = null; +KeyRing.prototype.generate = function generate(compress, network) { + if (typeof compress !== 'boolean') { + network = compress; + compress = null; } - key = secp256k1.generatePrivateKey(); + const key = secp256k1.generatePrivateKey(); - return this.fromKey(key, compressed, network); + return this.fromKey(key, compress, network); }; /** * Generate a keyring. + * @param {Boolean?} compress * @param {(Network|NetworkType)?} network * @returns {KeyRing} */ -KeyRing.generate = function generate(compressed, network) { - return new KeyRing().generate(compressed, network); +KeyRing.generate = function generate(compress, network) { + return new KeyRing().generate(compress, network); }; /** @@ -213,19 +214,20 @@ KeyRing.fromPublic = function fromPublic(key, network) { * Inject data from public key. * @private * @param {Buffer} privateKey + * @param {Boolean?} compress * @param {(NetworkType|Network)?} network */ -KeyRing.prototype.fromKey = function fromKey(key, compressed, network) { +KeyRing.prototype.fromKey = function fromKey(key, compress, network) { assert(Buffer.isBuffer(key), 'Key must be a buffer.'); - if (typeof compressed !== 'boolean') { - network = compressed; - compressed = null; + if (typeof compress !== 'boolean') { + network = compress; + compress = null; } if (key.length === 32) - return this.fromPrivate(key, compressed !== false, network); + return this.fromPrivate(key, compress !== false, network); return this.fromPublic(key, network); }; @@ -233,12 +235,13 @@ KeyRing.prototype.fromKey = function fromKey(key, compressed, network) { /** * Instantiate keyring from a public key. * @param {Buffer} publicKey + * @param {Boolean?} compress * @param {(NetworkType|Network)?} network * @returns {KeyRing} */ -KeyRing.fromKey = function fromKey(key, compressed, network) { - return new KeyRing().fromKey(key, compressed, network); +KeyRing.fromKey = function fromKey(key, compress, network) { + return new KeyRing().fromKey(key, compress, network); }; /** @@ -246,18 +249,19 @@ KeyRing.fromKey = function fromKey(key, compressed, network) { * @private * @param {Buffer} key * @param {Script} script + * @param {Boolean?} compress * @param {(NetworkType|Network)?} network */ -KeyRing.prototype.fromScript = function fromScript(key, script, compressed, network) { +KeyRing.prototype.fromScript = function fromScript(key, script, compress, network) { assert(script instanceof Script, 'Non-script passed into KeyRing.'); - if (typeof compressed !== 'boolean') { - network = compressed; - compressed = null; + if (typeof compress !== 'boolean') { + network = compress; + compress = null; } - this.fromKey(key, compressed, network); + this.fromKey(key, compress, network); this.script = script; return this; @@ -267,12 +271,13 @@ KeyRing.prototype.fromScript = function fromScript(key, script, compressed, netw * Instantiate keyring from script. * @param {Buffer} key * @param {Script} script + * @param {Boolean?} compress * @param {(NetworkType|Network)?} network * @returns {KeyRing} */ -KeyRing.fromScript = function fromScript(key, script, compressed, network) { - return new KeyRing().fromScript(key, script, compressed, network); +KeyRing.fromScript = function fromScript(key, script, compress, network) { + return new KeyRing().fromScript(key, script, compress, network); }; /** @@ -301,8 +306,8 @@ KeyRing.prototype.getSecretSize = function getSecretSize() { */ KeyRing.prototype.toSecret = function toSecret(network) { - let size = this.getSecretSize(); - let bw = new StaticWriter(size); + const size = this.getSecretSize(); + const bw = new StaticWriter(size); assert(this.privateKey, 'Cannot serialize without private key.'); @@ -330,24 +335,24 @@ KeyRing.prototype.toSecret = function toSecret(network) { */ KeyRing.prototype.fromSecret = function fromSecret(data, network) { - let br = new BufferReader(base58.decode(data), true); - let version, key, compressed; + const br = new BufferReader(base58.decode(data), true); + + const version = br.readU8(); - version = br.readU8(); network = Network.fromWIF(version, network); - key = br.readBytes(32); + const key = br.readBytes(32); + + let compress = false; if (br.left() > 4) { assert(br.readU8() === 1, 'Bad compression flag.'); - compressed = true; - } else { - compressed = false; + compress = true; } br.verifyChecksum(); - return this.fromPrivate(key, compressed, network); + return this.fromPrivate(key, compress, network); }; /** @@ -369,7 +374,7 @@ KeyRing.fromSecret = function fromSecret(data, network) { KeyRing.prototype.getPrivateKey = function getPrivateKey(enc) { if (!this.privateKey) - return; + return null; if (enc === 'base58') return this.toSecret(); @@ -411,17 +416,16 @@ KeyRing.prototype.getScript = function getScript() { */ KeyRing.prototype.getProgram = function getProgram() { - let hash, program; - if (!this.witness) - return; + return null; if (!this._program) { + let program; if (!this.script) { - hash = digest.hash160(this.publicKey); + const hash = digest.hash160(this.publicKey); program = Script.fromProgram(0, hash); } else { - hash = this.script.sha256(); + const hash = this.script.sha256(); program = Script.fromProgram(0, hash); } this._program = program; @@ -439,7 +443,7 @@ KeyRing.prototype.getProgram = function getProgram() { KeyRing.prototype.getNestedHash = function getNestedHash(enc) { if (!this.witness) - return; + return null; if (!this._nestedHash) this._nestedHash = this.getProgram().hash160(); @@ -456,15 +460,13 @@ KeyRing.prototype.getNestedHash = function getNestedHash(enc) { */ KeyRing.prototype.getNestedAddress = function getNestedAddress(enc) { - let hash, address; - if (!this.witness) - return; + return null; if (!this._nestedAddress) { - hash = this.getNestedHash(); - address = Address.fromScripthash(hash, this.network); - this._nestedAddress = address; + const hash = this.getNestedHash(); + const addr = Address.fromScripthash(hash, this.network); + this._nestedAddress = addr; } if (enc === 'base58') @@ -494,9 +496,9 @@ KeyRing.prototype.getScriptHash = function getScriptHash(enc) { * @returns {Buffer} */ -KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) { +KeyRing.prototype.getScriptHash160 = function getScriptHash160(enc) { if (!this.script) - return; + return null; if (!this._scriptHash160) this._scriptHash160 = this.script.hash160(); @@ -514,7 +516,7 @@ KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) { KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) { if (!this.script) - return; + return null; if (!this._scriptHash256) this._scriptHash256 = this.script.sha256(); @@ -531,20 +533,19 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) { */ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) { - let hash, address; - if (!this.script) - return; + return null; if (!this._scriptAddress) { + let addr; if (this.witness) { - hash = this.getScriptHash256(); - address = Address.fromWitnessScripthash(hash, this.network); + const hash = this.getScriptHash256(); + addr = Address.fromWitnessScripthash(hash, this.network); } else { - hash = this.getScriptHash160(); - address = Address.fromScripthash(hash, this.network); + const hash = this.getScriptHash160(); + addr = Address.fromScripthash(hash, this.network); } - this._scriptAddress = address; + this._scriptAddress = addr; } if (enc === 'base58') @@ -578,15 +579,16 @@ KeyRing.prototype.getKeyHash = function getKeyHash(enc) { */ KeyRing.prototype.getKeyAddress = function getKeyAddress(enc) { - let hash, address; - if (!this._keyAddress) { - hash = this.getKeyHash(); + const hash = this.getKeyHash(); + + let addr; if (this.witness) - address = Address.fromWitnessPubkeyhash(hash, this.network); + addr = Address.fromWitnessPubkeyhash(hash, this.network); else - address = Address.fromPubkeyhash(hash, this.network); - this._keyAddress = address; + addr = Address.fromPubkeyhash(hash, this.network); + + this._keyAddress = addr; } if (enc === 'base58') @@ -607,8 +609,10 @@ KeyRing.prototype.getKeyAddress = function getKeyAddress(enc) { KeyRing.prototype.getHash = function getHash(enc) { if (this.nested) return this.getNestedHash(enc); + if (this.script) return this.getScriptHash(enc); + return this.getKeyHash(enc); }; @@ -621,8 +625,10 @@ KeyRing.prototype.getHash = function getHash(enc) { KeyRing.prototype.getAddress = function getAddress(enc) { if (this.nested) return this.getNestedAddress(enc); + if (this.script) return this.getScriptAddress(enc); + return this.getKeyAddress(enc); }; @@ -868,7 +874,7 @@ KeyRing.prototype.toWriter = function toWriter(bw) { */ KeyRing.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -880,27 +886,25 @@ KeyRing.prototype.toRaw = function toRaw() { */ KeyRing.prototype.fromReader = function fromReader(br, network) { - let field, key, script; - this.network = Network.get(network); - field = br.readU8(); + const field = br.readU8(); this.witness = (field & 1) !== 0; this.nested = (field & 2) !== 0; - key = br.readVarBytes(); + const key = br.readVarBytes(); if (key.length === 32) { - let compressed = br.readU8() === 1; + const compress = br.readU8() === 1; this.privateKey = key; - this.publicKey = secp256k1.publicKeyCreate(key, compressed); + this.publicKey = secp256k1.publicKeyCreate(key, compress); } else { this.publicKey = key; assert(secp256k1.publicKeyVerify(key), 'Invalid public key.'); } - script = br.readVarBytes(); + const script = br.readVarBytes(); if (script.length > 0) this.script = Script.fromRaw(script); diff --git a/lib/primitives/memblock.js b/lib/primitives/memblock.js index 5209b30b1..fb91ec68f 100644 --- a/lib/primitives/memblock.js +++ b/lib/primitives/memblock.js @@ -7,11 +7,10 @@ 'use strict'; -const util = require('../utils/util'); const AbstractBlock = require('./abstractblock'); const Block = require('./block'); -const Script = require('../script/script'); const Headers = require('./headers'); +const Script = require('../script/script'); const BufferReader = require('../utils/reader'); const DUMMY = Buffer.alloc(0); @@ -40,26 +39,28 @@ function MemBlock() { if (!(this instanceof MemBlock)) return new MemBlock(); + AbstractBlock.call(this); + this._raw = DUMMY; } -util.inherits(MemBlock, AbstractBlock); +Object.setPrototypeOf(MemBlock.prototype, AbstractBlock.prototype); /** - * Memory flag. - * @const {Boolean} - * @default - * @memberof MemBlock# + * Test whether the block is a memblock. + * @returns {Boolean} */ -MemBlock.prototype.memory = true; +MemBlock.prototype.isMemory = function isMemory() { + return true; +}; /** * Serialize the block headers. * @returns {Buffer} */ -MemBlock.prototype.abbr = function abbr() { +MemBlock.prototype.toHead = function toHead() { return this._raw.slice(0, 80); }; @@ -106,31 +107,30 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() { */ MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() { - let br = new BufferReader(this._raw, true); - let count, script; + const br = new BufferReader(this._raw, true); br.seek(80); - count = br.readVarint(); + const txCount = br.readVarint(); - if (count === 0) + if (txCount === 0) return -1; br.seek(4); - count = br.readVarint(); + let inCount = br.readVarint(); - if (count === 0) { + if (inCount === 0) { if (br.readU8() !== 0) - count = br.readVarint(); + inCount = br.readVarint(); } - if (count === 0) + if (inCount === 0) return -1; br.seek(36); - script = br.readVarBytes(); + const script = br.readVarBytes(); return Script.getCoinbaseHeight(script); }; @@ -142,9 +142,9 @@ MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() { */ MemBlock.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); + const br = new BufferReader(data, true); - this.parseAbbr(br); + this.readHead(br); this._raw = br.data; @@ -187,7 +187,7 @@ MemBlock.prototype.toNormal = function toNormal() { */ MemBlock.prototype.toBlock = function toBlock() { - let block = Block.fromRaw(this._raw); + const block = Block.fromRaw(this._raw); block._hash = this._hash; block._hhash = this._hhash; @@ -211,7 +211,10 @@ MemBlock.prototype.toHeaders = function toHeaders() { */ MemBlock.isMemBlock = function isMemBlock(obj) { - return obj && obj.memory && typeof obj.toBlock === 'function'; + return obj + && typeof obj.toBlock === 'function' + && typeof obj.isMemory === 'function' + && obj.isMemory(); }; /* diff --git a/lib/primitives/merkleblock.js b/lib/primitives/merkleblock.js index 5ac28db6d..5ff6b7d9c 100644 --- a/lib/primitives/merkleblock.js +++ b/lib/primitives/merkleblock.js @@ -32,18 +32,18 @@ function MerkleBlock(options) { AbstractBlock.call(this); + this.txs = []; this.hashes = []; this.flags = DUMMY; this.totalTX = 0; - this.tree = null; - this.txs = []; + this._tree = null; if (options) this.fromOptions(options); } -util.inherits(MerkleBlock, AbstractBlock); +Object.setPrototypeOf(MerkleBlock.prototype, AbstractBlock.prototype); /** * Inject properties from options object. @@ -57,21 +57,26 @@ MerkleBlock.prototype.fromOptions = function fromOptions(options) { assert(options, 'MerkleBlock data is required.'); assert(Array.isArray(options.hashes)); assert(Buffer.isBuffer(options.flags)); - assert(util.isUInt32(options.totalTX)); + assert(util.isU32(options.totalTX)); if (options.hashes) { for (let hash of options.hashes) { if (typeof hash === 'string') hash = Buffer.from(hash, 'hex'); + assert(Buffer.isBuffer(hash)); this.hashes.push(hash); } } - if (options.flags) + if (options.flags) { + assert(Buffer.isBuffer(options.flags)); this.flags = options.flags; + } - if (options.totalTX != null) + if (options.totalTX != null) { + assert(util.isU32(options.totalTX)); this.totalTX = options.totalTX; + } return this; }; @@ -92,24 +97,14 @@ MerkleBlock.fromOptions = function fromOptions(data) { */ MerkleBlock.prototype.refresh = function refresh(all) { - this.tree = null; - this._refresh(all); -}; + this._refresh(); + this._tree = null; -/** - * Add a transaction to the block's tx vector. - * @param {TX} tx - * @returns {Number} - */ + if (!all) + return; -MerkleBlock.prototype.addTX = function addTX(tx) { - let tree = this.getTree(); - let hash = tx.hash('hex'); - let index = tree.map.get(hash); - - this.txs.push(tx); - - return index != null ? index : -1; + for (const tx of this.txs) + tx.refresh(); }; /** @@ -129,8 +124,8 @@ MerkleBlock.prototype.hasTX = function hasTX(hash) { */ MerkleBlock.prototype.indexOf = function indexOf(hash) { - let tree = this.getTree(); - let index = tree.map.get(hash); + const tree = this.getTree(); + const index = tree.map.get(hash); if (index == null) return -1; @@ -145,7 +140,7 @@ MerkleBlock.prototype.indexOf = function indexOf(hash) { */ MerkleBlock.prototype.verifyBody = function verifyBody() { - let [valid] = this.checkBody(); + const [valid] = this.checkBody(); return valid; }; @@ -156,12 +151,12 @@ MerkleBlock.prototype.verifyBody = function verifyBody() { */ MerkleBlock.prototype.checkBody = function checkBody() { - let tree = this.getTree(); + const tree = this.getTree(); if (tree.root !== this.merkleRoot) return [false, 'bad-txnmrklroot', 100]; - return [true, 'valid', 100]; + return [true, 'valid', 0]; }; /** @@ -171,14 +166,14 @@ MerkleBlock.prototype.checkBody = function checkBody() { */ MerkleBlock.prototype.getTree = function getTree() { - if (!this.tree) { + if (!this._tree) { try { - this.tree = this.extractTree(); + this._tree = this.extractTree(); } catch (e) { - this.tree = new PartialTree(); + this._tree = new PartialTree(); } } - return this.tree; + return this._tree; }; /** @@ -189,31 +184,29 @@ MerkleBlock.prototype.getTree = function getTree() { */ MerkleBlock.prototype.extractTree = function extractTree() { + const matches = []; + const indexes = []; + const map = new Map(); + const hashes = this.hashes; + const flags = this.flags; + const totalTX = this.totalTX; let bitsUsed = 0; let hashUsed = 0; - let matches = []; - let indexes = []; - let map = new Map(); let failed = false; - let hashes = this.hashes; - let flags = this.flags; - let totalTX = this.totalTX; let height = 0; - let root; - let width = (height) => { + const width = (height) => { return (totalTX + (1 << height) - 1) >>> height; }; - let traverse = (height, pos) => { - let parent, hash, left, right; - + const traverse = (height, pos) => { if (bitsUsed >= flags.length * 8) { failed = true; return encoding.ZERO_HASH; } - parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1; + const parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1; + bitsUsed++; if (height === 0 || !parent) { @@ -222,10 +215,10 @@ MerkleBlock.prototype.extractTree = function extractTree() { return encoding.ZERO_HASH; } - hash = hashes[hashUsed++]; + const hash = hashes[hashUsed++]; if (height === 0 && parent) { - let txid = hash.toString('hex'); + const txid = hash.toString('hex'); matches.push(hash); indexes.push(pos); map.set(txid, pos); @@ -234,7 +227,8 @@ MerkleBlock.prototype.extractTree = function extractTree() { return hash; } - left = traverse(height - 1, pos * 2); + const left = traverse(height - 1, pos * 2); + let right; if (pos * 2 + 1 < width(height - 1)) { right = traverse(height - 1, pos * 2 + 1); @@ -262,7 +256,7 @@ MerkleBlock.prototype.extractTree = function extractTree() { while (width(height) > 1) height++; - root = traverse(height, 0); + const root = traverse(height, 0); if (failed) throw new Error('Mutated merkle tree.'); @@ -307,11 +301,11 @@ MerkleBlock.prototype.format = function format(view, height) { return { hash: this.rhash(), height: height != null ? height : -1, - date: util.date(this.ts), + date: util.date(this.time), version: util.hex32(this.version), prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce, totalTX: this.totalTX, @@ -346,13 +340,13 @@ MerkleBlock.prototype.getSize = function getSize() { */ MerkleBlock.prototype.toWriter = function toWriter(bw) { - this.writeAbbr(bw); + this.writeHead(bw); bw.writeU32(this.totalTX); bw.writeVarint(this.hashes.length); - for (let hash of this.hashes) + for (const hash of this.hashes) bw.writeHash(hash); bw.writeVarBytes(this.flags); @@ -367,7 +361,7 @@ MerkleBlock.prototype.toWriter = function toWriter(bw) { */ MerkleBlock.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -378,13 +372,11 @@ MerkleBlock.prototype.toRaw = function toRaw() { */ MerkleBlock.prototype.fromReader = function fromReader(br) { - let count; - - this.parseAbbr(br); + this.readHead(br); this.totalTX = br.readU32(); - count = br.readVarint(); + const count = br.readVarint(); for (let i = 0; i < count; i++) this.hashes.push(br.readHash()); @@ -455,7 +447,7 @@ MerkleBlock.prototype.getJSON = function getJSON(network, view, height) { version: this.version, prevBlock: util.revHex(this.prevBlock), merkleRoot: util.revHex(this.merkleRoot), - ts: this.ts, + time: this.time, bits: this.bits, nonce: this.nonce, totalTX: this.totalTX, @@ -476,7 +468,7 @@ MerkleBlock.prototype.fromJSON = function fromJSON(json) { assert(json, 'MerkleBlock data is required.'); assert(Array.isArray(json.hashes)); assert(typeof json.flags === 'string'); - assert(util.isUInt32(json.totalTX)); + assert(util.isU32(json.totalTX)); this.parseJSON(json); @@ -512,9 +504,9 @@ MerkleBlock.fromJSON = function fromJSON(json) { */ MerkleBlock.fromBlock = function fromBlock(block, filter) { - let matches = []; + const matches = []; - for (let tx of block.txs) + for (const tx of block.txs) matches.push(tx.isWatched(filter) ? 1 : 0); return MerkleBlock.fromMatches(block, matches); @@ -529,18 +521,19 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) { */ MerkleBlock.fromHashes = function fromHashes(block, hashes) { - let filter = {}; - let matches = []; + const filter = new Set(); for (let hash of hashes) { if (Buffer.isBuffer(hash)) hash = hash.toString('hex'); - filter[hash] = true; + filter.add(hash); } - for (let tx of block.txs) { - let hash = tx.hash('hex'); - matches.push(filter[hash] ? 1 : 0); + const matches = []; + + for (const tx of block.txs) { + const hash = tx.hash('hex'); + matches.push(filter.has(hash) ? 1 : 0); } return MerkleBlock.fromMatches(block, matches); @@ -555,25 +548,23 @@ MerkleBlock.fromHashes = function fromHashes(block, hashes) { */ MerkleBlock.fromMatches = function fromMatches(block, matches) { - let txs = []; - let leaves = []; - let bits = []; - let hashes = []; - let totalTX = block.txs.length; + const txs = []; + const leaves = []; + const bits = []; + const hashes = []; + const totalTX = block.txs.length; let height = 0; - let flags, merkle; - let width = (height) => { + const width = (height) => { return (totalTX + (1 << height) - 1) >>> height; }; - let hash = (height, pos, leaves) => { - let left, right; - + const hash = (height, pos, leaves) => { if (height === 0) return leaves[pos]; - left = hash(height - 1, pos * 2, leaves); + const left = hash(height - 1, pos * 2, leaves); + let right; if (pos * 2 + 1 < width(height - 1)) right = hash(height - 1, pos * 2 + 1, leaves); @@ -583,7 +574,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) { return digest.root256(left, right); }; - let traverse = (height, pos, leaves, matches) => { + const traverse = (height, pos, leaves, matches) => { let parent = 0; for (let p = (pos << height); p < ((pos + 1) << height) && p < totalTX; p++) @@ -603,7 +594,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) { }; for (let i = 0; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; if (matches[i]) txs.push(tx); @@ -616,19 +607,19 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) { traverse(height, 0, leaves, matches); - flags = Buffer.allocUnsafe((bits.length + 7) / 8 | 0); + const flags = Buffer.allocUnsafe((bits.length + 7) / 8 | 0); flags.fill(0); for (let p = 0; p < bits.length; p++) flags[p / 8 | 0] |= bits[p] << (p % 8); - merkle = new MerkleBlock(); + const merkle = new MerkleBlock(); merkle._hash = block._hash; merkle._hhash = block._hhash; merkle.version = block.version; merkle.prevBlock = block.prevBlock; merkle.merkleRoot = block.merkleRoot; - merkle.ts = block.ts; + merkle.time = block.time; merkle.bits = block.bits; merkle.nonce = block.nonce; merkle.totalTX = totalTX; diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index 2351f246f..6ae12cf44 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -21,7 +21,7 @@ const encoding = require('../utils/encoding'); const consensus = require('../protocol/consensus'); const policy = require('../protocol/policy'); const Amount = require('../btc/amount'); -const opcodes = Script.opcodes; +const Stack = require('../script/stack'); /** * A mutable transaction object. @@ -56,7 +56,7 @@ function MTX(options) { this.fromOptions(options); } -util.inherits(MTX, TX); +Object.setPrototypeOf(MTX.prototype, TX.prototype); /** * Inject properties from options object. @@ -66,35 +66,30 @@ util.inherits(MTX, TX); MTX.prototype.fromOptions = function fromOptions(options) { if (options.version != null) { - assert(util.isUInt32(options.version), 'Version must a be uint32.'); + assert(util.isU32(options.version), 'Version must a be uint32.'); this.version = options.version; } - if (options.flag != null) { - assert(util.isUInt8(options.flag), 'Flag must be a uint8.'); - this.flag = options.flag; - } - if (options.inputs) { assert(Array.isArray(options.inputs), 'Inputs must be an array.'); - for (let input of options.inputs) + for (const input of options.inputs) this.addInput(input); } if (options.outputs) { assert(Array.isArray(options.outputs), 'Outputs must be an array.'); - for (let output of options.outputs) + for (const output of options.outputs) this.addOutput(output); } if (options.locktime != null) { - assert(util.isUInt32(options.locktime), 'Locktime must be a uint32.'); + assert(util.isU32(options.locktime), 'Locktime must be a uint32.'); this.locktime = options.locktime; } if (options.changeIndex != null) { if (options.changeIndex !== -1) { - assert(util.isUInt32(options.changeIndex), + assert(util.isU32(options.changeIndex), 'Change index must be a uint32.'); this.changeIndex = options.changeIndex; } else { @@ -122,7 +117,7 @@ MTX.fromOptions = function fromOptions(options) { */ MTX.prototype.clone = function clone() { - let mtx = new MTX(); + const mtx = new MTX(); mtx.inject(this); mtx.changeIndex = this.changeIndex; return mtx; @@ -139,7 +134,7 @@ MTX.prototype.clone = function clone() { */ MTX.prototype.addInput = function addInput(options) { - let input = Input.fromOptions(options); + const input = Input.fromOptions(options); this.inputs.push(input); return input; }; @@ -155,8 +150,8 @@ MTX.prototype.addInput = function addInput(options) { */ MTX.prototype.addOutpoint = function addOutpoint(outpoint) { - let prevout = Outpoint.fromOptions(outpoint); - let input = Input.fromOutpoint(prevout); + const prevout = Outpoint.fromOptions(outpoint); + const input = Input.fromOutpoint(prevout); this.inputs.push(input); return input; }; @@ -172,11 +167,9 @@ MTX.prototype.addOutpoint = function addOutpoint(outpoint) { */ MTX.prototype.addCoin = function addCoin(coin) { - let input; - assert(coin instanceof Coin, 'Cannot add non-coin.'); - input = Input.fromCoin(coin); + const input = Input.fromCoin(coin); this.inputs.push(input); this.view.addCoin(coin); @@ -198,15 +191,13 @@ MTX.prototype.addCoin = function addCoin(coin) { */ MTX.prototype.addTX = function addTX(tx, index, height) { - let input, coin; - assert(tx instanceof TX, 'Cannot add non-transaction.'); if (height == null) height = -1; - input = Input.fromTX(tx, index); - coin = Coin.fromTX(tx, index, height); + const input = Input.fromTX(tx, index); + const coin = Coin.fromTX(tx, index, height); this.inputs.push(input); this.view.addCoin(coin); @@ -231,7 +222,7 @@ MTX.prototype.addOutput = function addOutput(script, value) { let output; if (value != null) { - assert(util.isUInt53(value), 'Value must be a uint53.'); + assert(util.isU64(value), 'Value must be a uint64.'); output = Output.fromScript(script, value); } else { output = Output.fromOptions(script); @@ -408,7 +399,7 @@ MTX.prototype.getSigopsSize = function getSigopsSize() { */ MTX.prototype.verifyInputs = function verifyInputs(height) { - let [fee] = this.checkInputs(height); + const [fee] = this.checkInputs(height); return fee !== -1; }; @@ -438,28 +429,29 @@ MTX.prototype.checkInputs = function checkInputs(height) { */ MTX.prototype.scriptInput = function scriptInput(index, coin, ring) { - let input = this.inputs[index]; - let prev; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); assert(coin, 'No coin passed.'); // Don't bother with any below calculation // if the output is already templated. - if (input.script.length !== 0 - || input.witness.length !== 0) { + if (input.script.raw.length !== 0 + || input.witness.items.length !== 0) { return true; } // Get the previous output's script - prev = coin.script; + const prev = coin.script; // This is easily the hardest part about // building a transaction with segwit: // figuring out where the redeem script // and witness redeem scripts go. - if (prev.isScripthash()) { - let redeem = ring.getRedeem(prev.get(1)); + const sh = prev.getScripthash(); + + if (sh) { + const redeem = ring.getRedeem(sh); if (!redeem) return false; @@ -467,33 +459,37 @@ MTX.prototype.scriptInput = function scriptInput(index, coin, ring) { // Witness program nested in regular P2SH. if (redeem.isProgram()) { // P2WSH nested within pay-to-scripthash. - if (redeem.isWitnessScripthash()) { - prev = ring.getRedeem(redeem.get(1)); + const wsh = redeem.getWitnessScripthash(); + if (wsh) { + const wredeem = ring.getRedeem(wsh); - if (!prev) + if (!wredeem) return false; - if (!this.scriptVector(prev, input.witness, ring)) + const witness = this.scriptVector(wredeem, ring); + + if (!witness) return false; - input.witness.push(prev.toRaw()); - input.witness.compile(); + witness.push(wredeem.toRaw()); - input.script.push(redeem.toRaw()); - input.script.compile(); + input.witness.fromStack(witness); + input.script.fromItems([redeem.toRaw()]); return true; } // P2WPKH nested within pay-to-scripthash. - if (redeem.isWitnessPubkeyhash()) { - prev = Script.fromPubkeyhash(ring.getKeyHash()); + const wpkh = redeem.getWitnessPubkeyhash(); + if (wpkh) { + const pkh = Script.fromPubkeyhash(wpkh); + const witness = this.scriptVector(pkh, ring); - if (!this.scriptVector(prev, input.witness, ring)) + if (!witness) return false; - input.script.push(redeem.toRaw()); - input.script.compile(); + input.witness.fromStack(witness); + input.script.fromItems([redeem.toRaw()]); return true; } @@ -503,11 +499,14 @@ MTX.prototype.scriptInput = function scriptInput(index, coin, ring) { } // Regular P2SH. - if (!this.scriptVector(redeem, input.script, ring)) + const vector = this.scriptVector(redeem, ring); + + if (!vector) return false; - input.script.push(redeem.toRaw()); - input.script.compile(); + vector.push(redeem.toRaw()); + + input.script.fromStack(vector); return true; } @@ -515,29 +514,35 @@ MTX.prototype.scriptInput = function scriptInput(index, coin, ring) { // Witness program. if (prev.isProgram()) { // Bare P2WSH. - if (prev.isWitnessScripthash()) { - let redeem = ring.getRedeem(prev.get(1)); + const wsh = prev.getWitnessScripthash(); + if (wsh) { + const wredeem = ring.getRedeem(wsh); - if (!redeem) + if (!wredeem) return false; - if (!this.scriptVector(redeem, input.witness, ring)) + const vector = this.scriptVector(wredeem, ring); + + if (!vector) return false; - input.witness.push(redeem.toRaw()); - input.witness.compile(); + vector.push(wredeem.toRaw()); + + input.witness.fromStack(vector); return true; } // Bare P2WPKH. - if (prev.isWitnessPubkeyhash()) { - prev = Script.fromPubkeyhash(prev.get(1)); + const wpkh = prev.getWitnessPubkeyhash(); + if (wpkh) { + const pkh = Script.fromPubkeyhash(wpkh); + const vector = this.scriptVector(pkh, ring); - if (!this.scriptVector(prev, input.witness, ring)) + if (!vector) return false; - input.witness.compile(); + input.witness.fromStack(vector); return true; } @@ -547,63 +552,73 @@ MTX.prototype.scriptInput = function scriptInput(index, coin, ring) { } // Wow, a normal output! Praise be to Jengus and Gord. - return this.scriptVector(prev, input.script, ring); + const vector = this.scriptVector(prev, ring); + + if (!vector) + return false; + + input.script.fromStack(vector); + + return true; }; /** * Build script for a single vector * based on a previous script. * @param {Script} prev - * @param {Witness|Script} vector * @param {Buffer} ring * @return {Boolean} */ -MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) { +MTX.prototype.scriptVector = function scriptVector(prev, ring) { // P2PK - if (prev.isPubkey()) { - if (!prev.get(0).equals(ring.publicKey)) - return false; + const pk = prev.getPubkey(); + if (pk) { + if (!pk.equals(ring.publicKey)) + return null; - vector.set(0, opcodes.OP_0); + const stack = new Stack(); - return true; + stack.pushInt(0); + + return stack; } // P2PKH - if (prev.isPubkeyhash()) { - if (!prev.get(2).equals(ring.getKeyHash())) - return false; + const pkh = prev.getPubkeyhash(); + if (pkh) { + if (!pkh.equals(ring.getKeyHash())) + return null; - vector.set(0, opcodes.OP_0); - vector.set(1, ring.publicKey); + const stack = new Stack(); - return true; + stack.pushInt(0); + stack.pushData(ring.publicKey); + + return stack; } // Multisig - if (prev.isMultisig()) { - let n; - + const [, n] = prev.getMultisig(); + if (n !== -1) { if (prev.indexOf(ring.publicKey) === -1) - return false; + return null; // Technically we should create m signature slots, // but we create n signature slots so we can order // the signatures properly. - vector.set(0, opcodes.OP_0); + const stack = new Stack(); - // Grab `n` value (number of keys). - n = prev.getSmall(prev.length - 2); + stack.pushInt(0); // Fill script with `n` signature slots. for (let i = 0; i < n; i++) - vector.set(i + 1, opcodes.OP_0); + stack.pushInt(0); - return true; + return stack; } - return false; + return null; }; /** @@ -617,11 +632,11 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) { * @returns {Promise} */ -MTX.prototype.signInputAsync = function signInputAsync(index, coin, ring, type, pool) { +MTX.prototype.signInputAsync = async function signInputAsync(index, coin, ring, type, pool) { if (!pool) return this.signInput(index, coin, ring, type); - return pool.signInput(this, index, coin, ring, type, pool); + return await pool.signInput(this, index, coin, ring, type, pool); }; /** @@ -634,19 +649,18 @@ MTX.prototype.signInputAsync = function signInputAsync(index, coin, ring, type, */ MTX.prototype.signInput = function signInput(index, coin, ring, type) { - let input = this.inputs[index]; - let version = 0; - let redeem = false; - let key = ring.privateKey; - let prev, value, vector, sig, result; + const input = this.inputs[index]; + const key = ring.privateKey; assert(input, 'Input does not exist.'); assert(coin, 'No coin passed.'); // Get the previous output's script - prev = coin.script; - value = coin.value; - vector = input.script; + const value = coin.value; + let prev = coin.script; + let vector = input.script; + let version = 0; + let redeem = false; // Grab regular p2sh redeem script. if (prev.isScripthash()) { @@ -669,32 +683,51 @@ MTX.prototype.signInput = function signInput(index, coin, ring, type) { vector = input.witness; redeem = true; version = 1; - } else if (prev.isWitnessPubkeyhash()) { - prev = Script.fromPubkeyhash(prev.get(1)); - vector = input.witness; - redeem = false; - version = 1; + } else { + const wpkh = prev.getWitnessPubkeyhash(); + if (wpkh) { + prev = Script.fromPubkeyhash(wpkh); + vector = input.witness; + redeem = false; + version = 1; + } } // Create our signature. - sig = this.signature(index, prev, value, key, type, version); + const sig = this.signature(index, prev, value, key, type, version); if (redeem) { - redeem = vector.pop(); - result = this.signVector(prev, vector, sig, ring); - vector.push(redeem); - vector.compile(); - return result; + const stack = vector.toStack(); + const redeem = stack.pop(); + + const result = this.signVector(prev, stack, sig, ring); + + if (!result) + return false; + + result.push(redeem); + + vector.fromStack(result); + + return true; } - return this.signVector(prev, vector, sig, ring); + const stack = vector.toStack(); + const result = this.signVector(prev, stack, sig, ring); + + if (!result) + return false; + + vector.fromStack(result); + + return true; }; /** * Add a signature to a vector * based on a previous script. * @param {Script} prev - * @param {Witness|Script} vector + * @param {Stack} vector * @param {Buffer} sig * @param {KeyRing} ring * @return {Boolean} @@ -702,91 +735,93 @@ MTX.prototype.signInput = function signInput(index, coin, ring, type) { MTX.prototype.signVector = function signVector(prev, vector, sig, ring) { // P2PK - if (prev.isPubkey()) { + const pk = prev.getPubkey(); + if (pk) { // Make sure the pubkey is ours. - if (!ring.publicKey.equals(prev.get(0))) - return false; - - // Already signed. - if (Script.isSignature(vector.get(0))) - return true; + if (!ring.publicKey.equals(pk)) + return null; - if (vector.getSmall(0) !== 0) + if (vector.length === 0) throw new Error('Input has not been templated.'); + // Already signed. + if (vector.get(0).length > 0) + return vector; + vector.set(0, sig); - vector.compile(); - return true; + return vector; } // P2PKH - if (prev.isPubkeyhash()) { + const pkh = prev.getPubkeyhash(); + if (pkh) { // Make sure the pubkey hash is ours. - if (!ring.getKeyHash().equals(prev.get(2))) - return false; + if (!ring.getKeyHash().equals(pkh)) + return null; - // Already signed. - if (Script.isSignature(vector.get(0))) - return true; + if (vector.length !== 2) + throw new Error('Input has not been templated.'); - if (!Script.isKey(vector.get(1))) + if (vector.get(1).length === 0) throw new Error('Input has not been templated.'); + // Already signed. + if (vector.get(0).length > 0) + return vector; + vector.set(0, sig); - vector.compile(); - return true; + return vector; } // Multisig - if (prev.isMultisig()) { - let total = 0; - let keys = []; - let keyIndex; - - // Grab `m` value (number of sigs required). - let m = prev.getSmall(0); - - // Grab `n` value (number of keys). - let n = prev.getSmall(prev.length - 2); - - // Grab the redeem script's keys to figure - // out where our key should go. - for (let i = 1; i < prev.length - 2; i++) - keys.push(prev.get(i)); + const [m, n] = prev.getMultisig(); + if (m !== -1) { + if (vector.length < 2) + throw new Error('Input has not been templated.'); - if (vector.getSmall(0) !== 0) + if (vector.get(0).length !== 0) throw new Error('Input has not been templated.'); // Too many signature slots. Abort. if (vector.length - 1 > n) - return false; + throw new Error('Input has not been templated.'); // Count the number of current signatures. + let total = 0; for (let i = 1; i < vector.length; i++) { - if (Script.isSignature(vector.get(i))) + const item = vector.get(i); + if (item.length > 0) total++; } // Signatures are already finalized. if (total === m && vector.length - 1 === m) - return true; + return vector; // Add some signature slots for us to use if // there was for some reason not enough. while (vector.length - 1 < n) - vector.push(opcodes.OP_0); + vector.pushInt(0); + + // Grab the redeem script's keys to figure + // out where our key should go. + const keys = []; + for (const op of prev.code) { + if (op.data) + keys.push(op.data); + } // Find the key index so we can place // the signature in the same index. - keyIndex = util.indexOf(keys, ring.publicKey); + let keyIndex = util.indexOf(keys, ring.publicKey); // Our public key is not in the prev_out // script. We tried to sign a transaction // that is not redeemable by us. if (keyIndex === -1) - return false; + return null; // Offset key index by one to turn it into // "sig index". Accounts for OP_0 byte at @@ -797,7 +832,7 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) { // and increment the total number of // signatures. if (keyIndex < vector.length && total < m) { - if (vector.getSmall(keyIndex) === 0) { + if (vector.get(keyIndex).length === 0) { vector.set(keyIndex, sig); total++; } @@ -807,7 +842,8 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) { if (total >= m) { // Remove empty slots left over. for (let i = vector.length - 1; i >= 1; i--) { - if (vector.getSmall(i) === 0) + const item = vector.get(i); + if (item.length === 0) vector.remove(i); } @@ -823,15 +859,10 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) { assert(vector.length - 1 === m); } - vector.compile(); - - if (total !== m) - return false; - - return true; + return vector; } - return false; + return null; }; /** @@ -841,8 +872,8 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) { MTX.prototype.isSigned = function isSigned() { for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = this.view.getOutput(input); + const {prevout} = this.inputs[i]; + const coin = this.view.getOutput(prevout); if (!coin) return false; @@ -862,15 +893,14 @@ MTX.prototype.isSigned = function isSigned() { */ MTX.prototype.isInputSigned = function isInputSigned(index, coin) { - let input = this.inputs[index]; - let prev, vector, redeem, result; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); assert(coin, 'No coin passed.'); - prev = coin.script; - vector = input.script; - redeem = false; + let prev = coin.script; + let vector = input.script; + let redeem = false; // Grab redeem script if possible. if (prev.isScripthash()) { @@ -889,57 +919,69 @@ MTX.prototype.isInputSigned = function isInputSigned(index, coin) { return false; vector = input.witness; redeem = true; - } else if (prev.isWitnessPubkeyhash()) { - prev = Script.fromPubkeyhash(prev.get(1)); - vector = input.witness; - redeem = false; + } else { + const wpkh = prev.getWitnessPubkeyhash(); + if (wpkh) { + prev = Script.fromPubkeyhash(wpkh); + vector = input.witness; + redeem = false; + } } - if (redeem) { - redeem = vector.pop(); - result = this.isVectorSigned(prev, vector); - vector.push(redeem); - return result; - } + const stack = vector.toStack(); - return this.isVectorSigned(prev, vector); + if (redeem) + stack.pop(); + + return this.isVectorSigned(prev, stack); }; /** * Test whether a vector is fully-signed. * @param {Script} prev - * @param {Script|Witness} vector + * @param {Stack} vector * @returns {Boolean} */ MTX.prototype.isVectorSigned = function isVectorSigned(prev, vector) { if (prev.isPubkey()) { - if (!Script.isSignature(vector.get(0))) + if (vector.length !== 1) + return false; + + if (vector.get(0).length === 0) return false; + return true; } if (prev.isPubkeyhash()) { - if (!Script.isSignature(vector.get(0))) + if (vector.length !== 2) + return false; + + if (vector.get(0).length === 0) + return false; + + if (vector.get(1).length === 0) return false; + return true; } - if (prev.isMultisig()) { - // Grab `m` value (number of required sigs). - let m = prev.getSmall(0); - - // Ensure all members are signatures. - for (let i = 1; i < vector.length; i++) { - if (!Script.isSignature(vector.get(i))) - return false; - } + const [m] = prev.getMultisig(); + if (m !== -1) { // Ensure we have the correct number // of required signatures. if (vector.length - 1 !== m) return false; + // Ensure all members are signatures. + for (let i = 1; i < vector.length; i++) { + const item = vector.get(i); + if (item.length === 0) + return false; + } + return true; } @@ -954,17 +996,18 @@ MTX.prototype.isVectorSigned = function isVectorSigned(prev, vector) { */ MTX.prototype.template = function template(ring) { - let total = 0; - if (Array.isArray(ring)) { - for (let key of ring) + let total = 0; + for (const key of ring) total += this.template(key); return total; } + let total = 0; + for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = this.view.getOutput(input); + const {prevout} = this.inputs[i]; + const coin = this.view.getOutput(prevout); if (!coin) continue; @@ -991,19 +1034,20 @@ MTX.prototype.template = function template(ring) { */ MTX.prototype.sign = function sign(ring, type) { - let total = 0; - if (Array.isArray(ring)) { - for (let key of ring) + let total = 0; + for (const key of ring) total += this.sign(key, type); return total; } assert(ring.privateKey, 'No private key available.'); + let total = 0; + for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = this.view.getOutput(input); + const {prevout} = this.inputs[i]; + const coin = this.view.getOutput(prevout); if (!coin) continue; @@ -1034,11 +1078,11 @@ MTX.prototype.sign = function sign(ring, type) { * @returns {Promise} */ -MTX.prototype.signAsync = function signAsync(ring, type, pool) { +MTX.prototype.signAsync = async function signAsync(ring, type, pool) { if (!pool) return this.sign(ring, type); - return pool.sign(this, ring, type); + return await pool.sign(this, ring, type); }; /** @@ -1048,7 +1092,8 @@ MTX.prototype.signAsync = function signAsync(ring, type, pool) { */ MTX.prototype.estimateSize = async function estimateSize(estimate) { - let scale = consensus.WITNESS_SCALE_FACTOR; + const scale = consensus.WITNESS_SCALE_FACTOR; + let total = 0; // Calculate the size, minus the input scripts. @@ -1058,16 +1103,14 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { total += encoding.sizeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) total += output.getSize(); total += 4; // Add size for signatures and public keys - for (let input of this.inputs) { - let coin = this.view.getOutput(input); - let size = 0; - let prev; + for (const {prevout} of this.inputs) { + const coin = this.view.getOutput(prevout); // We're out of luck here. // Just assume it's a p2pkh. @@ -1077,36 +1120,36 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { } // Previous output script. - prev = coin.script; + const prev = coin.script; // P2PK if (prev.isPubkey()) { // varint script size - size += 1; + total += 1; // OP_PUSHDATA0 [signature] - size += 1 + 73; - total += size; + total += 1 + 73; continue; } // P2PKH if (prev.isPubkeyhash()) { // varint script size - size += 1; + total += 1; // OP_PUSHDATA0 [signature] - size += 1 + 73; + total += 1 + 73; // OP_PUSHDATA0 [key] - size += 1 + 33; - total += size; + total += 1 + 33; continue; } - if (prev.isMultisig()) { + const [m] = prev.getMultisig(); + if (m !== -1) { + let size = 0; // Bare Multisig // OP_0 size += 1; // OP_PUSHDATA0 [signature] ... - size += (1 + 73) * prev.getSmall(0); + size += (1 + 73) * m; // varint len size += encoding.sizeVarint(size); total += size; @@ -1115,6 +1158,7 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { // P2WPKH if (prev.isWitnessPubkeyhash()) { + let size = 0; // varint-items-len size += 1; // varint-len [signature] @@ -1129,7 +1173,7 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { // Call out to the custom estimator. if (estimate) { - size = await estimate(prev); + const size = await estimate(prev); if (size !== -1) { total += size; continue; @@ -1147,6 +1191,7 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { // P2WSH if (prev.isWitnessScripthash()) { + let size = 0; // varint-items-len size += 1; // 2-of-3 multisig input @@ -1173,39 +1218,74 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { */ MTX.prototype.selectCoins = function selectCoins(coins, options) { - let selector = new CoinSelector(this, options); + const selector = new CoinSelector(this, options); return selector.select(coins); }; /** - * Attempt to subtract a fee from outputs. + * Attempt to subtract a fee from a single output. + * @param {Number} index * @param {Amount} fee - * @param {Number?} index */ -MTX.prototype.subtractFee = function subtractFee(fee, index) { - if (typeof index === 'number') { - let output = this.outputs[index]; - let min; +MTX.prototype.subtractIndex = function subtractIndex(index, fee) { + assert(typeof index === 'number'); + assert(typeof fee === 'number'); - if (!output) - throw new Error('Subtraction index does not exist.'); + const output = this.outputs[index]; - min = fee + output.getDustThreshold(); + if (!output) + throw new Error('Subtraction index does not exist.'); - if (output.value < min) - throw new Error('Could not subtract fee.'); + if (output.value < fee + output.getDustThreshold()) + throw new Error('Could not subtract fee.'); + + output.value -= fee; +}; + +/** + * Attempt to subtract a fee from all outputs evenly. + * @param {Amount} fee + */ + +MTX.prototype.subtractFee = function subtractFee(fee) { + assert(typeof fee === 'number'); - output.value -= fee; + let outputs = 0; - return; + for (const output of this.outputs) { + // Ignore nulldatas and + // other OP_RETURN scripts. + if (output.script.isUnspendable()) + continue; + outputs += 1; } - for (let output of this.outputs) { - let min = fee + output.getDustThreshold(); + if (outputs === 0) + throw new Error('Could not subtract fee.'); + + const left = fee % outputs; + const share = (fee - left) / outputs; + + // First pass, remove even shares. + for (const output of this.outputs) { + if (output.script.isUnspendable()) + continue; + + if (output.value < share + output.getDustThreshold()) + throw new Error('Could not subtract fee.'); - if (output.value >= min) { - output.value -= fee; + output.value -= share; + } + + // Second pass, remove the remainder + // for the one unlucky output. + for (const output of this.outputs) { + if (output.script.isUnspendable()) + continue; + + if (output.value >= left + output.getDustThreshold()) { + output.value -= left; return; } } @@ -1221,36 +1301,39 @@ MTX.prototype.subtractFee = function subtractFee(fee, index) { */ MTX.prototype.fund = async function fund(coins, options) { - let select, change; - assert(options, 'Options are required.'); assert(options.changeAddress, 'Change address is required.'); assert(this.inputs.length === 0, 'TX is already funded.'); // Select necessary coins. - select = await this.selectCoins(coins, options); + const select = await this.selectCoins(coins, options); // Add coins to transaction. - for (let coin of select.chosen) + for (const coin of select.chosen) this.addCoin(coin); // Attempt to subtract fee. - if (select.shouldSubtract) - this.subtractFee(select.fee, select.subtractFee); + if (select.subtractFee) { + const index = select.subtractIndex; + if (index !== -1) + this.subtractIndex(index, select.fee); + else + this.subtractFee(select.fee); + } // Add a change output. - change = new Output(); - change.value = select.change; - change.script.fromAddress(select.changeAddress); + const output = new Output(); + output.value = select.change; + output.script.fromAddress(select.changeAddress); - if (change.isDust(policy.MIN_RELAY)) { + if (output.isDust(policy.MIN_RELAY)) { // Do nothing. Change is added to fee. this.changeIndex = -1; - assert.equal(this.getFee(), select.fee + select.change); + assert.strictEqual(this.getFee(), select.fee + select.change); } else { - this.outputs.push(change); + this.outputs.push(output); this.changeIndex = this.outputs.length - 1; - assert.equal(this.getFee(), select.fee); + assert.strictEqual(this.getFee(), select.fee); } return select; @@ -1262,7 +1345,7 @@ MTX.prototype.fund = async function fund(coins, options) { */ MTX.prototype.sortMembers = function sortMembers() { - let changeOutput; + let changeOutput = null; if (this.changeIndex !== -1) { changeOutput = this.outputs[this.changeIndex]; @@ -1303,10 +1386,10 @@ MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) { */ MTX.prototype.setLocktime = function setLocktime(locktime) { - assert(util.isUInt32(locktime), 'Locktime must be a uint32.'); + assert(util.isU32(locktime), 'Locktime must be a uint32.'); assert(this.inputs.length > 0, 'Cannot set sequence with no inputs.'); - for (let input of this.inputs) { + for (const input of this.inputs) { if (input.sequence === 0xffffffff) input.sequence = 0xfffffffe; } @@ -1322,18 +1405,19 @@ MTX.prototype.setLocktime = function setLocktime(locktime) { */ MTX.prototype.setSequence = function setSequence(index, locktime, seconds) { - let input = this.inputs[index]; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); - assert(util.isUInt32(locktime), 'Locktime must be a uint32.'); + assert(util.isU32(locktime), 'Locktime must be a uint32.'); this.version = 2; if (seconds) { locktime >>>= consensus.SEQUENCE_GRANULARITY; - locktime = consensus.SEQUENCE_TYPE_FLAG | locktime; + locktime &= consensus.SEQUENCE_MASK; + locktime |= consensus.SEQUENCE_TYPE_FLAG; } else { - locktime = consensus.SEQUENCE_MASK & locktime; + locktime &= consensus.SEQUENCE_MASK; } input.sequence = locktime; @@ -1419,6 +1503,15 @@ MTX.prototype.toTX = function toTX() { return new TX().inject(this); }; +/** + * Convert the MTX to a TX. + * @returns {Array} [tx, view] + */ + +MTX.prototype.commit = function commit() { + return [this.toTX(), this.view]; +}; + /** * Instantiate MTX from TX. * @param {TX} tx @@ -1436,10 +1529,7 @@ MTX.fromTX = function fromTX(tx) { */ MTX.isMTX = function isMTX(obj) { - return obj - && Array.isArray(obj.inputs) - && typeof obj.locktime === 'number' - && typeof obj.scriptInput === 'function'; + return obj instanceof MTX; }; /** @@ -1463,8 +1553,8 @@ function CoinSelector(tx, options) { this.fee = CoinSelector.MIN_FEE; this.selection = 'value'; - this.shouldSubtract = false; - this.subtractFee = null; + this.subtractFee = false; + this.subtractIndex = -1; this.height = -1; this.depth = -1; this.hardFee = -1; @@ -1521,48 +1611,54 @@ CoinSelector.prototype.fromOptions = function fromOptions(options) { if (options.subtractFee != null) { if (typeof options.subtractFee === 'number') { - assert(util.isUInt32(options.subtractFee)); - this.subtractFee = options.subtractFee; - this.shouldSubtract = true; + assert(util.isInt(options.subtractFee)); + assert(options.subtractFee >= -1); + this.subtractIndex = options.subtractFee; + this.subtractFee = this.subtractIndex !== -1; } else { assert(typeof options.subtractFee === 'boolean'); this.subtractFee = options.subtractFee; - this.shouldSubtract = options.subtractFee; } } + if (options.subtractIndex != null) { + assert(util.isInt(options.subtractIndex)); + assert(options.subtractIndex >= -1); + this.subtractIndex = options.subtractIndex; + this.subtractFee = this.subtractIndex !== -1; + } + if (options.height != null) { - assert(util.isNumber(options.height)); + assert(util.isInt(options.height)); assert(options.height >= -1); this.height = options.height; } if (options.confirmations != null) { - assert(util.isNumber(options.confirmations)); + assert(util.isInt(options.confirmations)); assert(options.confirmations >= -1); this.depth = options.confirmations; } if (options.depth != null) { - assert(util.isNumber(options.depth)); + assert(util.isInt(options.depth)); assert(options.depth >= -1); this.depth = options.depth; } if (options.hardFee != null) { - assert(util.isNumber(options.hardFee)); + assert(util.isInt(options.hardFee)); assert(options.hardFee >= -1); this.hardFee = options.hardFee; } if (options.rate != null) { - assert(util.isNumber(options.rate)); - assert(options.rate >= 0); + assert(util.isU64(options.rate)); this.rate = options.rate; } if (options.maxFee != null) { - assert(util.isNumber(options.maxFee)); + assert(util.isInt(options.maxFee)); assert(options.maxFee >= -1); this.maxFee = options.maxFee; } @@ -1573,7 +1669,7 @@ CoinSelector.prototype.fromOptions = function fromOptions(options) { } if (options.changeAddress) { - let addr = options.changeAddress; + const addr = options.changeAddress; if (typeof addr === 'string') { this.changeAddress = Address.fromString(addr); } else { @@ -1626,7 +1722,7 @@ CoinSelector.prototype.init = function init(coins) { */ CoinSelector.prototype.total = function total() { - if (this.shouldSubtract) + if (this.subtractFee) return this.outputValue; return this.outputValue + this.fee; }; @@ -1649,8 +1745,6 @@ CoinSelector.prototype.isFull = function isFull() { */ CoinSelector.prototype.isSpendable = function isSpendable(coin) { - let depth; - if (this.height === -1) return true; @@ -1667,7 +1761,7 @@ CoinSelector.prototype.isSpendable = function isSpendable(coin) { if (this.depth === -1) return true; - depth = coin.getDepth(this.height); + const depth = coin.getDepth(this.height); if (depth < this.depth) return false; @@ -1682,17 +1776,15 @@ CoinSelector.prototype.isSpendable = function isSpendable(coin) { */ CoinSelector.prototype.getFee = function getFee(size) { - let fee; - + // This is mostly here for testing. + // i.e. A fee rounded to the nearest + // kb is easier to predict ahead of time. if (this.round) { - // This is mostly here for testing. - // i.e. A fee rounded to the nearest - // kb is easier to predict ahead of time. - fee = policy.getRoundFee(size, this.rate); - } else { - fee = policy.getMinFee(size, this.rate); + const fee = policy.getRoundFee(size, this.rate); + return Math.min(fee, CoinSelector.MAX_FEE); } + const fee = policy.getMinFee(size, this.rate); return Math.min(fee, CoinSelector.MAX_FEE); }; @@ -1703,10 +1795,8 @@ CoinSelector.prototype.getFee = function getFee(size) { */ CoinSelector.prototype.fund = function fund() { - let coin; - while (this.index < this.coins.length) { - coin = this.coins[this.index++]; + const coin = this.coins[this.index++]; if (!this.isSpendable(coin)) continue; @@ -1761,15 +1851,13 @@ CoinSelector.prototype.select = async function select(coins) { */ CoinSelector.prototype.selectEstimate = async function selectEstimate() { - let change; - // Set minimum fee and do // an initial round of funding. this.fee = CoinSelector.MIN_FEE; this.fund(); // Add dummy output for change. - change = new Output(); + const change = new Output(); if (this.changeAddress) { change.script.fromAddress(this.changeAddress); @@ -1784,7 +1872,7 @@ CoinSelector.prototype.selectEstimate = async function selectEstimate() { // Keep recalculating the fee and funding // until we reach some sort of equilibrium. do { - let size = await this.tx.estimateSize(this.estimate); + const size = await this.tx.estimateSize(this.estimate); this.fee = this.getFee(size); @@ -1838,7 +1926,7 @@ function FundingError(msg, available, required) { Error.captureStackTrace(this, FundingError); } -util.inherits(FundingError, Error); +Object.setPrototypeOf(FundingError.prototype, Error.prototype); /* * Helpers @@ -1857,29 +1945,19 @@ function sortRandom(a, b) { function sortValue(a, b) { if (a.height === -1 && b.height !== -1) return 1; + if (a.height !== -1 && b.height === -1) return -1; + return b.value - a.value; } function sortInputs(a, b) { - let ahash = a.prevout.txid(); - let bhash = b.prevout.txid(); - let cmp = util.strcmp(ahash, bhash); - - if (cmp !== 0) - return cmp; - - return a.prevout.index - b.prevout.index; + return a.compare(b); } function sortOutputs(a, b) { - let cmp = a.value - b.value; - - if (cmp !== 0) - return cmp; - - return a.script.raw.compare(b.script.raw); + return a.compare(b); } /* diff --git a/lib/primitives/netaddress.js b/lib/primitives/netaddress.js index d053107da..497b3c6d3 100644 --- a/lib/primitives/netaddress.js +++ b/lib/primitives/netaddress.js @@ -19,14 +19,14 @@ const BufferReader = require('../utils/reader'); * @alias module:primitives.NetAddress * @constructor * @param {Object} options - * @param {Number?} options.ts - Timestamp. + * @param {Number?} options.time - Timestamp. * @param {Number?} options.services - Service bits. * @param {String?} options.host - IP address (IPv6 or IPv4). * @param {Number?} options.port - Port. * @property {Host} host * @property {Number} port * @property {Number} services - * @property {Number} ts + * @property {Number} time */ function NetAddress(options) { @@ -36,7 +36,7 @@ function NetAddress(options) { this.host = '0.0.0.0'; this.port = 0; this.services = 0; - this.ts = 0; + this.time = 0; this.hostname = '0.0.0.0:0'; this.raw = IP.ZERO_IP; @@ -75,9 +75,9 @@ NetAddress.prototype.fromOptions = function fromOptions(options) { this.services = options.services; } - if (options.ts) { - assert(typeof options.ts === 'number'); - this.ts = options.ts; + if (options.time) { + assert(typeof options.time === 'number'); + this.time = options.time; } this.hostname = IP.toHostname(this.host, this.port); @@ -183,7 +183,7 @@ NetAddress.prototype.equal = function equal(addr) { */ NetAddress.prototype.compare = function compare(addr) { - let cmp = this.raw.compare(addr.raw); + const cmp = this.raw.compare(addr.raw); if (cmp !== 0) return cmp; @@ -250,7 +250,7 @@ NetAddress.prototype.fromHost = function fromHost(host, port, network) { this.host = IP.toString(this.raw); this.port = port; this.services = NetAddress.DEFAULT_SERVICES; - this.ts = network.now(); + this.time = network.now(); this.hostname = IP.toHostname(this.host, this.port); @@ -278,11 +278,9 @@ NetAddress.fromHost = function fromHost(host, port, network) { */ NetAddress.prototype.fromHostname = function fromHostname(hostname, network) { - let addr; - network = Network.get(network); - addr = IP.fromHostname(hostname, network.port); + const addr = IP.fromHostname(hostname, network.port); return this.fromHost(addr.host, addr.port, network); }; @@ -306,8 +304,8 @@ NetAddress.fromHostname = function fromHostname(hostname, network) { */ NetAddress.prototype.fromSocket = function fromSocket(socket, network) { - let host = socket.remoteAddress; - let port = socket.remotePort; + const host = socket.remoteAddress; + const port = socket.remotePort; assert(typeof host === 'string'); assert(typeof port === 'number'); return this.fromHost(IP.normalize(host), port, network); @@ -332,7 +330,7 @@ NetAddress.fromSocket = function fromSocket(hostname, network) { */ NetAddress.prototype.fromReader = function fromReader(br, full) { - this.ts = full ? br.readU32() : 0; + this.time = full ? br.readU32() : 0; this.services = br.readU32(); // Note: hi service bits @@ -389,7 +387,7 @@ NetAddress.fromRaw = function fromRaw(data, full) { NetAddress.prototype.toWriter = function toWriter(bw, full) { if (full) - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU32(this.services); bw.writeU32(0); @@ -415,7 +413,7 @@ NetAddress.prototype.getSize = function getSize(full) { */ NetAddress.prototype.toRaw = function toRaw(full) { - let size = this.getSize(full); + const size = this.getSize(full); return this.toWriter(new StaticWriter(size), full).render(); }; @@ -429,7 +427,7 @@ NetAddress.prototype.toJSON = function toJSON() { host: this.host, port: this.port, services: this.services, - ts: this.ts + time: this.time }; }; @@ -441,15 +439,14 @@ NetAddress.prototype.toJSON = function toJSON() { */ NetAddress.prototype.fromJSON = function fromJSON(json) { - assert(util.isNumber(json.port)); - assert(json.port >= 0 && json.port <= 0xffff); - assert(util.isNumber(json.services)); - assert(util.isNumber(json.ts)); + assert(util.isU16(json.port)); + assert(util.isU32(json.services)); + assert(util.isU32(json.time)); this.raw = IP.toBuffer(json.host); this.host = json.host; this.port = json.port; this.services = json.services; - this.ts = json.ts; + this.time = json.time; this.hostname = IP.toHostname(this.host, this.port); return this; }; @@ -473,7 +470,7 @@ NetAddress.prototype.inspect = function inspect() { return ''; }; diff --git a/lib/primitives/outpoint.js b/lib/primitives/outpoint.js index 9195c61cd..d8cfd2a4e 100644 --- a/lib/primitives/outpoint.js +++ b/lib/primitives/outpoint.js @@ -6,8 +6,8 @@ 'use strict'; -const util = require('../utils/util'); const assert = require('assert'); +const util = require('../utils/util'); const StaticWriter = require('../utils/writer'); const BufferReader = require('../utils/reader'); const encoding = require('../utils/encoding'); @@ -31,7 +31,7 @@ function Outpoint(hash, index) { if (hash != null) { assert(typeof hash === 'string', 'Hash must be a string.'); - assert(util.isUInt32(index), 'Index must be a uint32.'); + assert(util.isU32(index), 'Index must be a uint32.'); this.hash = hash; this.index = index; } @@ -46,7 +46,7 @@ function Outpoint(hash, index) { Outpoint.prototype.fromOptions = function fromOptions(options) { assert(options, 'Outpoint data is required.'); assert(typeof options.hash === 'string', 'Hash must be a string.'); - assert(util.isUInt32(options.index), 'Index must be a uint32.'); + assert(util.isU32(options.index), 'Index must be a uint32.'); this.hash = options.hash; this.index = options.index; return this; @@ -62,6 +62,47 @@ Outpoint.fromOptions = function fromOptions(options) { return new Outpoint().fromOptions(options); }; +/** + * Clone the outpoint. + * @returns {Outpoint} + */ + +Outpoint.prototype.clone = function clone() { + const outpoint = new Outpoint(); + outpoint.hash = this.value; + outpoint.index = this.index; + return outpoint; +}; + +/** + * Test equality against another outpoint. + * @param {Outpoint} prevout + * @returns {Boolean} + */ + +Outpoint.prototype.equals = function equals(prevout) { + assert(Outpoint.isOutpoint(prevout)); + return this.hash === prevout.hash + && this.index === prevout.index; +}; + +/** + * Compare against another outpoint (BIP69). + * @param {Outpoint} prevout + * @returns {Number} + */ + +Outpoint.prototype.compare = function compare(prevout) { + assert(Outpoint.isOutpoint(prevout)); + + const cmp = util.strcmp(this.txid(), prevout.txid()); + + if (cmp !== 0) + return cmp; + + return this.index - prevout.index; +}; + /** * Test whether the outpoint is null (hash of zeroes * with max-u32 index). Used to detect coinbases. @@ -110,7 +151,7 @@ Outpoint.prototype.toKey = function toKey() { Outpoint.prototype.fromKey = function fromKey(key) { assert(key.length > 64); this.hash = key.slice(0, 64); - this.index = +key.slice(64); + this.index = parseInt(key.slice(64), 10); return this; }; @@ -204,7 +245,7 @@ Outpoint.fromRaw = function fromRaw(data) { Outpoint.prototype.fromJSON = function fromJSON(json) { assert(json, 'Outpoint data is required.'); assert(typeof json.hash === 'string', 'Hash must be a string.'); - assert(util.isUInt32(json.index), 'Index must be a uint32.'); + assert(util.isU32(json.index), 'Index must be a uint32.'); this.hash = util.revHex(json.hash); this.index = json.index; return this; @@ -293,10 +334,7 @@ Outpoint.prototype.inspect = function inspect() { */ Outpoint.isOutpoint = function isOutpoint(obj) { - return obj - && typeof obj.hash === 'string' - && typeof obj.index === 'number' - && typeof obj.toKey === 'function'; + return obj instanceof Outpoint; }; /* diff --git a/lib/primitives/output.js b/lib/primitives/output.js index 040c116e7..4d21f035a 100644 --- a/lib/primitives/output.js +++ b/lib/primitives/output.js @@ -48,7 +48,7 @@ Output.prototype.fromOptions = function fromOptions(options) { assert(options, 'Output data is required.'); if (options.value) { - assert(util.isUInt53(options.value), 'Value must be a uint53.'); + assert(util.isU64(options.value), 'Value must be a uint64.'); this.value = options.value; } @@ -87,7 +87,7 @@ Output.prototype.fromScript = function fromScript(script, value) { script = Script.fromAddress(script); assert(script instanceof Script, 'Script must be a Script.'); - assert(util.isUInt53(value), 'Value must be a uint53.'); + assert(util.isU64(value), 'Value must be a uint64.'); this.script = script; this.value = value; @@ -112,12 +112,41 @@ Output.fromScript = function fromScript(script, value) { */ Output.prototype.clone = function clone() { - let output = new Output(); + const output = new Output(); output.value = this.value; output.script.inject(this.script); return output; }; +/** + * Test equality against another output. + * @param {Output} output + * @returns {Boolean} + */ + +Output.prototype.equals = function equals(output) { + assert(Output.isOutput(output)); + return this.value === output.value + && this.script.equals(output.script); +}; + +/** + * Compare against another output (BIP69). + * @param {Output} output + * @returns {Number} + */ + +Output.prototype.compare = function compare(output) { + assert(Output.isOutput(output)); + + const cmp = this.value - output.value; + + if (cmp !== 0) + return cmp; + + return this.script.compare(output.script); +}; + /** * Get the script type as a string. * @returns {ScriptType} type @@ -143,9 +172,11 @@ Output.prototype.getAddress = function getAddress() { */ Output.prototype.getHash = function getHash(enc) { - let addr = this.getAddress(); + const addr = this.getAddress(); + if (!addr) - return; + return null; + return addr.getHash(enc); }; @@ -203,13 +234,12 @@ Output.prototype.getJSON = function getJSON(network) { */ Output.prototype.getDustThreshold = function getDustThreshold(rate) { - let scale = consensus.WITNESS_SCALE_FACTOR; - let size; + const scale = consensus.WITNESS_SCALE_FACTOR; if (this.script.isUnspendable()) return 0; - size = this.getSize(); + let size = this.getSize(); if (this.script.isProgram()) { // 75% segwit discount applied to script size. @@ -248,7 +278,7 @@ Output.prototype.isDust = function isDust(rate) { Output.prototype.fromJSON = function fromJSON(json) { assert(json, 'Output data is required.'); - assert(util.isUInt53(json.value), 'Value must be a uint53.'); + assert(util.isU64(json.value), 'Value must be a uint64.'); this.value = json.value; this.script.fromJSON(json.script); return this; @@ -270,7 +300,7 @@ Output.fromJSON = function fromJSON(json) { */ Output.prototype.toWriter = function toWriter(bw) { - bw.write64(this.value); + bw.writeI64(this.value); bw.writeVarBytes(this.script.toRaw()); return bw; }; @@ -282,7 +312,7 @@ Output.prototype.toWriter = function toWriter(bw) { */ Output.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -293,7 +323,7 @@ Output.prototype.toRaw = function toRaw() { */ Output.prototype.fromReader = function fromReader(br) { - this.value = br.read64(); + this.value = br.readI64(); this.script.fromRaw(br.readVarBytes()); return this; }; @@ -338,10 +368,7 @@ Output.fromRaw = function fromRaw(data, enc) { */ Output.isOutput = function isOutput(obj) { - return obj - && typeof obj.value === 'number' - && typeof obj.script === 'object' - && typeof obj.getAddress === 'function'; + return obj instanceof Output; }; /* diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index ae9de01be..2849e039b 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -24,7 +24,7 @@ const InvItem = require('./invitem'); const Bloom = require('../utils/bloom'); const consensus = require('../protocol/consensus'); const policy = require('../protocol/policy'); -const {ScriptError} = require('../script/common'); +const ScriptError = require('../script/scripterror'); const hashType = Script.hashType; /** @@ -47,7 +47,6 @@ function TX(options) { return new TX(options); this.version = 1; - this.flag = 1; this.inputs = []; this.outputs = []; this.locktime = 0; @@ -61,6 +60,7 @@ function TX(options) { this._raw = null; this._size = -1; this._witness = -1; + this._sigops = -1; this._hashPrevouts = null; this._hashSequence = null; @@ -80,29 +80,24 @@ TX.prototype.fromOptions = function fromOptions(options) { assert(options, 'TX data is required.'); if (options.version != null) { - assert(util.isUInt32(options.version), 'Version must be a uint32.'); + assert(util.isU32(options.version), 'Version must be a uint32.'); this.version = options.version; } - if (options.flag != null) { - assert(util.isUInt8(options.flag), 'Flag must be a uint8.'); - this.flag = options.flag; - } - if (options.inputs) { assert(Array.isArray(options.inputs), 'Inputs must be an array.'); - for (let input of options.inputs) + for (const input of options.inputs) this.inputs.push(new Input(input)); } if (options.outputs) { assert(Array.isArray(options.outputs), 'Outputs must be an array.'); - for (let output of options.outputs) + for (const output of options.outputs) this.outputs.push(new Output(output)); } if (options.locktime != null) { - assert(util.isUInt32(options.locktime), 'Locktime must be a uint32.'); + assert(util.isU32(options.locktime), 'Locktime must be a uint32.'); this.locktime = options.locktime; } @@ -138,12 +133,11 @@ TX.prototype.clone = function clone() { TX.prototype.inject = function inject(tx) { this.version = tx.version; - this.flag = tx.flag; - for (let input of tx.inputs) + for (const input of tx.inputs) this.inputs.push(input.clone()); - for (let output of tx.outputs) + for (const output of tx.outputs) this.outputs.push(output.clone()); this.locktime = tx.locktime; @@ -163,6 +157,7 @@ TX.prototype.refresh = function refresh() { this._raw = null; this._size = -1; this._witness = -1; + this._sigops = -1; this._hashPrevouts = null; this._hashSequence = null; @@ -175,26 +170,26 @@ TX.prototype.refresh = function refresh() { * @returns {Hash|Buffer} hash */ -TX.prototype.hash = function _hash(enc) { - let hash = this._hash; +TX.prototype.hash = function hash(enc) { + let h = this._hash; - if (!hash) { - hash = digest.hash256(this.toNormal()); + if (!h) { + h = digest.hash256(this.toNormal()); if (!this.mutable) - this._hash = hash; + this._hash = h; } if (enc === 'hex') { let hex = this._hhash; if (!hex) { - hex = hash.toString('hex'); + hex = h.toString('hex'); if (!this.mutable) this._hhash = hex; } - hash = hex; + h = hex; } - return hash; + return h; }; /** @@ -207,11 +202,11 @@ TX.prototype.hash = function _hash(enc) { */ TX.prototype.witnessHash = function witnessHash(enc) { - let hash = this._whash; - if (!this.hasWitness()) return this.hash(enc); + let hash = this._whash; + if (!hash) { hash = digest.hash256(this.toRaw()); if (!this.mutable) @@ -287,8 +282,6 @@ TX.prototype.toNormalWriter = function toNormalWriter(bw) { */ TX.prototype.frame = function frame() { - let raw; - if (this.mutable) { assert(!this._raw); if (this.hasWitness()) @@ -297,20 +290,21 @@ TX.prototype.frame = function frame() { } if (this._raw) { - assert(this._size > 0); + assert(this._size >= 0); assert(this._witness >= 0); - raw = new RawTX(this._size, this._witness); + const raw = new RawTX(this._size, this._witness); raw.data = this._raw; return raw; } + let raw; if (this.hasWitness()) raw = this.frameWitness(); else raw = this.frameNormal(); this._raw = raw.data; - this._size = raw.total; + this._size = raw.size; this._witness = raw.witness; return raw; @@ -318,7 +312,7 @@ TX.prototype.frame = function frame() { /** * Calculate total size and size of the witness bytes. - * @returns {Object} Contains `total` and `witness`. + * @returns {Object} Contains `size` and `witness`. */ TX.prototype.getSizes = function getSizes() { @@ -337,7 +331,7 @@ TX.prototype.getSizes = function getSizes() { */ TX.prototype.getVirtualSize = function getVirtualSize() { - let scale = consensus.WITNESS_SCALE_FACTOR; + const scale = consensus.WITNESS_SCALE_FACTOR; return (this.getWeight() + scale - 1) / scale | 0; }; @@ -349,9 +343,9 @@ TX.prototype.getVirtualSize = function getVirtualSize() { */ TX.prototype.getSigopsSize = function getSigopsSize(sigops) { - let scale = consensus.WITNESS_SCALE_FACTOR; - let bytes = policy.BYTES_PER_SIGOP; - let weight = Math.max(this.getWeight(), sigops * bytes); + const scale = consensus.WITNESS_SCALE_FACTOR; + const bytes = policy.BYTES_PER_SIGOP; + const weight = Math.max(this.getWeight(), sigops * bytes); return (weight + scale - 1) / scale | 0; }; @@ -362,9 +356,9 @@ TX.prototype.getSigopsSize = function getSigopsSize(sigops) { */ TX.prototype.getWeight = function getWeight() { - let raw = this.getSizes(); - let base = raw.total - raw.witness; - return base * (consensus.WITNESS_SCALE_FACTOR - 1) + raw.total; + const raw = this.getSizes(); + const base = raw.size - raw.witness; + return base * (consensus.WITNESS_SCALE_FACTOR - 1) + raw.size; }; /** @@ -374,7 +368,7 @@ TX.prototype.getWeight = function getWeight() { */ TX.prototype.getSize = function getSize() { - return this.getSizes().total; + return this.getSizes().size; }; /** @@ -385,8 +379,8 @@ TX.prototype.getSize = function getSize() { */ TX.prototype.getBaseSize = function getBaseSize() { - let raw = this.getSizes(); - return raw.total - raw.witness; + const raw = this.getSizes(); + return raw.size - raw.witness; }; /** @@ -398,7 +392,7 @@ TX.prototype.hasWitness = function hasWitness() { if (this._witness !== -1) return this._witness !== 0; - for (let input of this.inputs) { + for (const input of this.inputs) { if (input.witness.items.length > 0) return true; } @@ -432,7 +426,7 @@ TX.prototype.signatureHash = function signatureHash(index, prev, value, type, ve if (version === 1) return this.signatureHashV1(index, prev, value, type); - assert(false, 'Unknown sighash version.'); + throw new Error('Unknown sighash version.'); }; /** @@ -445,8 +439,6 @@ TX.prototype.signatureHash = function signatureHash(index, prev, value, type, ve */ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { - let size, bw; - if ((type & 0x1f) === hashType.SINGLE) { // Bitcoind used to return 1 as an error code: // it ended up being treated like a hash. @@ -458,9 +450,8 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { prev = prev.removeSeparators(); // Calculate buffer size. - size = this.hashSize(index, prev, type); - - bw = new StaticWriter(size); + const size = this.hashSize(index, prev, type); + const bw = new StaticWriter(size); bw.writeU32(this.version); @@ -468,7 +459,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { if (type & hashType.ANYONECANPAY) { // Serialize only the current // input if ANYONECANPAY. - let input = this.inputs[index]; + const input = this.inputs[index]; // Count. bw.writeVarint(1); @@ -483,7 +474,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { } else { bw.writeVarint(this.inputs.length); for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; + const input = this.inputs[i]; // Outpoint. input.prevout.toWriter(bw); @@ -520,7 +511,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { break; } case hashType.SINGLE: { - let output = this.outputs[index]; + const output = this.outputs[index]; // Drop all outputs after the // current input index if SINGLE. @@ -529,7 +520,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { for (let i = 0; i < index; i++) { // Null all outputs not at // current input index. - bw.write64(-1); + bw.writeI64(-1); bw.writeVarint(0); } @@ -542,7 +533,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { default: { // Regular output serialization if ALL. bw.writeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) output.toWriter(bw); break; } @@ -594,7 +585,7 @@ TX.prototype.hashSize = function hashSize(index, prev, type) { break; default: size += encoding.sizeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) size += output.getSize(); break; } @@ -615,19 +606,18 @@ TX.prototype.hashSize = function hashSize(index, prev, type) { */ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type) { + const input = this.inputs[index]; let prevouts = encoding.ZERO_HASH; let sequences = encoding.ZERO_HASH; let outputs = encoding.ZERO_HASH; - let input = this.inputs[index]; - let bw, size; if (!(type & hashType.ANYONECANPAY)) { if (this._hashPrevouts) { prevouts = this._hashPrevouts; } else { - let bw = new StaticWriter(this.inputs.length * 36); + const bw = new StaticWriter(this.inputs.length * 36); - for (let input of this.inputs) + for (const input of this.inputs) input.prevout.toWriter(bw); prevouts = digest.hash256(bw.render()); @@ -643,9 +633,9 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type if (this._hashSequence) { sequences = this._hashSequence; } else { - let bw = new StaticWriter(this.inputs.length * 4); + const bw = new StaticWriter(this.inputs.length * 4); - for (let input of this.inputs) + for (const input of this.inputs) bw.writeU32(input.sequence); sequences = digest.hash256(bw.render()); @@ -661,14 +651,13 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type outputs = this._hashOutputs; } else { let size = 0; - let bw; - for (let output of this.outputs) + for (const output of this.outputs) size += output.getSize(); - bw = new StaticWriter(size); + const bw = new StaticWriter(size); - for (let output of this.outputs) + for (const output of this.outputs) output.toWriter(bw); outputs = digest.hash256(bw.render()); @@ -677,12 +666,12 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type this._hashOutputs = outputs; } } else if ((type & 0x1f) === hashType.SINGLE && index < this.outputs.length) { - let output = this.outputs[index]; + const output = this.outputs[index]; outputs = digest.hash256(output.toRaw()); } - size = 156 + prev.getVarSize(); - bw = new StaticWriter(size); + const size = 156 + prev.getVarSize(); + const bw = new StaticWriter(size); bw.writeU32(this.version); bw.writeBytes(prevouts); @@ -690,7 +679,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type bw.writeHash(input.prevout.hash); bw.writeU32(input.prevout.index); bw.writeVarBytes(prev.toRaw()); - bw.write64(value); + bw.writeI64(value); bw.writeU32(input.sequence); bw.writeBytes(outputs); bw.writeU32(this.locktime); @@ -711,13 +700,11 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type */ TX.prototype.checksig = function checksig(index, prev, value, sig, key, version) { - let type, hash; - if (sig.length === 0) return false; - type = sig[sig.length - 1]; - hash = this.signatureHash(index, prev, value, type, version); + const type = sig[sig.length - 1]; + const hash = this.signatureHash(index, prev, value, type, version); return secp256k1.verify(hash, sig.slice(0, -1), key); }; @@ -736,18 +723,15 @@ TX.prototype.checksig = function checksig(index, prev, value, sig, key, version) */ TX.prototype.signature = function signature(index, prev, value, key, type, version) { - let hash, sig, bw; - if (type == null) type = hashType.ALL; if (version == null) version = 0; - hash = this.signatureHash(index, prev, value, type, version); - - sig = secp256k1.sign(hash, key); - bw = new StaticWriter(sig.length + 1); + const hash = this.signatureHash(index, prev, value, type, version); + const sig = secp256k1.sign(hash, key); + const bw = new StaticWriter(sig.length + 1); bw.writeBytes(sig); bw.writeU8(type); @@ -770,8 +754,8 @@ TX.prototype.check = function check(view, flags) { return; for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = view.getOutput(input); + const {prevout} = this.inputs[i]; + const coin = view.getOutput(prevout); if (!coin) throw new ScriptError('UNKNOWN_ERROR', 'No coin available.'); @@ -790,7 +774,7 @@ TX.prototype.check = function check(view, flags) { */ TX.prototype.checkInput = function checkInput(index, coin, flags) { - let input = this.inputs[index]; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); assert(coin, 'No coin passed.'); @@ -822,10 +806,12 @@ TX.prototype.checkAsync = async function checkAsync(view, flags, pool) { if (this.isCoinbase()) return; - if (!pool) - return this.check(view, flags); + if (!pool) { + this.check(view, flags); + return; + } - return await pool.check(this, view, flags); + await pool.check(this, view, flags); }; /** @@ -839,15 +825,17 @@ TX.prototype.checkAsync = async function checkAsync(view, flags, pool) { */ TX.prototype.checkInputAsync = async function checkInputAsync(index, coin, flags, pool) { - let input = this.inputs[index]; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); assert(coin, 'No coin passed.'); - if (!pool) - return this.checkInput(index, coin, flags); + if (!pool) { + this.checkInput(index, coin, flags); + return; + } - return await pool.checkInput(this, index, coin, flags); + await pool.checkInput(this, index, coin, flags); }; /** @@ -949,7 +937,7 @@ TX.prototype.isRBF = function isRBF() { if (this.version === 2) return false; - for (let input of this.inputs) { + for (const input of this.inputs) { if (input.isRBF()) return true; } @@ -979,8 +967,8 @@ TX.prototype.getFee = function getFee(view) { TX.prototype.getInputValue = function getInputValue(view) { let total = 0; - for (let input of this.inputs) { - let coin = view.getOutput(input); + for (const {prevout} of this.inputs) { + const coin = view.getOutput(prevout); if (!coin) return 0; @@ -999,7 +987,7 @@ TX.prototype.getInputValue = function getInputValue(view) { TX.prototype.getOutputValue = function getOutputValue() { let total = 0; - for (let output of this.outputs) + for (const output of this.outputs) total += output.value; return total; @@ -1012,22 +1000,21 @@ TX.prototype.getOutputValue = function getOutputValue() { * @returns {Array} [addrs, table] */ -TX.prototype._getInputAddresses = function getInputAddresses(view) { - let table = {}; - let addrs = []; +TX.prototype._getInputAddresses = function _getInputAddresses(view) { + const table = Object.create(null); + const addrs = []; if (this.isCoinbase()) return [addrs, table]; - for (let input of this.inputs) { - let coin = view ? view.getOutput(input) : null; - let addr = input.getAddress(coin); - let hash; + for (const input of this.inputs) { + const coin = view ? view.getOutputFor(input) : null; + const addr = input.getAddress(coin); if (!addr) continue; - hash = addr.getHash('hex'); + const hash = addr.getHash('hex'); if (!table[hash]) { table[hash] = true; @@ -1044,18 +1031,17 @@ TX.prototype._getInputAddresses = function getInputAddresses(view) { * @returns {Array} [addrs, table] */ -TX.prototype._getOutputAddresses = function getOutputAddresses() { - let table = {}; - let addrs = []; +TX.prototype._getOutputAddresses = function _getOutputAddresses() { + const table = Object.create(null); + const addrs = []; - for (let output of this.outputs) { - let addr = output.getAddress(); - let hash; + for (const output of this.outputs) { + const addr = output.getAddress(); if (!addr) continue; - hash = addr.getHash('hex'); + const hash = addr.getHash('hex'); if (!table[hash]) { table[hash] = true; @@ -1073,12 +1059,12 @@ TX.prototype._getOutputAddresses = function getOutputAddresses() { * @returns {Array} [addrs, table] */ -TX.prototype._getAddresses = function getAddresses(view) { - let [addrs, table] = this._getInputAddresses(view); - let output = this.getOutputAddresses(); +TX.prototype._getAddresses = function _getAddresses(view) { + const [addrs, table] = this._getInputAddresses(view); + const output = this.getOutputAddresses(); - for (let addr of output) { - let hash = addr.getHash('hex'); + for (const addr of output) { + const hash = addr.getHash('hex'); if (!table[hash]) { table[hash] = true; @@ -1096,7 +1082,7 @@ TX.prototype._getAddresses = function getAddresses(view) { */ TX.prototype.getInputAddresses = function getInputAddresses(view) { - let [addrs] = this._getInputAddresses(view); + const [addrs] = this._getInputAddresses(view); return addrs; }; @@ -1106,7 +1092,7 @@ TX.prototype.getInputAddresses = function getInputAddresses(view) { */ TX.prototype.getOutputAddresses = function getOutputAddresses() { - let [addrs] = this._getOutputAddresses(); + const [addrs] = this._getOutputAddresses(); return addrs; }; @@ -1117,7 +1103,7 @@ TX.prototype.getOutputAddresses = function getOutputAddresses() { */ TX.prototype.getAddresses = function getAddresses(view) { - let [addrs] = this._getAddresses(view); + const [addrs] = this._getAddresses(view); return addrs; }; @@ -1128,17 +1114,15 @@ TX.prototype.getAddresses = function getAddresses(view) { */ TX.prototype.getInputHashes = function getInputHashes(view, enc) { - let hashes = []; - let addrs; - if (enc === 'hex') { - let [, table] = this._getInputAddresses(view); + const [, table] = this._getInputAddresses(view); return Object.keys(table); } - addrs = this.getInputAddresses(view); + const addrs = this.getInputAddresses(view); + const hashes = []; - for (let addr of addrs) + for (const addr of addrs) hashes.push(addr.getHash()); return hashes; @@ -1150,17 +1134,15 @@ TX.prototype.getInputHashes = function getInputHashes(view, enc) { */ TX.prototype.getOutputHashes = function getOutputHashes(enc) { - let hashes = []; - let addrs; - if (enc === 'hex') { - let [, table] = this._getOutputAddresses(); + const [, table] = this._getOutputAddresses(); return Object.keys(table); } - addrs = this.getOutputAddresses(); + const addrs = this.getOutputAddresses(); + const hashes = []; - for (let addr of addrs) + for (const addr of addrs) hashes.push(addr.getHash()); return hashes; @@ -1173,17 +1155,15 @@ TX.prototype.getOutputHashes = function getOutputHashes(enc) { */ TX.prototype.getHashes = function getHashes(view, enc) { - let hashes = []; - let addrs; - if (enc === 'hex') { - let [, table] = this._getAddresses(view); + const [, table] = this._getAddresses(view); return Object.keys(table); } - addrs = this.getAddresses(view); + const addrs = this.getAddresses(view); + const hashes = []; - for (let addr of addrs) + for (const addr of addrs) hashes.push(addr.getHash()); return hashes; @@ -1200,8 +1180,8 @@ TX.prototype.hasCoins = function hasCoins(view) { if (this.inputs.length === 0) return false; - for (let input of this.inputs) { - if (!view.hasEntry(input)) + for (const {prevout} of this.inputs) { + if (!view.hasEntry(prevout)) return false; } @@ -1216,7 +1196,7 @@ TX.prototype.hasCoins = function hasCoins(view) { * @param {Number} height - Height at which to test. This * is usually the chain height, or the chain height + 1 * when the transaction entered the mempool. - * @param {Number} ts - Time at which to test. This is + * @param {Number} time - Time at which to test. This is * usually the chain tip's parent's median time, or the * time at which the transaction entered the mempool. If * MEDIAN_TIME_PAST is enabled this will be the median @@ -1224,16 +1204,16 @@ TX.prototype.hasCoins = function hasCoins(view) { * @returns {Boolean} */ -TX.prototype.isFinal = function isFinal(height, ts) { - let THRESHOLD = consensus.LOCKTIME_THRESHOLD; +TX.prototype.isFinal = function isFinal(height, time) { + const THRESHOLD = consensus.LOCKTIME_THRESHOLD; if (this.locktime === 0) return true; - if (this.locktime < (this.locktime < THRESHOLD ? height : ts)) + if (this.locktime < (this.locktime < THRESHOLD ? height : time)) return true; - for (let input of this.inputs) { + for (const input of this.inputs) { if (input.sequence !== 0xffffffff) return false; } @@ -1245,23 +1225,22 @@ TX.prototype.isFinal = function isFinal(height, ts) { * Verify the absolute locktime of a transaction. * Called by OP_CHECKLOCKTIMEVERIFY. * @param {Number} index - Index of input being verified. - * @param {Number} locktime - Locktime to verify against. + * @param {Number} predicate - Locktime to verify against. * @returns {Boolean} */ -TX.prototype.verifyLocktime = function verifyLocktime(index, locktime) { - let THRESHOLD = consensus.LOCKTIME_THRESHOLD; - let input = this.inputs[index]; +TX.prototype.verifyLocktime = function verifyLocktime(index, predicate) { + const THRESHOLD = consensus.LOCKTIME_THRESHOLD; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); - assert(locktime >= 0, 'Locktime must be non-negative.'); + assert(predicate >= 0, 'Locktime must be non-negative.'); - if (!((this.locktime < THRESHOLD && locktime < THRESHOLD) - || (this.locktime >= THRESHOLD && locktime >= THRESHOLD))) { + // Locktimes must be of the same type (blocks or seconds). + if ((this.locktime < THRESHOLD) !== (predicate < THRESHOLD)) return false; - } - if (locktime > this.locktime) + if (predicate > this.locktime) return false; if (input.sequence === 0xffffffff) @@ -1274,39 +1253,38 @@ TX.prototype.verifyLocktime = function verifyLocktime(index, locktime) { * Verify the relative locktime of an input. * Called by OP_CHECKSEQUENCEVERIFY. * @param {Number} index - Index of input being verified. - * @param {Number} locktime - Sequence locktime to verify against. + * @param {Number} predicate - Relative locktime to verify against. * @returns {Boolean} */ -TX.prototype.verifySequence = function verifySequence(index, locktime) { - let DISABLE_FLAG = consensus.SEQUENCE_DISABLE_FLAG; - let TYPE_FLAG = consensus.SEQUENCE_TYPE_FLAG; - let SEQUENCE_MASK = consensus.SEQUENCE_MASK; - let input = this.inputs[index]; - let mask, sequence, predicate; +TX.prototype.verifySequence = function verifySequence(index, predicate) { + const DISABLE_FLAG = consensus.SEQUENCE_DISABLE_FLAG; + const TYPE_FLAG = consensus.SEQUENCE_TYPE_FLAG; + const MASK = consensus.SEQUENCE_MASK; + const input = this.inputs[index]; assert(input, 'Input does not exist.'); - assert(locktime >= 0, 'Locktime must be non-negative.'); + assert(predicate >= 0, 'Locktime must be non-negative.'); - if ((locktime & DISABLE_FLAG) !== 0) + // For future softfork capability. + if (predicate & DISABLE_FLAG) return true; + // Version must be >=2. if (this.version < 2) return false; - if ((input.sequence & DISABLE_FLAG) !== 0) + // Cannot use the disable flag without + // the predicate also having the disable + // flag (for future softfork capability). + if (input.sequence & DISABLE_FLAG) return false; - mask = TYPE_FLAG | SEQUENCE_MASK; - sequence = input.sequence & mask; - predicate = locktime & mask; - - if (!((sequence < TYPE_FLAG && predicate < TYPE_FLAG) - || (sequence >= TYPE_FLAG && predicate >= TYPE_FLAG))) { + // Locktimes must be of the same type (blocks or seconds). + if ((input.sequence & TYPE_FLAG) !== (predicate & TYPE_FLAG)) return false; - } - if (predicate > sequence) + if ((predicate & MASK) > (input.sequence & MASK)) return false; return true; @@ -1318,14 +1296,20 @@ TX.prototype.verifySequence = function verifySequence(index, locktime) { */ TX.prototype.getLegacySigops = function getLegacySigops() { + if (this._sigops !== -1) + return this._sigops; + let total = 0; - for (let input of this.inputs) + for (const input of this.inputs) total += input.script.getSigops(false); - for (let output of this.outputs) + for (const output of this.outputs) total += output.script.getSigops(false); + if (!this.mutable) + this._sigops = total; + return total; }; @@ -1336,13 +1320,13 @@ TX.prototype.getLegacySigops = function getLegacySigops() { */ TX.prototype.getScripthashSigops = function getScripthashSigops(view) { - let total = 0; - if (this.isCoinbase()) return 0; - for (let input of this.inputs) { - let coin = view.getOutput(input); + let total = 0; + + for (const input of this.inputs) { + const coin = view.getOutputFor(input); if (!coin) continue; @@ -1356,6 +1340,30 @@ TX.prototype.getScripthashSigops = function getScripthashSigops(view) { return total; }; +/** + * Calculate accurate sigop count, taking into account redeem scripts. + * @param {CoinView} view + * @returns {Number} sigop count + */ + +TX.prototype.getWitnessSigops = function getWitnessSigops(view) { + if (this.isCoinbase()) + return 0; + + let total = 0; + + for (const input of this.inputs) { + const coin = view.getOutputFor(input); + + if (!coin) + continue; + + total += coin.script.getWitnessSigops(input.script, input.witness); + } + + return total; +}; + /** * Calculate sigops cost, taking into account witness programs. * @param {CoinView} view @@ -1364,29 +1372,18 @@ TX.prototype.getScripthashSigops = function getScripthashSigops(view) { */ TX.prototype.getSigopsCost = function getSigopsCost(view, flags) { - let scale = consensus.WITNESS_SCALE_FACTOR; - let cost = this.getLegacySigops() * scale; - if (flags == null) flags = Script.flags.STANDARD_VERIFY_FLAGS; - if (this.isCoinbase()) - return cost; + const scale = consensus.WITNESS_SCALE_FACTOR; + + let cost = this.getLegacySigops() * scale; if (flags & Script.flags.VERIFY_P2SH) cost += this.getScripthashSigops(view) * scale; - if (!(flags & Script.flags.VERIFY_WITNESS)) - return cost; - - for (let input of this.inputs) { - let coin = view.getOutput(input); - - if (!coin) - continue; - - cost += coin.script.getWitnessSigops(input.script, input.witness); - } + if (flags & Script.flags.VERIFY_WITNESS) + cost += this.getWitnessSigops(view); return cost; }; @@ -1399,7 +1396,7 @@ TX.prototype.getSigopsCost = function getSigopsCost(view, flags) { */ TX.prototype.getSigops = function getSigops(view, flags) { - let scale = consensus.WITNESS_SCALE_FACTOR; + const scale = consensus.WITNESS_SCALE_FACTOR; return (this.getSigopsCost(view, flags) + scale - 1) / scale | 0; }; @@ -1411,7 +1408,7 @@ TX.prototype.getSigops = function getSigops(view, flags) { */ TX.prototype.isSane = function isSane() { - let [valid] = this.checkSanity(); + const [valid] = this.checkSanity(); return valid; }; @@ -1423,9 +1420,6 @@ TX.prototype.isSane = function isSane() { */ TX.prototype.checkSanity = function checkSanity() { - let prevout = {}; - let total = 0; - if (this.inputs.length === 0) return [false, 'bad-txns-vin-empty', 100]; @@ -1435,7 +1429,9 @@ TX.prototype.checkSanity = function checkSanity() { if (this.getBaseSize() > consensus.MAX_BLOCK_SIZE) return [false, 'bad-txns-oversize', 100]; - for (let output of this.outputs) { + let total = 0; + + for (const output of this.outputs) { if (output.value < 0) return [false, 'bad-txns-vout-negative', 100]; @@ -1448,19 +1444,23 @@ TX.prototype.checkSanity = function checkSanity() { return [false, 'bad-txns-txouttotal-toolarge', 100]; } - for (let input of this.inputs) { - let key = input.prevout.toKey(); - if (prevout[key]) + const prevout = new Set(); + + for (const input of this.inputs) { + const key = input.prevout.toKey(); + + if (prevout.has(key)) return [false, 'bad-txns-inputs-duplicate', 100]; - prevout[key] = true; + + prevout.add(key); } if (this.isCoinbase()) { - let size = this.inputs[0].script.getSize(); + const size = this.inputs[0].script.getSize(); if (size < 2 || size > 100) return [false, 'bad-cb-length', 100]; } else { - for (let input of this.inputs) { + for (const input of this.inputs) { if (input.prevout.isNull()) return [false, 'bad-txns-prevout-null', 10]; } @@ -1480,7 +1480,7 @@ TX.prototype.checkSanity = function checkSanity() { */ TX.prototype.isStandard = function isStandard() { - let [valid] = this.checkStandard(); + const [valid] = this.checkStandard(); return valid; }; @@ -1495,15 +1495,13 @@ TX.prototype.isStandard = function isStandard() { */ TX.prototype.checkStandard = function checkStandard() { - let nulldata = 0; - if (this.version < 1 || this.version > policy.MAX_TX_VERSION) return [false, 'version', 0]; if (this.getWeight() >= policy.MAX_TX_WEIGHT) return [false, 'tx-size', 0]; - for (let input of this.inputs) { + for (const input of this.inputs) { if (input.script.getSize() > 1650) return [false, 'scriptsig-size', 0]; @@ -1511,7 +1509,9 @@ TX.prototype.checkStandard = function checkStandard() { return [false, 'scriptsig-not-pushonly', 0]; } - for (let output of this.outputs) { + let nulldata = 0; + + for (const output of this.outputs) { if (!output.script.isStandard()) return [false, 'scriptpubkey', 0]; @@ -1546,8 +1546,8 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(view) { if (this.isCoinbase()) return true; - for (let input of this.inputs) { - let coin = view.getOutput(input); + for (const input of this.inputs) { + const coin = view.getOutputFor(input); if (!coin) return false; @@ -1556,7 +1556,7 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(view) { continue; if (coin.script.isScripthash()) { - let redeem = input.script.getRedeem(); + const redeem = input.script.getRedeem(); if (!redeem) return false; @@ -1585,10 +1585,9 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { if (this.isCoinbase()) return true; - for (let input of this.inputs) { - let witness = input.witness; - let coin = view.getOutput(input); - let prev; + for (const input of this.inputs) { + const witness = input.witness; + const coin = view.getOutputFor(input); if (!coin) continue; @@ -1596,7 +1595,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { if (witness.items.length === 0) continue; - prev = coin.script; + let prev = coin.script; if (prev.isScripthash()) { prev = input.script.getRedeem(); @@ -1621,25 +1620,23 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { } if (prev.isWitnessScripthash()) { - let redeem; - if (witness.items.length - 1 > policy.MAX_P2WSH_STACK) return false; for (let i = 0; i < witness.items.length - 1; i++) { - let item = witness.items[i]; + const item = witness.items[i]; if (item.length > policy.MAX_P2WSH_PUSH) return false; } - redeem = witness.items[witness.items.length - 1]; + const raw = witness.items[witness.items.length - 1]; - if (redeem.length > policy.MAX_P2WSH_SIZE) + if (raw.length > policy.MAX_P2WSH_SIZE) return false; - prev = new Script(redeem); + const redeem = Script.fromRaw(raw); - if (prev.isPubkey()) { + if (redeem.isPubkey()) { if (witness.items.length - 1 !== 1) return false; @@ -1649,8 +1646,8 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { continue; } - if (prev.isPubkeyhash()) { - if (input.witness.length - 1 !== 2) + if (redeem.isPubkeyhash()) { + if (input.witness.items.length - 1 !== 2) return false; if (witness.items[0].length > 73) @@ -1662,9 +1659,9 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { continue; } - if (prev.isMultisig()) { - let m = prev.getSmall(0); + const [m] = redeem.getMultisig(); + if (m !== -1) { if (witness.items.length - 1 !== m + 1) return false; @@ -1672,7 +1669,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { return false; for (let i = 1; i < witness.items.length - 1; i++) { - let item = witness.items[i]; + const item = witness.items[i]; if (item.length > 73) return false; } @@ -1684,7 +1681,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { if (witness.items.length > policy.MAX_P2WSH_STACK) return false; - for (let item of witness.items) { + for (const item of witness.items) { if (item.length > policy.MAX_P2WSH_PUSH) return false; } @@ -1707,7 +1704,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { */ TX.prototype.verifyInputs = function verifyInputs(view, height) { - let [fee] = this.checkInputs(view, height); + const [fee] = this.checkInputs(view, height); return fee !== -1; }; @@ -1725,27 +1722,23 @@ TX.prototype.verifyInputs = function verifyInputs(view, height) { */ TX.prototype.checkInputs = function checkInputs(view, height) { - let total = 0; - let fee, value; - assert(typeof height === 'number'); - for (let input of this.inputs) { - let coins = view.get(input.prevout.hash); - let coin; + let total = 0; + + for (const {prevout} of this.inputs) { + const entry = view.getEntry(prevout); - if (!coins) + if (!entry) return [-1, 'bad-txns-inputs-missingorspent', 0]; - if (coins.coinbase) { - if (height - coins.height < consensus.COINBASE_MATURITY) + if (entry.coinbase) { + if (height - entry.height < consensus.COINBASE_MATURITY) return [-1, 'bad-txns-premature-spend-of-coinbase', 0]; } - coin = coins.getOutput(input.prevout.index); - - if (!coin) - return [-1, 'bad-txns-inputs-missingorspent', 0]; + const coin = view.getOutput(prevout); + assert(coin); if (coin.value < 0 || coin.value > consensus.MAX_MONEY) return [-1, 'bad-txns-inputvalues-outofrange', 100]; @@ -1757,12 +1750,12 @@ TX.prototype.checkInputs = function checkInputs(view, height) { } // Overflows already checked in `isSane()`. - value = this.getOutputValue(); + const value = this.getOutputValue(); if (total < value) return [-1, 'bad-txns-in-belowout', 100]; - fee = total - value; + const fee = total - value; if (fee < 0) return [-1, 'bad-txns-fee-negative', 100]; @@ -1782,13 +1775,11 @@ TX.prototype.checkInputs = function checkInputs(view, height) { */ TX.prototype.getModifiedSize = function getModifiedSize(size) { - let offset; - if (size == null) size = this.getVirtualSize(); - for (let input of this.inputs) { - offset = 41 + Math.min(110, input.script.getSize()); + for (const input of this.inputs) { + const offset = 41 + Math.min(110, input.script.getSize()); if (size > offset) size -= offset; } @@ -1806,30 +1797,29 @@ TX.prototype.getModifiedSize = function getModifiedSize(size) { */ TX.prototype.getPriority = function getPriority(view, height, size) { - let sum = 0; - assert(typeof height === 'number', 'Must pass in height.'); if (this.isCoinbase()) - return sum; + return 0; if (size == null) size = this.getVirtualSize(); - for (let input of this.inputs) { - let coin = view.getOutput(input); - let coinHeight; + let sum = 0; + + for (const {prevout} of this.inputs) { + const coin = view.getOutput(prevout); if (!coin) continue; - coinHeight = view.getHeight(input); + const coinHeight = view.getHeight(prevout); if (coinHeight === -1) continue; if (coinHeight <= height) { - let age = height - coinHeight; + const age = height - coinHeight; sum += coin.value * age; } } @@ -1844,21 +1834,20 @@ TX.prototype.getPriority = function getPriority(view, height, size) { */ TX.prototype.getChainValue = function getChainValue(view) { - let value = 0; - if (this.isCoinbase()) - return value; + return 0; - for (let input of this.inputs) { - let coin = view.getOutput(input); - let coinHeight; + let value = 0; + + for (const {prevout} of this.inputs) { + const coin = view.getOutput(prevout); if (!coin) continue; - coinHeight = view.getHeight(input); + const height = view.getHeight(prevout); - if (coinHeight === -1) + if (height === -1) continue; value += coin.value; @@ -1881,7 +1870,7 @@ TX.prototype.getChainValue = function getChainValue(view) { */ TX.prototype.isFree = function isFree(view, height, size) { - let priority = this.getPriority(view, height, size); + const priority = this.getPriority(view, height, size); return priority > policy.FREE_THRESHOLD; }; @@ -1927,7 +1916,7 @@ TX.prototype.getRoundFee = function getRoundFee(size, rate) { */ TX.prototype.getRate = function getRate(view, size) { - let fee = this.getFee(view); + const fee = this.getFee(view); if (fee < 0) return 0; @@ -1944,12 +1933,12 @@ TX.prototype.getRate = function getRate(view, size) { */ TX.prototype.getPrevout = function getPrevout() { - let prevout = {}; - if (this.isCoinbase()) return []; - for (let input of this.inputs) + const prevout = Object.create(null); + + for (const input of this.inputs) prevout[input.prevout.hash] = true; return Object.keys(prevout); @@ -1976,15 +1965,15 @@ TX.prototype.isWatched = function isWatched(filter) { // 2. Test data elements in output scripts // (may need to update filter on match) for (let i = 0; i < this.outputs.length; i++) { - let output = this.outputs[i]; + const output = this.outputs[i]; // Test the output script if (output.script.test(filter)) { if (filter.update === Bloom.flags.ALL) { - let prevout = Outpoint.fromTX(this, i); + const prevout = Outpoint.fromTX(this, i); filter.add(prevout.toRaw()); } else if (filter.update === Bloom.flags.PUBKEY_ONLY) { if (output.script.isPubkey() || output.script.isMultisig()) { - let prevout = Outpoint.fromTX(this, i); + const prevout = Outpoint.fromTX(this, i); filter.add(prevout.toRaw()); } } @@ -1997,8 +1986,8 @@ TX.prototype.isWatched = function isWatched(filter) { // 3. Test prev_out structure // 4. Test data elements in input scripts - for (let input of this.inputs) { - let prevout = input.prevout; + for (const input of this.inputs) { + const prevout = input.prevout; // Test the COutPoint structure if (filter.test(prevout.toRaw())) @@ -2082,7 +2071,7 @@ TX.prototype.format = function format(view, entry, index) { let fee = 0; let height = -1; let block = null; - let ts = 0; + let time = 0; let date = null; if (view) { @@ -2090,15 +2079,15 @@ TX.prototype.format = function format(view, entry, index) { rate = this.getRate(view); // Rate can exceed 53 bits in testing. - if (!util.isSafeInteger(rate)) + if (!Number.isSafeInteger(rate)) rate = 0; } if (entry) { height = entry.height; block = util.revHex(entry.hash); - ts = entry.ts; - date = util.date(ts); + time = entry.time; + date = util.date(time); } if (index == null) @@ -2115,13 +2104,12 @@ TX.prototype.format = function format(view, entry, index) { minFee: Amount.btc(this.getMinFee()), height: height, block: block, - ts: ts, + time: time, date: date, index: index, version: this.version, - flag: this.flag, inputs: this.inputs.map((input) => { - let coin = view ? view.getOutput(input) : null; + const coin = view ? view.getOutputFor(input) : null; return input.format(coin); }), outputs: this.outputs, @@ -2152,22 +2140,22 @@ TX.prototype.toJSON = function toJSON() { */ TX.prototype.getJSON = function getJSON(network, view, entry, index) { - let rate, fee, height, block, ts, date; + let rate, fee, height, block, time, date; if (view) { fee = this.getFee(view); rate = this.getRate(view); // Rate can exceed 53 bits in testing. - if (!util.isSafeInteger(rate)) + if (!Number.isSafeInteger(rate)) rate = 0; } if (entry) { height = entry.height; block = util.revHex(entry.hash); - ts = entry.ts; - date = util.date(ts); + time = entry.time; + date = util.date(time); } network = Network.get(network); @@ -2177,22 +2165,22 @@ TX.prototype.getJSON = function getJSON(network, view, entry, index) { witnessHash: this.wtxid(), fee: fee, rate: rate, - ps: util.now(), + mtime: util.now(), height: height, block: block, - ts: ts, + time: time, date: date, index: index, version: this.version, - flag: this.flag, inputs: this.inputs.map((input) => { - let coin = view ? view.getCoin(input) : null; + const coin = view ? view.getCoinFor(input) : null; return input.getJSON(network, coin); }), outputs: this.outputs.map((output) => { return output.getJSON(network); }), - locktime: this.locktime + locktime: this.locktime, + hex: this.toRaw().toString('hex') }; }; @@ -2204,19 +2192,17 @@ TX.prototype.getJSON = function getJSON(network, view, entry, index) { TX.prototype.fromJSON = function fromJSON(json) { assert(json, 'TX data is required.'); - assert(util.isUInt32(json.version), 'Version must be a uint32.'); - assert(util.isUInt8(json.flag), 'Flag must be a uint8.'); + assert(util.isU32(json.version), 'Version must be a uint32.'); assert(Array.isArray(json.inputs), 'Inputs must be an array.'); assert(Array.isArray(json.outputs), 'Outputs must be an array.'); - assert(util.isUInt32(json.locktime), 'Locktime must be a uint32.'); + assert(util.isU32(json.locktime), 'Locktime must be a uint32.'); this.version = json.version; - this.flag = json.flag; - for (let input of json.inputs) + for (const input of json.inputs) this.inputs.push(Input.fromJSON(input)); - for (let output of json.outputs) + for (const output of json.outputs) this.outputs.push(Output.fromJSON(output)); this.locktime = json.locktime; @@ -2275,23 +2261,21 @@ TX.prototype.fromRaw = function fromRaw(data) { */ TX.prototype.fromReader = function fromReader(br) { - let count; - - if (TX.isWitness(br)) + if (hasWitnessBytes(br)) return this.fromWitnessReader(br); br.start(); this.version = br.readU32(); - count = br.readVarint(); + const inCount = br.readVarint(); - for (let i = 0; i < count; i++) + for (let i = 0; i < inCount; i++) this.inputs.push(Input.fromReader(br)); - count = br.readVarint(); + const outCount = br.readVarint(); - for (let i = 0; i < count; i++) + for (let i = 0; i < outCount; i++) this.outputs.push(Output.fromReader(br)); this.locktime = br.readU32(); @@ -2315,39 +2299,35 @@ TX.prototype.fromReader = function fromReader(br) { */ TX.prototype.fromWitnessReader = function fromWitnessReader(br) { - let flag = 0; - let witness = 0; - let hasWitness = false; - let count; - br.start(); this.version = br.readU32(); assert(br.readU8() === 0, 'Non-zero marker.'); - flag = br.readU8(); + let flags = br.readU8(); - assert(flag !== 0, 'Flag byte is zero.'); + assert(flags !== 0, 'Flags byte is zero.'); - this.flag = flag; + const inCount = br.readVarint(); - count = br.readVarint(); - - for (let i = 0; i < count; i++) + for (let i = 0; i < inCount; i++) this.inputs.push(Input.fromReader(br)); - count = br.readVarint(); + const outCount = br.readVarint(); - for (let i = 0; i < count; i++) + for (let i = 0; i < outCount; i++) this.outputs.push(Output.fromReader(br)); - if (flag & 1) { - flag ^= 1; + let witness = 0; + let hasWitness = false; + + if (flags & 1) { + flags ^= 1; witness = br.offset; - for (let input of this.inputs) { + for (const input of this.inputs) { input.witness.fromReader(br); if (input.witness.items.length > 0) hasWitness = true; @@ -2356,7 +2336,7 @@ TX.prototype.fromWitnessReader = function fromWitnessReader(br) { witness = (br.offset - witness) + 2; } - if (flag !== 0) + if (flags !== 0) throw new Error('Unknown witness flag.'); // We'll never be able to reserialize @@ -2385,11 +2365,11 @@ TX.prototype.fromWitnessReader = function fromWitnessReader(br) { */ TX.prototype.frameNormal = function frameNormal() { - let sizes = this.getNormalSizes(); - let bw = new StaticWriter(sizes.total); + const raw = this.getNormalSizes(); + const bw = new StaticWriter(raw.size); this.writeNormal(bw); - sizes.data = bw.render(); - return sizes; + raw.data = bw.render(); + return raw; }; /** @@ -2400,11 +2380,11 @@ TX.prototype.frameNormal = function frameNormal() { */ TX.prototype.frameWitness = function frameWitness() { - let sizes = this.getWitnessSizes(); - let bw = new StaticWriter(sizes.total); + const raw = this.getWitnessSizes(); + const bw = new StaticWriter(raw.size); this.writeWitness(bw); - sizes.data = bw.render(); - return sizes; + raw.data = bw.render(); + return raw; }; /** @@ -2422,12 +2402,12 @@ TX.prototype.writeNormal = function writeNormal(bw) { bw.writeVarint(this.inputs.length); - for (let input of this.inputs) + for (const input of this.inputs) input.toWriter(bw); bw.writeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) output.toWriter(bw); bw.writeU32(this.locktime); @@ -2444,31 +2424,29 @@ TX.prototype.writeNormal = function writeNormal(bw) { */ TX.prototype.writeWitness = function writeWitness(bw) { - let witness; - if (this.inputs.length === 0 && this.outputs.length !== 0) throw new Error('Cannot serialize zero-input tx.'); bw.writeU32(this.version); bw.writeU8(0); - bw.writeU8(this.flag); + bw.writeU8(1); bw.writeVarint(this.inputs.length); - for (let input of this.inputs) + for (const input of this.inputs) input.toWriter(bw); bw.writeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) output.toWriter(bw); - witness = bw.written; + const start = bw.offset; - for (let input of this.inputs) + for (const input of this.inputs) input.witness.toWriter(bw); - witness = bw.written - witness; + const witness = bw.offset - start; bw.writeU32(this.locktime); @@ -2491,12 +2469,12 @@ TX.prototype.getNormalSizes = function getNormalSizes() { base += encoding.sizeVarint(this.inputs.length); - for (let input of this.inputs) + for (const input of this.inputs) base += input.getSize(); base += encoding.sizeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) base += output.getSize(); base += 4; @@ -2519,14 +2497,14 @@ TX.prototype.getWitnessSizes = function getWitnessSizes() { base += encoding.sizeVarint(this.inputs.length); - for (let input of this.inputs) { + for (const input of this.inputs) { base += input.getSize(); witness += input.witness.getVarSize(); } base += encoding.sizeVarint(this.outputs.length); - for (let output of this.outputs) + for (const output of this.outputs) base += output.getSize(); base += 4; @@ -2534,20 +2512,6 @@ TX.prototype.getWitnessSizes = function getWitnessSizes() { return new RawTX(base + witness, witness); }; -/** - * Test whether data is a witness transaction. - * @param {Buffer|BufferReader} data - * @returns {Boolean} - */ - -TX.isWitness = function isWitness(br) { - if (br.left() < 6) - return false; - - return br.data[br.offset + 4] === 0 - && br.data[br.offset + 5] !== 0; -}; - /** * Test whether an object is a TX. * @param {Object} obj @@ -2555,19 +2519,24 @@ TX.isWitness = function isWitness(br) { */ TX.isTX = function isTX(obj) { - return obj - && Array.isArray(obj.inputs) - && typeof obj.locktime === 'number' - && typeof obj.witnessHash === 'function'; + return obj instanceof TX; }; /* * Helpers */ -function RawTX(total, witness) { +function hasWitnessBytes(br) { + if (br.left() < 6) + return false; + + return br.data[br.offset + 4] === 0 + && br.data[br.offset + 5] !== 0; +} + +function RawTX(size, witness) { this.data = null; - this.total = total; + this.size = size; this.witness = witness; } diff --git a/lib/primitives/txmeta.js b/lib/primitives/txmeta.js index 0e39ebe97..aed439bbf 100644 --- a/lib/primitives/txmeta.js +++ b/lib/primitives/txmeta.js @@ -24,11 +24,11 @@ function TXMeta(options) { return new TXMeta(options); this.tx = new TX(); - this.ps = util.now(); + this.mtime = util.now(); this.height = -1; this.block = null; - this.ts = 0; - this.index = 0; + this.time = 0; + this.index = -1; if (options) this.fromOptions(options); @@ -46,13 +46,13 @@ TXMeta.prototype.fromOptions = function fromOptions(options) { this.tx = options.tx; } - if (options.ps != null) { - assert(util.isNumber(options.ps)); - this.ps = options.ps; + if (options.mtime != null) { + assert(util.isU32(options.mtime)); + this.mtime = options.mtime; } if (options.height != null) { - assert(util.isNumber(options.height)); + assert(util.isInt(options.height)); this.height = options.height; } @@ -61,13 +61,13 @@ TXMeta.prototype.fromOptions = function fromOptions(options) { this.block = options.block; } - if (options.ts != null) { - assert(util.isNumber(options.ts)); - this.ts = options.ts; + if (options.time != null) { + assert(util.isU32(options.time)); + this.time = options.time; } if (options.index != null) { - assert(util.isNumber(options.index)); + assert(util.isInt(options.index)); this.index = options.index; } @@ -95,7 +95,7 @@ TXMeta.prototype.fromTX = function fromTX(tx, entry, index) { if (entry) { this.height = entry.height; this.block = entry.hash; - this.ts = entry.ts; + this.time = entry.time; this.index = index; } return this; @@ -126,11 +126,11 @@ TXMeta.prototype.inspect = function inspect() { */ TXMeta.prototype.format = function format(view) { - let data = this.tx.format(view, null, this.index); - data.ps = this.ps; + const data = this.tx.format(view, null, this.index); + data.mtime = this.mtime; data.height = this.height; data.block = this.block ? util.revHex(this.block) : null; - data.ts = this.ts; + data.time = this.time; return data; }; @@ -152,11 +152,11 @@ TXMeta.prototype.toJSON = function toJSON() { */ TXMeta.prototype.getJSON = function getJSON(network, view) { - let json = this.tx.getJSON(network, view, null, this.index); - json.ps = this.ps; + const json = this.tx.getJSON(network, view, null, this.index); + json.mtime = this.mtime; json.height = this.height; json.block = this.block ? util.revHex(this.block) : null; - json.ts = this.ts; + json.time = this.time; return json; }; @@ -169,13 +169,13 @@ TXMeta.prototype.getJSON = function getJSON(network, view) { TXMeta.prototype.fromJSON = function fromJSON(json) { this.tx.fromJSON(json); - assert(util.isNumber(json.ps)); - assert(util.isNumber(json.height)); + assert(util.isU32(json.mtime)); + assert(util.isInt(json.height)); assert(!json.block || typeof json.block === 'string'); - assert(util.isNumber(json.ts)); - assert(util.isNumber(json.index)); + assert(util.isU32(json.time)); + assert(util.isInt(json.index)); - this.ps = json.ps; + this.mtime = json.mtime; this.height = json.height; this.block = util.revHex(json.block); this.index = json.index; @@ -226,18 +226,18 @@ TXMeta.prototype.getSize = function getSize() { */ TXMeta.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); this.tx.toWriter(bw); - bw.writeU32(this.ps); + bw.writeU32(this.mtime); if (this.block) { bw.writeU8(1); bw.writeHash(this.block); bw.writeU32(this.height); - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU32(this.index); } else { bw.writeU8(0); @@ -253,16 +253,16 @@ TXMeta.prototype.toRaw = function toRaw() { */ TXMeta.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.tx.fromReader(br); - this.ps = br.readU32(); + this.mtime = br.readU32(); if (br.readU8() === 1) { this.block = br.readHash('hex'); this.height = br.readU32(); - this.ts = br.readU32(); + this.time = br.readU32(); this.index = br.readU32(); if (this.index === 0x7fffffff) this.index = -1; @@ -295,7 +295,7 @@ TXMeta.isTXMeta = function isTXMeta(obj) { return obj && Array.isArray(obj.inputs) && typeof obj.locktime === 'number' - && typeof obj.ps === 'number'; + && typeof obj.mtime === 'number'; }; /* diff --git a/lib/protocol/consensus.js b/lib/protocol/consensus.js index ea671eeb4..1cf8bc346 100644 --- a/lib/protocol/consensus.js +++ b/lib/protocol/consensus.js @@ -226,8 +226,8 @@ exports.BIP16_TIME = 1333238400; */ exports.fromCompact = function fromCompact(compact) { - let exponent = compact >>> 24; - let negative = (compact >>> 23) & 1; + const exponent = compact >>> 24; + const negative = (compact >>> 23) & 1; let mantissa = compact & 0x7fffff; let num; @@ -293,7 +293,7 @@ exports.toCompact = function toCompact(num) { */ exports.verifyPOW = function verifyPOW(hash, bits) { - let target = exports.fromCompact(bits); + const target = exports.fromCompact(bits); if (target.isNeg() || target.cmpn(0) === 0) return false; @@ -313,7 +313,7 @@ exports.verifyPOW = function verifyPOW(hash, bits) { */ exports.getReward = function getReward(height, interval) { - let halvings = Math.floor(height / interval); + const halvings = Math.floor(height / interval); assert(height >= 0, 'Bad height for reward.'); @@ -341,8 +341,8 @@ exports.getReward = function getReward(height, interval) { */ exports.hasBit = function hasBit(version, bit) { - let bits = version & exports.VERSION_TOP_MASK; - let topBits = exports.VERSION_TOP_BITS; - let mask = 1 << bit; + const bits = version & exports.VERSION_TOP_MASK; + const topBits = exports.VERSION_TOP_BITS; + const mask = 1 << bit; return (bits >>> 0) === topBits && (version & mask) !== 0; }; diff --git a/lib/protocol/errors.js b/lib/protocol/errors.js index bafdc6ec8..765e43563 100644 --- a/lib/protocol/errors.js +++ b/lib/protocol/errors.js @@ -12,7 +12,6 @@ */ const assert = require('assert'); -const util = require('../utils/util'); /** * An error thrown during verification. Can be either @@ -57,7 +56,7 @@ function VerifyError(msg, code, reason, score, malleated) { Error.captureStackTrace(this, VerifyError); } -util.inherits(VerifyError, Error); +Object.setPrototypeOf(VerifyError.prototype, Error.prototype); /* * Expose diff --git a/lib/protocol/network.js b/lib/protocol/network.js index a0abc092d..a01030c43 100644 --- a/lib/protocol/network.js +++ b/lib/protocol/network.js @@ -92,20 +92,17 @@ Network.bitcoincash = null; Network.prototype._init = function _init() { let bits = 0; - let keys; - for (let deployment of this.deploys) + for (const deployment of this.deploys) bits |= 1 << deployment.bit; bits |= consensus.VERSION_TOP_MASK; this.unknownBits = ~bits; - keys = Object.keys(this.checkpointMap); - - for (let key of keys) { - let hash = this.checkpointMap[key]; - let height = +key; + for (const key of Object.keys(this.checkpointMap)) { + const hash = this.checkpointMap[key]; + const height = Number(key); this.checkpoints.push({ hash: hash, height: height }); } @@ -120,9 +117,11 @@ Network.prototype._init = function _init() { */ Network.prototype.byBit = function byBit(bit) { - let index = util.binarySearch(this.deploys, bit, cmpBit); + const index = util.binarySearch(this.deploys, bit, cmpBit); + if (index === -1) return null; + return this.deploys[index]; }; @@ -151,8 +150,6 @@ Network.prototype.ms = function ms() { */ Network.create = function create(options) { - let network; - if (typeof options === 'string') options = networks[options]; @@ -161,7 +158,7 @@ Network.create = function create(options) { if (Network[options.type]) return Network[options.type]; - network = new Network(options); + const network = new Network(options); Network[network.type] = network; @@ -204,7 +201,7 @@ Network.get = function get(type) { if (typeof type === 'string') return Network.create(type); - assert(false, 'Unknown network.'); + throw new Error('Unknown network.'); }; /** @@ -250,7 +247,7 @@ Network.by = function by(value, compare, network, name) { throw new Error(`Network mismatch for ${name}.`); } - for (let type of networks.types) { + for (const type of networks.types) { network = networks[type]; if (compare(network, value)) return Network.get(type); @@ -420,7 +417,7 @@ function cmpPriv58(network, prefix) { } function cmpAddress(network, prefix) { - let prefixes = network.addressPrefix; + const prefixes = network.addressPrefix; switch (prefix) { case prefixes.pubkeyhash: diff --git a/lib/protocol/networks.js b/lib/protocol/networks.js index 8687a2925..36ad890a6 100644 --- a/lib/protocol/networks.js +++ b/lib/protocol/networks.js @@ -14,7 +14,6 @@ const BN = require('../crypto/bn'); const network = exports; -let main, testnet, regtest, segnet4, simnet, bitcoincash; /** * Network type list. @@ -32,7 +31,7 @@ network.types = ['main', 'testnet', 'regtest', 'segnet4', 'simnet', 'bitcoincash * @type {Object} */ -main = network.main = {}; +const main = {}; /** * Symbolic network type. @@ -101,7 +100,8 @@ main.checkpointMap = { 420000: 'a1ff746b2d42b834cb7d6b8981b09c265c2cabc016e8cc020000000000000000', 440000: '9bf296b8de5f834f7635d5e258a434ad51b4dbbcf7c08c030000000000000000', 450000: '0ba2070c62cd9da1f8cef88a0648c661a411d33e728340010000000000000000', - 460000: '8c25fc7e414d3e868d6ce0ec473c30ad44e7e8bc1b75ef000000000000000000' + 460000: '8c25fc7e414d3e868d6ce0ec473c30ad44e7e8bc1b75ef000000000000000000', + 470000: '89756d1ed75901437300af10d5ab69070a282e729c536c000000000000000000' }; /** @@ -110,7 +110,7 @@ main.checkpointMap = { * @default */ -main.lastCheckpoint = 460000; +main.lastCheckpoint = 470000; /** * @const {Number} @@ -128,8 +128,9 @@ main.genesis = { version: 1, hash: '6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000', prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', - merkleRoot: '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', - ts: 1231006505, + merkleRoot: + '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + time: 1231006505, bits: 486604799, nonce: 2083236893, height: 0 @@ -182,7 +183,7 @@ main.pow = { */ chainwork: new BN( - '00000000000000000000000000000000000000000055c9a5edbc0c72c659b0b2', + '00000000000000000000000000000000000000000074093f7ecede98cadd3a32', 'hex' ), @@ -478,7 +479,7 @@ main.requestMempool = false; * https://en.bitcoin.it/wiki/Testnet */ -testnet = network.testnet = {}; +const testnet = {}; testnet.type = 'testnet'; @@ -495,7 +496,6 @@ testnet.port = 18333; testnet.checkpointMap = { 546: '70cb6af7ebbcb1315d3414029c556c55f3e2fc353c4c9063a76c932a00000000', - // Custom checkpoints 10000: '02a1b43f52591e53b660069173ac83b675798e12599dbb0442b7580000000000', 100000: '1e0a16bbadccde1d80c66597b1939e45f91b570d29f95fc158299e0000000000', 170000: '508125560d202b89757889bb0e49c712477be20440058f05db4f0e0000000000', @@ -512,7 +512,7 @@ testnet.checkpointMap = { 1050000: 'd8190cf0af7f08e179cab51d67db0b44b87951a78f7fdc31b4a01a0000000000' }; -testnet.lastCheckpoint = 900000; +testnet.lastCheckpoint = 1050000; testnet.halvingInterval = 210000; @@ -520,8 +520,9 @@ testnet.genesis = { version: 1, hash: '43497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000', prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', - merkleRoot: '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', - ts: 1296688602, + merkleRoot: + '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + time: 1296688602, bits: 486604799, nonce: 414098458, height: 0 @@ -545,7 +546,7 @@ testnet.pow = { ), bits: 486604799, chainwork: new BN( - '000000000000000000000000000000000000000000000023301a0019bca9e74c', + '0000000000000000000000000000000000000000000000286d17360c5492b2c4', 'hex' ), targetTimespan: 14 * 24 * 60 * 60, @@ -659,7 +660,7 @@ testnet.requestMempool = false; * Regtest */ -regtest = network.regtest = {}; +const regtest = {}; regtest.type = 'regtest'; @@ -680,8 +681,9 @@ regtest.genesis = { version: 1, hash: '06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f', prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', - merkleRoot: '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', - ts: 1296688602, + merkleRoot: + '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + time: 1296688602, bits: 545259519, nonce: 2, height: 0 @@ -732,7 +734,7 @@ regtest.bip30 = {}; regtest.activationThreshold = 108; // 75% for testchains -regtest.minerWindow = 144; // Faster than normal for regtest (144 instead of 2016) +regtest.minerWindow = 144; // Faster than normal for regtest regtest.deployments = { csv: { @@ -815,173 +817,11 @@ regtest.selfConnect = true; regtest.requestMempool = true; -/* - * segnet4 - */ - -segnet4 = network.segnet4 = {}; - -segnet4.type = 'segnet4'; - -segnet4.seeds = [ - '104.243.38.34', - '37.34.48.17' -]; - -segnet4.magic = 0xc4a1abdc; - -segnet4.port = 28901; - -segnet4.checkpointMap = {}; -segnet4.lastCheckpoint = 0; - -segnet4.halvingInterval = 210000; - -segnet4.genesis = { - version: 1, - hash: 'b291211d4bb2b7e1b7a4758225e69e50104091a637213d033295c010f55ffb18', - prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', - merkleRoot: '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', - ts: 1452831101, - bits: 503447551, - nonce: 0, - height: 0 -}; - -segnet4.genesisBlock = - '0100000000000000000000000000000000000000000000000000000000000000000000' - + '003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a7d71' - + '9856ffff011e0000000001010000000100000000000000000000000000000000000000' - + '00000000000000000000000000ffffffff4d04ffff001d0104455468652054696d6573' - + '2030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66' - + '207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01' - + '000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f' - + '61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f' - + 'ac00000000'; - -segnet4.pow = { - // 512x lower min difficulty than mainnet - limit: new BN( - '000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', - 'hex' - ), - bits: 503447551, - chainwork: new BN( - '0000000000000000000000000000000000000000000000000000000000800040', - 'hex' - ), - targetTimespan: 14 * 24 * 60 * 60, - targetSpacing: 10 * 60, - retargetInterval: 2016, - targetReset: true, - noRetargeting: false -}; - -segnet4.block = { - bip34height: 8, - bip34hash: '6c48386dc7c460defabb5640e28b6510a5f238cdbe6756c2976a7e0913000000', - bip65height: 8, - bip65hash: '6c48386dc7c460defabb5640e28b6510a5f238cdbe6756c2976a7e0913000000', - bip66height: 8, - bip66hash: '6c48386dc7c460defabb5640e28b6510a5f238cdbe6756c2976a7e0913000000', - pruneAfterHeight: 1000, - keepBlocks: 10000, - maxTipAge: 7 * 24 * 60 * 60, - slowHeight: 50000 -}; - -segnet4.bip30 = {}; - -segnet4.activationThreshold = 108; - -segnet4.minerWindow = 144; - -segnet4.deployments = { - csv: { - name: 'csv', - bit: 0, - startTime: 1456790400, // March 1st, 2016 - timeout: 1493596800, // May 1st, 2017 - threshold: -1, - window: -1, - required: false, - force: true - }, - segwit: { - name: 'segwit', - bit: 1, - startTime: 0, - timeout: 0xffffffff, - threshold: -1, - window: -1, - required: true, - force: false - }, - segsignal: { - name: 'segsignal', - bit: 4, - startTime: 0xffffffff, - timeout: 0xffffffff, - threshold: 269, - window: 336, - required: false, - force: false - }, - testdummy: { - name: 'testdummy', - bit: 28, - startTime: 1199145601, // January 1, 2008 - timeout: 1230767999, // December 31, 2008 - threshold: -1, - window: -1, - required: false, - force: true - } -}; - -segnet4.deploys = [ - segnet4.deployments.csv, - segnet4.deployments.segwit, - segnet4.deployments.segsignal, - segnet4.deployments.testdummy -]; - -segnet4.keyPrefix = { - privkey: 0x9e, - xpubkey: 0x053587cf, - xprivkey: 0x05358394, - xpubkey58: '2793', - xprivkey58: '2791', - coinType: 1 -}; - -segnet4.addressPrefix = { - pubkeyhash: 0x1e, - scripthash: 0x32, - witnesspubkeyhash: 0x04, - witnessscripthash: 0x29, - bech32: 'sg' -}; - -segnet4.requireStandard = false; - -segnet4.rpcPort = 28902; - -segnet4.minRelay = 1000; - -segnet4.feeRate = 20000; - -segnet4.maxFeeRate = 60000; - -segnet4.selfConnect = false; - -segnet4.requestMempool = true; - /* * Simnet (btcd) */ -simnet = network.simnet = {}; +const simnet = {}; simnet.type = 'simnet'; @@ -1003,8 +843,9 @@ simnet.genesis = { version: 1, hash: 'f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68', prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', - merkleRoot: '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', - ts: 1401292357, + merkleRoot: + '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + time: 1401292357, bits: 545259519, nonce: 2, height: 0 @@ -1143,12 +984,15 @@ simnet.requestMempool = false; * bitcoincash (Bitcoin Cash) */ +let bitcoincash = {}; + bitcoincash = network.bitcoincash = {}; bitcoincash.type = 'bitcoincash'; bitcoincash.seeds = [ - '127.0.0.1' + '195.154.168.129', + '50.63.202.19' ]; bitcoincash.magic = 0xd9b4bef9; @@ -1156,20 +1000,20 @@ bitcoincash.magic = 0xd9b4bef9; bitcoincash.port = 8333; bitcoincash.checkpointMap = { - 11111: '0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2', - 33333: '000000002dd5588a74784eaa7ab0507a18ad16a236e', - 74000: '0000000000573993a3c9e41ce34471c079dcf5f52a0', - 105000: '00000000000291ce28027faea320c8d2b054b2e0fe', - 134444: '00000000000005b12ffd4cd315cd34ffd4a594f430', - 168000: '000000000000099e61ea72015e79632f216fe6cb33', - 193000: '000000000000059f452a5f7340de6682a977387c17', - 210000: '000000000000048b95347e83192f69cf0366076336', - 216116: '00000000000001b4f4b433e81ee46494af945cf960', - 225430: '00000000000001c108384350f74090433e7fcf79a6', - 250000: '000000000000003887df1f29024b06fc2200b55f8a', - 279000: '0000000000000001ae8c72a0b0c301f67e3afca10e', - 295000: '00000000000000004d9b4ef50f0f9d686fd69db2e0', - 478559: '000000000000000000651ef99cb9fcbe0dadde1d42' + 11111: '0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d', + 33333: '0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6', + 74000: '0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20', + 105000: '0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97', + 134444: '0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe', + 168000: '0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763', + 193000: '0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317', + 210000: '0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e', + 216116: '0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e', + 225430: '0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932', + 250000: '0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214', + 279000: '0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40', + 295000: '0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983', + 478559: '0x000000000000000000651ef99cb9fcbe0dadde1d424bd9f15ff20136191a5eec' }; bitcoincash.lastCheckpoint = 478559; @@ -1291,3 +1135,13 @@ bitcoincash.maxFeeRate = 400000; bitcoincash.selfConnect = false; bitcoincash.requestMempool = false; + +/* + * Expose + */ + +network.main = main; +network.testnet = testnet; +network.regtest = regtest; +network.simnet = simnet; +network.bitcoincash = bitcoincash; diff --git a/lib/protocol/policy.js b/lib/protocol/policy.js index 8d9ffecc6..8a3652c3a 100644 --- a/lib/protocol/policy.js +++ b/lib/protocol/policy.js @@ -217,8 +217,6 @@ exports.BLOCK_PRIORITY_THRESHOLD = exports.FREE_THRESHOLD; */ exports.getMinFee = function getMinFee(size, rate) { - let fee; - if (rate == null) rate = exports.MIN_RELAY; @@ -228,7 +226,7 @@ exports.getMinFee = function getMinFee(size, rate) { if (size === 0) return 0; - fee = Math.floor(rate * size / 1000); + let fee = Math.floor(rate * size / 1000); if (fee === 0 && rate > 0) fee = rate; @@ -246,8 +244,6 @@ exports.getMinFee = function getMinFee(size, rate) { */ exports.getRoundFee = function getRoundFee(size, rate) { - let fee; - if (rate == null) rate = exports.MIN_RELAY; @@ -257,7 +253,7 @@ exports.getRoundFee = function getRoundFee(size, rate) { if (size === 0) return 0; - fee = rate * Math.ceil(size / 1000); + let fee = rate * Math.ceil(size / 1000); if (fee === 0 && rate > 0) fee = rate; diff --git a/lib/protocol/timedata.js b/lib/protocol/timedata.js index f09396201..310c090a3 100644 --- a/lib/protocol/timedata.js +++ b/lib/protocol/timedata.js @@ -40,7 +40,7 @@ function TimeData(limit) { this.checked = false; } -util.inherits(TimeData, EventEmitter); +Object.setPrototypeOf(TimeData.prototype, EventEmitter.prototype); /** * Add time data. @@ -49,14 +49,14 @@ util.inherits(TimeData, EventEmitter); */ TimeData.prototype.add = function add(id, time) { - let sample = time - util.now(); - if (this.samples.length >= this.limit) return; if (this.known.has(id)) return; + const sample = time - util.now(); + this.known.set(id, sample); util.binaryInsert(this.samples, sample, compare); @@ -69,17 +69,20 @@ TimeData.prototype.add = function add(id, time) { if (Math.abs(median) >= 70 * 60) { if (!this.checked) { let match = false; - for (let offset of this.samples) { + + for (const offset of this.samples) { if (offset !== 0 && Math.abs(offset) < 5 * 60) { match = true; break; } } + if (!match) { this.checked = true; this.emit('mismatch'); } } + median = 0; } diff --git a/lib/script/common.js b/lib/script/common.js index e728e6196..4313a329c 100644 --- a/lib/script/common.js +++ b/lib/script/common.js @@ -12,9 +12,9 @@ */ const assert = require('assert'); -const BN = require('../crypto/bn'); const util = require('../utils/util'); const secp256k1 = require('../crypto/secp256k1'); +const ScriptNum = require('./scriptnum'); /** * Script opcodes. @@ -23,7 +23,7 @@ const secp256k1 = require('../crypto/secp256k1'); */ exports.opcodes = { - OP_FALSE: 0x00, + // Push OP_0: 0x00, OP_PUSHDATA1: 0x4c, @@ -34,7 +34,6 @@ exports.opcodes = { OP_RESERVED: 0x50, - OP_TRUE: 0x51, OP_1: 0x51, OP_2: 0x52, OP_3: 0x53, @@ -52,6 +51,7 @@ exports.opcodes = { OP_15: 0x5f, OP_16: 0x60, + // Control OP_NOP: 0x61, OP_VER: 0x62, OP_IF: 0x63, @@ -63,6 +63,7 @@ exports.opcodes = { OP_VERIFY: 0x69, OP_RETURN: 0x6a, + // Stack OP_TOALTSTACK: 0x6b, OP_FROMALTSTACK: 0x6c, OP_2DROP: 0x6d, @@ -83,22 +84,24 @@ exports.opcodes = { OP_SWAP: 0x7c, OP_TUCK: 0x7d, + // Splice OP_CAT: 0x7e, OP_SUBSTR: 0x7f, OP_LEFT: 0x80, OP_RIGHT: 0x81, OP_SIZE: 0x82, + // Bit OP_INVERT: 0x83, OP_AND: 0x84, OP_OR: 0x85, OP_XOR: 0x86, OP_EQUAL: 0x87, OP_EQUALVERIFY: 0x88, - OP_RESERVED1: 0x89, OP_RESERVED2: 0x8a, + // Numeric OP_1ADD: 0x8b, OP_1SUB: 0x8c, OP_2MUL: 0x8d, @@ -127,6 +130,7 @@ exports.opcodes = { OP_MAX: 0xa4, OP_WITHIN: 0xa5, + // Crypto OP_RIPEMD160: 0xa6, OP_SHA1: 0xa7, OP_SHA256: 0xa8, @@ -138,11 +142,9 @@ exports.opcodes = { OP_CHECKMULTISIG: 0xae, OP_CHECKMULTISIGVERIFY: 0xaf, - OP_EVAL: 0xb0, + // Expansion OP_NOP1: 0xb0, - OP_NOP2: 0xb1, OP_CHECKLOCKTIMEVERIFY: 0xb1, - OP_NOP3: 0xb2, OP_CHECKSEQUENCEVERIFY: 0xb2, OP_NOP4: 0xb3, OP_NOP5: 0xb4, @@ -152,8 +154,7 @@ exports.opcodes = { OP_NOP9: 0xb8, OP_NOP10: 0xb9, - OP_PUBKEYHASH: 0xfd, - OP_PUBKEY: 0xfe, + // Custom OP_INVALIDOPCODE: 0xff }; @@ -162,7 +163,33 @@ exports.opcodes = { * @const {RevMap} */ -exports.opcodesByVal = util.revMap(exports.opcodes); +exports.opcodesByVal = util.reverse(exports.opcodes); + +/** + * Small ints (1 indexed, 1==0). + * @const {Buffer[]} + */ + +exports.small = [ + Buffer.from([0x81]), + Buffer.from([]), + Buffer.from([0x01]), + Buffer.from([0x02]), + Buffer.from([0x03]), + Buffer.from([0x04]), + Buffer.from([0x05]), + Buffer.from([0x06]), + Buffer.from([0x07]), + Buffer.from([0x08]), + Buffer.from([0x09]), + Buffer.from([0x0a]), + Buffer.from([0x0b]), + Buffer.from([0x0c]), + Buffer.from([0x0d]), + Buffer.from([0x0e]), + Buffer.from([0x0f]), + Buffer.from([0x10]) +]; /** * Script and locktime flags. See {@link VerifyFlags}. @@ -267,7 +294,7 @@ exports.hashType = { * @const {RevMap} */ -exports.hashTypeByVal = util.revMap(exports.hashType); +exports.hashTypeByVal = util.reverse(exports.hashType); /** * Output script types. @@ -292,28 +319,7 @@ exports.types = { * @const {RevMap} */ -exports.typesByVal = util.revMap(exports.types); - -/** - * False stack return value. - * @const {Buffer} - */ - -exports.STACK_FALSE = Buffer.from([]); - -/** - * True stack return value. - * @const {Buffer} - */ - -exports.STACK_TRUE = Buffer.from([0x01]); - -/** - * -1 stack return value. - * @const {Buffer} - */ - -exports.STACK_NEGATE = Buffer.from([0x81]); +exports.typesByVal = util.reverse(exports.types); /** * Test a signature to see whether it contains a valid sighash type. @@ -322,14 +328,12 @@ exports.STACK_NEGATE = Buffer.from([0x81]); */ exports.isHashType = function isHashType(sig) { - let type; - assert(Buffer.isBuffer(sig)); if (sig.length === 0) return false; - type = sig[sig.length - 1] & ~exports.hashType.ANYONECANPAY; + const type = sig[sig.length - 1] & ~exports.hashType.ANYONECANPAY; if (!(type >= exports.hashType.ALL && type <= exports.hashType.SINGLE)) return false; @@ -350,56 +354,6 @@ exports.isLowDER = function isLowDER(sig) { return secp256k1.isLowS(sig.slice(0, -1)); }; -/** - * Get a small integer from an opcode (OP_0-OP_16). - * @param {Number} index - * @returns {Number} - */ - -exports.getSmall = function getSmall(op) { - assert(typeof op === 'number'); - - if (op === exports.opcodes.OP_0) - return 0; - - if (op >= exports.opcodes.OP_1 && op <= exports.opcodes.OP_16) - return op - 0x50; - - return -1; -}; - -/** - * Test whether the data element is a ripemd160 hash. - * @param {Buffer?} hash - * @returns {Boolean} - */ - -exports.isHash = function isHash(hash) { - return Buffer.isBuffer(hash) && hash.length === 20; -}; - -/** - * Test whether the data element is a public key. Note that - * this does not verify the format of the key, only the length. - * @param {Buffer?} key - * @returns {Boolean} - */ - -exports.isKey = function isKey(key) { - return Buffer.isBuffer(key) && key.length >= 33 && key.length <= 65; -}; - -/** - * Test whether the data element is a signature. Note that - * this does not verify the format of the signature, only the length. - * @param {Buffer?} sig - * @returns {Boolean} - */ - -exports.isSignature = function isSignature(sig) { - return Buffer.isBuffer(sig) && sig.length >= 9 && sig.length <= 73; -}; - /** * Test whether the data element is a valid key. * @param {Buffer} key @@ -451,17 +405,17 @@ exports.isCompressedEncoding = function isCompressedEncoding(key) { */ exports.isSignatureEncoding = function isSignatureEncoding(sig) { - let lenR, lenS; - assert(Buffer.isBuffer(sig)); - // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] + // Format: + // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] // * total-length: 1-byte length descriptor of everything that follows, // excluding the sighash byte. // * R-length: 1-byte length descriptor of the R value that follows. // * R: arbitrary-length big-endian encoded R value. It must use the shortest // possible encoding for a positive integers (which means no null bytes at - // the start, except a single one when the next byte has its highest bit set). + // the start, except a single one when the next byte has its highest bit + // set). // * S-length: 1-byte length descriptor of the S value that follows. // * S: arbitrary-length big-endian encoded S value. The same rules apply. // * sighash: 1-byte value indicating what data is hashed (not part of the DER @@ -483,14 +437,14 @@ exports.isSignatureEncoding = function isSignatureEncoding(sig) { return false; // Extract the length of the R element. - lenR = sig[3]; + const lenR = sig[3]; // Make sure the length of the S element is still inside the signature. if (5 + lenR >= sig.length) return false; // Extract the length of the S element. - lenS = sig[5 + lenR]; + const lenS = sig[5 + lenR]; // Verify that the length of the signature matches the sum of the length // of the elements. @@ -535,309 +489,31 @@ exports.isSignatureEncoding = function isSignatureEncoding(sig) { }; /** - * Format script code into a human readable-string. - * @param {Array} code - * @returns {String} Human-readable string. - */ - -exports.formatStack = function formatStack(items) { - let out = []; - - for (let item of items) - out.push(item.toString('hex')); - - return out.join(' '); -}; - -/** - * Format script code into a human readable-string. - * @param {Array} code - * @returns {String} Human-readable string. - */ - -exports.formatCode = function formatCode(code) { - let out = []; - - for (let op of code) { - let data = op.data; - let value = op.value; - - if (data) { - let size = data.length.toString(16); - - while (size.length % 2 !== 0) - size = '0' + size; - - if (!exports.opcodesByVal[value]) { - value = value.toString(16); - if (value.length < 2) - value = '0' + value; - value = `0x${value} 0x${data.toString('hex')}`; - out.push(value); - continue; - } - - value = exports.opcodesByVal[value]; - value = `${value} 0x${size} 0x${data.toString('hex')}`; - out.push(value); - continue; - } - - assert(typeof value === 'number'); - - if (exports.opcodesByVal[value]) { - value = exports.opcodesByVal[value]; - out.push(value); - continue; - } - - if (value === -1) { - out.push('OP_INVALIDOPCODE'); - break; - } - - value = value.toString(16); - - if (value.length < 2) - value = '0' + value; - - value = `0x${value}`; - out.push(value); - } - - return out.join(' '); -}; - -/** - * Format script code into bitcoind asm format. - * @param {Array} code - * @param {Boolean?} decode - Attempt to decode hash types. - * @returns {String} Human-readable string. - */ - -exports.formatItem = function formatItem(data, decode) { - if (data.length <= 4) { - data = exports.num(data, exports.flags.VERIFY_NONE); - return data.toString(10); - } - - if (decode) { - let symbol = ''; - if (exports.isSignatureEncoding(data)) { - let type = data[data.length - 1]; - - symbol = exports.hashTypeByVal[type & 0x1f] || ''; - - if (symbol) { - if (type & exports.hashType.ANYONECANPAY) - symbol += '|ANYONECANPAY'; - symbol = `[${symbol}]`; - } - - data = data.slice(0, -1); - } - return data.toString('hex') + symbol; - } - - return data.toString('hex'); -}; - -/** - * Format script code into bitcoind asm format. - * @param {Array} code - * @param {Boolean?} decode - Attempt to decode hash types. - * @returns {String} Human-readable string. - */ - -exports.formatASM = function formatASM(code, decode) { - let out = []; - - if (code.length > 0 && code[0].value === exports.opcodes.OP_RETURN) - decode = false; - - for (let op of code) { - let data = op.data; - let value = op.value; - - if (value === -1) { - out.push('[error]'); - break; - } - - if (data) { - data = exports.formatItem(data, decode); - out.push(data); - continue; - } - - value = exports.opcodesByVal[value] || 'OP_UNKNOWN'; - - out.push(value); - } - - return out.join(' '); -}; - -/** - * Format script code into bitcoind asm format. - * @param {Array} code + * Format stack item into bitcoind asm format. + * @param {Buffer} item * @param {Boolean?} decode - Attempt to decode hash types. * @returns {String} Human-readable string. */ -exports.formatStackASM = function formatStackASM(items, decode) { - let out = []; - - for (let item of items) { - let data = exports.formatItem(item, decode); - out.push(data); +exports.toASM = function toASM(item, decode) { + if (item.length <= 4) { + const num = ScriptNum.decode(item); + return num.toString(10); } - return out.join(' '); -}; + if (decode && exports.isSignatureEncoding(item)) { + const type = item[item.length - 1]; -/** - * Create a CScriptNum. - * @param {Buffer} value - * @param {Boolean?} minimal - * @param {Number?} size - Max size in bytes. - * @returns {BN} - * @throws {ScriptError} - */ + let symbol = exports.hashTypeByVal[type & 0x1f] || ''; -exports.num = function num(value, minimal, size) { - let result; - - assert(Buffer.isBuffer(value)); - - if (size == null) - size = 4; - - if (value.length > size) - throw new exports.ScriptError('UNKNOWN_ERROR', 'Script number overflow.'); - - if (minimal && value.length > 0) { - // If the low bits on the last byte are unset, - // fail if the value's second to last byte does - // not have the high bit set. A number can't - // justify having the last byte's low bits unset - // unless they ran out of space for the sign bit - // in the second to last bit. We also fail on [0] - // to avoid negative zero (also avoids positive - // zero). - if (!(value[value.length - 1] & 0x7f)) { - if (value.length === 1 || !(value[value.length - 2] & 0x80)) { - throw new exports.ScriptError( - 'UNKNOWN_ERROR', - 'Non-minimally encoded Script number.'); - } + if (symbol) { + if (type & exports.hashType.ANYONECANPAY) + symbol += '|ANYONECANPAY'; + symbol = `[${symbol}]`; } - } - - if (value.length === 0) - return new BN(0); - - result = new BN(value, 'le'); - - // If the input vector's most significant byte is - // 0x80, remove it from the result's msb and return - // a negative. - // Equivalent to: - // -(result & ~(0x80 << (8 * (value.length - 1)))) - if (value[value.length - 1] & 0x80) - result.setn((value.length * 8) - 1, 0).ineg(); - - return result; -}; - -/** - * Create a script array. Will convert Numbers and big - * numbers to a little-endian buffer while taking into - * account negative zero, minimaldata, etc. - * @example - * assert.deepEqual(Script.array(0), Buffer.alloc(0)); - * assert.deepEqual(Script.array(0xffee), Buffer.from('eeff00', 'hex')); - * assert.deepEqual(Script.array(new BN(0xffee)), Buffer.from('eeff00', 'hex')); - * assert.deepEqual(Script.array(new BN(0x1e).ineg()), Buffer.from('9e', 'hex')); - * @param {Number|BN} value - * @returns {Buffer} - */ - -exports.array = function array(value) { - let neg, result; - if (util.isNumber(value)) - value = new BN(value); - - assert(BN.isBN(value)); - - if (value.cmpn(0) === 0) - return exports.STACK_FALSE; - - // If the most significant byte is >= 0x80 - // and the value is positive, push a new - // zero-byte to make the significant - // byte < 0x80 again. - - // If the most significant byte is >= 0x80 - // and the value is negative, push a new - // 0x80 byte that will be popped off when - // converting to an integral. - - // If the most significant byte is < 0x80 - // and the value is negative, add 0x80 to - // it, since it will be subtracted and - // interpreted as a negative when - // converting to an integral. - - neg = value.cmpn(0) < 0; - result = value.toArray('le'); - - if (result[result.length - 1] & 0x80) - result.push(neg ? 0x80 : 0); - else if (neg) - result[result.length - 1] |= 0x80; - - return Buffer.from(result); -}; - -/** - * An error thrown from the scripting system, - * potentially pertaining to Script execution. - * @alias module:script.ScriptError - * @constructor - * @extends Error - * @param {String} code - Error code. - * @param {Opcode} op - Opcode. - * @param {Number?} ip - Instruction pointer. - * @property {String} message - Error message. - * @property {String} code - Original code passed in. - * @property {Number} op - Opcode. - * @property {Number} ip - Instruction pointer. - */ - -exports.ScriptError = function ScriptError(code, op, ip) { - if (!(this instanceof ScriptError)) - return new ScriptError(code, op, ip); - - Error.call(this); - - this.type = 'ScriptError'; - this.code = code; - this.message = code; - this.op = -1; - this.ip = -1; - - if (typeof op === 'string') { - this.message = op; - } else if (op) { - this.message = `${code} (op=${op.toSymbol()}, ip=${ip})`; - this.op = op.value; - this.ip = ip; + return item.slice(0, -1).toString('hex') + symbol; } - if (Error.captureStackTrace) - Error.captureStackTrace(this, ScriptError); + return item.toString('hex'); }; - -util.inherits(exports.ScriptError, Error); diff --git a/lib/script/index.js b/lib/script/index.js index 4d83dc6e8..c3d9386b5 100644 --- a/lib/script/index.js +++ b/lib/script/index.js @@ -14,7 +14,8 @@ exports.common = require('./common'); exports.Opcode = require('./opcode'); exports.Program = require('./program'); exports.Script = require('./script'); -// exports.ScriptNum = require('./scriptnum'); +exports.ScriptError = require('./scripterror'); +exports.ScriptNum = require('./scriptnum'); exports.sigcache = require('./sigcache'); exports.Stack = require('./stack'); exports.Witness = require('./witness'); diff --git a/lib/script/opcode.js b/lib/script/opcode.js index 57b98e9b9..a46366e1b 100644 --- a/lib/script/opcode.js +++ b/lib/script/opcode.js @@ -8,16 +8,21 @@ 'use strict'; const assert = require('assert'); -const BN = require('../crypto/bn'); +const ScriptNum = require('./scriptnum'); const util = require('../utils/util'); const common = require('./common'); const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); const opcodes = common.opcodes; +const opCache = []; + +let PARSE_ERROR = null; + /** * A simple struct which contains * an opcode and pushdata buffer. + * Note: this should not be called directly. * @alias module:script.Opcode * @constructor * @param {Number} value - Opcode. @@ -43,24 +48,25 @@ Opcode.prototype.isMinimal = function isMinimal() { if (!this.data) return true; - if (this.data.length === 0) - return this.value === opcodes.OP_0; + if (this.data.length === 1) { + if (this.data[0] === 0x81) + return false; - if (this.data.length === 1 && this.data[0] >= 1 && this.data[0] <= 16) - return false; - - if (this.data.length === 1 && this.data[0] === 0x81) - return false; + if (this.data[0] >= 1 && this.data[0] <= 16) + return false; + } - if (this.data.length <= 75) + if (this.data.length <= 0x4b) return this.value === this.data.length; - if (this.data.length <= 255) + if (this.data.length <= 0xff) return this.value === opcodes.OP_PUSHDATA1; - if (this.data.length <= 65535) + if (this.data.length <= 0xffff) return this.value === opcodes.OP_PUSHDATA2; + assert(this.value === opcodes.OP_PUSHDATA4); + return true; }; @@ -101,57 +107,170 @@ Opcode.prototype.isBranch = function isBranch() { }; /** - * Encode the opcode to a buffer writer. - * @param {BufferWriter} bw + * Test opcode equality. + * @param {Opcode} op + * @returns {Boolean} */ -Opcode.prototype.toWriter = function toWriter(bw) { - if (this.value === -1) - throw new Error('Cannot reserialize a parse error.'); +Opcode.prototype.equals = function equals(op) { + assert(Opcode.isOpcode(op)); + + if (this.value !== op.value) + return false; if (!this.data) { - bw.writeU8(this.value); - return bw; + assert(!op.data); + return true; } - if (this.value <= 0x4b) { - assert(this.value === this.data.length); - bw.writeU8(this.value); - bw.writeBytes(this.data); - return bw; - } + assert(op.data); - switch (this.value) { - case opcodes.OP_PUSHDATA1: - bw.writeU8(this.value); - bw.writeU8(this.data.length); - bw.writeBytes(this.data); - break; - case opcodes.OP_PUSHDATA2: - bw.writeU8(this.value); - bw.writeU16(this.data.length); - bw.writeBytes(this.data); - break; - case opcodes.OP_PUSHDATA4: - bw.writeU8(this.value); - bw.writeU32(this.data.length); - bw.writeBytes(this.data); - break; - default: - throw new Error('Unknown pushdata opcode.'); - } + return this.data.equals(op.data); +}; - return bw; +/** + * Convert Opcode to opcode value. + * @returns {Number} + */ + +Opcode.prototype.toOp = function toOp() { + return this.value; }; /** - * Encode the opcode. - * @returns {Buffer} + * Covert opcode to data push. + * @returns {Buffer|null} */ -Opcode.prototype.toRaw = function toRaw() { - let size = this.getSize(); - return this.toWriter(new StaticWriter(size)).render(); +Opcode.prototype.toData = function toData() { + return this.data; +}; + +/** + * Covert opcode to data length. + * @returns {Number} + */ + +Opcode.prototype.toLength = function toLength() { + return this.data ? this.data.length : -1; +}; + +/** + * Covert and _cast_ opcode to data push. + * @returns {Buffer|null} + */ + +Opcode.prototype.toPush = function toPush() { + if (this.value === opcodes.OP_0) + return common.small[0 + 1]; + + if (this.value === opcodes.OP_1NEGATE) + return common.small[-1 + 1]; + + if (this.value >= opcodes.OP_1 && this.value <= opcodes.OP_16) + return common.small[this.value - 0x50 + 1]; + + return this.toData(); +}; + +/** + * Get string for opcode. + * @param {String?} enc + * @returns {Buffer|null} + */ + +Opcode.prototype.toString = function toString(enc) { + const data = this.toPush(); + + if (!data) + return null; + + return data.toString(enc || 'utf8'); +}; + +/** + * Convert opcode to small integer. + * @returns {Number} + */ + +Opcode.prototype.toSmall = function toSmall() { + if (this.value === opcodes.OP_0) + return 0; + + if (this.value >= opcodes.OP_1 && this.value <= opcodes.OP_16) + return this.value - 0x50; + + return -1; +}; + +/** + * Convert opcode to script number. + * @param {Boolean?} minimal + * @param {Number?} limit + * @returns {ScriptNum|null} + */ + +Opcode.prototype.toNum = function toNum(minimal, limit) { + if (this.value === opcodes.OP_0) + return ScriptNum.fromInt(0); + + if (this.value === opcodes.OP_1NEGATE) + return ScriptNum.fromInt(-1); + + if (this.value >= opcodes.OP_1 && this.value <= opcodes.OP_16) + return ScriptNum.fromInt(this.value - 0x50); + + if (!this.data) + return null; + + return ScriptNum.decode(this.data, minimal, limit); +}; + +/** + * Convert opcode to integer. + * @param {Boolean?} minimal + * @param {Number?} limit + * @returns {Number} + */ + +Opcode.prototype.toInt = function toInt(minimal, limit) { + const num = this.toNum(minimal, limit); + + if (!num) + return -1; + + return num.getInt(); +}; + +/** + * Convert opcode to boolean. + * @returns {Boolean} + */ + +Opcode.prototype.toBool = function toBool() { + const smi = this.toSmall(); + + if (smi === -1) + return false; + + return smi === 1; +}; + +/** + * Convert opcode to its symbolic representation. + * @returns {String} + */ + +Opcode.prototype.toSymbol = function toSymbol() { + if (this.value === -1) + return 'OP_INVALIDOPCODE'; + + const symbol = common.opcodesByVal[this.value]; + + if (!symbol) + return `0x${util.hex8(this.value)}`; + + return symbol; }; /** @@ -163,9 +282,6 @@ Opcode.prototype.getSize = function getSize() { if (!this.data) return 1; - if (this.value <= 0x4b) - return 1 + this.data.length; - switch (this.value) { case opcodes.OP_PUSHDATA1: return 2 + this.data.length; @@ -174,113 +290,120 @@ Opcode.prototype.getSize = function getSize() { case opcodes.OP_PUSHDATA4: return 5 + this.data.length; default: - throw new Error('Unknown pushdata opcode.'); + return 1 + this.data.length; } }; /** - * Inject properties from buffer reader. - * @param {BufferReader} br - * @private + * Encode the opcode to a buffer writer. + * @param {BufferWriter} bw */ -Opcode.prototype.fromReader = function fromReader(br) { - let op = br.readU8(); - let size; +Opcode.prototype.toWriter = function toWriter(bw) { + if (this.value === -1) + throw new Error('Cannot reserialize a parse error.'); - if (op >= 0x01 && op <= 0x4b) { - if (br.left() < op) { - this.value = -1; - br.seek(br.left()); - return this; - } - this.value = op; - this.data = br.readBytes(op); - return this; + if (!this.data) { + bw.writeU8(this.value); + return bw; } - switch (op) { + switch (this.value) { case opcodes.OP_PUSHDATA1: - if (br.left() < 1) { - this.value = -1; - break; - } - size = br.readU8(); - if (br.left() < size) { - this.value = -1; - br.seek(br.left()); - break; - } - this.value = op; - this.data = br.readBytes(size); + bw.writeU8(this.value); + bw.writeU8(this.data.length); + bw.writeBytes(this.data); break; case opcodes.OP_PUSHDATA2: - if (br.left() < 2) { - this.value = -1; - br.seek(br.left()); - break; - } - size = br.readU16(); - if (br.left() < size) { - this.value = -1; - br.seek(br.left()); - break; - } - this.value = op; - this.data = br.readBytes(size); + bw.writeU8(this.value); + bw.writeU16(this.data.length); + bw.writeBytes(this.data); break; case opcodes.OP_PUSHDATA4: - if (br.left() < 4) { - this.value = -1; - br.seek(br.left()); - break; - } - size = br.readU32(); - if (br.left() < size) { - this.value = -1; - br.seek(br.left()); - break; - } - this.value = op; - this.data = br.readBytes(size); + bw.writeU8(this.value); + bw.writeU32(this.data.length); + bw.writeBytes(this.data); break; default: - this.value = op; + assert(this.value === this.data.length); + bw.writeU8(this.value); + bw.writeBytes(this.data); break; } - return this; + return bw; }; /** - * Inject properties from serialized data. - * @private - * @param {Buffer} data - * @returns {Opcode} + * Encode the opcode. + * @returns {Buffer} */ -Opcode.prototype.fromRaw = function fromRaw(data) { - return this.fromReader(new BufferReader(data)); +Opcode.prototype.toRaw = function toRaw() { + const size = this.getSize(); + return this.toWriter(new StaticWriter(size)).render(); }; /** - * Instantiate opcode from buffer reader. - * @param {BufferReader} br - * @returns {Opcode} + * Convert the opcode to a bitcoind test string. + * @returns {String} Human-readable script code. */ -Opcode.fromReader = function fromReader(br) { - return new Opcode(0, null).fromReader(br); +Opcode.prototype.toFormat = function toFormat() { + if (this.value === -1) + return '0x01'; + + if (this.data) { + // Numbers + if (this.data.length <= 4) { + const num = this.toNum(); + if (this.equals(Opcode.fromNum(num))) + return num.toString(10); + } + + const symbol = common.opcodesByVal[this.value]; + const data = this.data.toString('hex'); + + // Direct push + if (!symbol) { + const size = util.hex8(this.value); + return `0x${size} 0x${data}`; + } + + // Pushdatas + let size = this.data.length.toString(16); + + while (size.length % 2 !== 0) + size = '0' + size; + + return `${symbol} 0x${size} 0x${data}`; + } + + // Opcodes + const symbol = common.opcodesByVal[this.value]; + if (symbol) + return symbol; + + // Unknown opcodes + const value = util.hex8(this.value); + + return `0x${value}`; }; /** - * Instantiate opcode from serialized data. - * @param {Buffer} data - * @returns {Opcode} + * Format the opcode as bitcoind asm. + * @param {Boolean?} decode - Attempt to decode hash types. + * @returns {String} Human-readable script. */ -Opcode.fromRaw = function fromRaw(data) { - return new Opcode(0, null).fromRaw(data); +Opcode.prototype.toASM = function toASM(decode) { + if (this.value === -1) + return '[error]'; + + if (this.data) + return common.toASM(this.data, decode); + + return common.opcodesByVal[this.value] || 'OP_UNKNOWN'; }; /** @@ -290,7 +413,13 @@ Opcode.fromRaw = function fromRaw(data) { */ Opcode.fromOp = function fromOp(op) { - return new Opcode(op, null); + assert(typeof op === 'number'); + + const cached = opCache[op]; + + assert(cached, 'Bad opcode.'); + + return cached; }; /** @@ -301,15 +430,14 @@ Opcode.fromOp = function fromOp(op) { */ Opcode.fromData = function fromData(data) { - if (data.length === 0) - return Opcode.fromOp(opcodes.OP_0); + assert(Buffer.isBuffer(data)); if (data.length === 1) { - if (data[0] >= 1 && data[0] <= 16) - return Opcode.fromOp(data[0] + 0x50); - if (data[0] === 0x81) return Opcode.fromOp(opcodes.OP_1NEGATE); + + if (data[0] >= 1 && data[0] <= 16) + return Opcode.fromOp(data[0] + 0x50); } return Opcode.fromPush(data); @@ -324,6 +452,11 @@ Opcode.fromData = function fromData(data) { */ Opcode.fromPush = function fromPush(data) { + assert(Buffer.isBuffer(data)); + + if (data.length === 0) + return Opcode.fromOp(opcodes.OP_0); + if (data.length <= 0x4b) return new Opcode(data.length, data); @@ -340,13 +473,16 @@ Opcode.fromPush = function fromPush(data) { }; /** - * Instantiate an opcode from a Number. - * @param {Number|BN} num + * Instantiate a pushdata opcode from a string. + * @param {String} str + * @param {String} [enc=utf8] * @returns {Opcode} */ -Opcode.fromNumber = function fromNumber(num) { - return Opcode.fromData(common.array(num)); +Opcode.fromString = function fromString(str, enc) { + assert(typeof str === 'string'); + const data = Buffer.from(str, enc || 'utf8'); + return Opcode.fromData(data); }; /** @@ -356,46 +492,51 @@ Opcode.fromNumber = function fromNumber(num) { */ Opcode.fromSmall = function fromSmall(num) { - assert(util.isNumber(num) && num >= 0 && num <= 16); + assert(util.isU8(num) && num >= 0 && num <= 16); return Opcode.fromOp(num === 0 ? 0 : num + 0x50); }; /** - * Instantiate a pushdata opcode from a string. - * @param {String} data + * Instantiate an opcode from a ScriptNum. + * @param {ScriptNumber} num * @returns {Opcode} */ -Opcode.fromString = function fromString(data, enc) { - if (typeof data === 'string') - data = Buffer.from(data, enc); - - return Opcode.fromData(data); +Opcode.fromNum = function fromNum(num) { + assert(ScriptNum.isScriptNum(num)); + return Opcode.fromData(num.encode()); }; /** - * Instantiate a pushdata opcode from anything. - * @param {String|Buffer|Number|BN|Opcode} data + * Instantiate an opcode from a Number. + * @param {Number} num * @returns {Opcode} */ -Opcode.from = function from(data) { - if (data instanceof Opcode) - return data; +Opcode.fromInt = function fromInt(num) { + assert(util.isInt(num)); - if (typeof data === 'number') - return Opcode.fromOp(data); + if (num === 0) + return Opcode.fromOp(opcodes.OP_0); - if (Buffer.isBuffer(data)) - return Opcode.fromData(data); + if (num === -1) + return Opcode.fromOp(opcodes.OP_1NEGATE); - if (typeof data === 'string') - return Opcode.fromString(data, 'utf8'); + if (num >= 1 && num <= 16) + return Opcode.fromOp(num + 0x50); - if (BN.isBN(data)) - return Opcode.fromNumber(data); + return Opcode.fromNum(ScriptNum.fromNumber(num)); +}; - assert(false, 'Bad data for opcode.'); +/** + * Instantiate an opcode from a Number. + * @param {Boolean} value + * @returns {Opcode} + */ + +Opcode.fromBool = function fromBool(value) { + assert(typeof value === 'boolean'); + return Opcode.fromSmall(value ? 1 : 0); }; /** @@ -407,8 +548,6 @@ Opcode.from = function from(data) { */ Opcode.fromSymbol = function fromSymbol(name) { - let op; - assert(typeof name === 'string'); assert(name.length > 0); @@ -418,30 +557,105 @@ Opcode.fromSymbol = function fromSymbol(name) { if (!util.startsWith(name, 'OP_')) name = `OP_${name}`; - op = common.opcodes[name]; - assert(op != null, 'Unknown opcode.'); + const op = common.opcodes[name]; + + if (op != null) + return Opcode.fromOp(op); - return Opcode.fromOp(op); + assert(util.startsWith(name, 'OP_0X'), 'Unknown opcode.'); + assert(name.length === 7, 'Unknown opcode.'); + + const value = parseInt(name.substring(5), 16); + + assert(util.isU8(value), 'Unknown opcode.'); + + return Opcode.fromOp(value); }; /** - * Convert opcode to its symbolic representation. - * @returns {String} + * Instantiate opcode from buffer reader. + * @param {BufferReader} br + * @returns {Opcode} */ -Opcode.prototype.toSymbol = function toSymbol() { - let op = this.value; - let symbol; +Opcode.fromReader = function fromReader(br) { + const value = br.readU8(); + const op = opCache[value]; - if (op === -1) - op = 0xff; + if (op) + return op; - symbol = common.opcodesByVal[op]; + switch (value) { + case opcodes.OP_PUSHDATA1: { + if (br.left() < 1) + return PARSE_ERROR; - if (symbol == null) - symbol = util.hex8(op); + const size = br.readU8(); - return symbol; + if (br.left() < size) { + br.seek(br.left()); + return PARSE_ERROR; + } + + const data = br.readBytes(size); + + return new Opcode(value, data); + } + case opcodes.OP_PUSHDATA2: { + if (br.left() < 2) { + br.seek(br.left()); + return PARSE_ERROR; + } + + const size = br.readU16(); + + if (br.left() < size) { + br.seek(br.left()); + return PARSE_ERROR; + } + + const data = br.readBytes(size); + + return new Opcode(value, data); + } + case opcodes.OP_PUSHDATA4: { + if (br.left() < 4) { + br.seek(br.left()); + return PARSE_ERROR; + } + + const size = br.readU32(); + + if (br.left() < size) { + br.seek(br.left()); + return PARSE_ERROR; + } + + const data = br.readBytes(size); + + return new Opcode(value, data); + } + default: { + if (br.left() < value) { + br.seek(br.left()); + return PARSE_ERROR; + } + + const data = br.readBytes(value); + + return new Opcode(value, data); + } + } +}; + +/** + * Instantiate opcode from serialized data. + * @param {Buffer} data + * @returns {Opcode} + */ + +Opcode.fromRaw = function fromRaw(data) { + return Opcode.fromReader(new BufferReader(data)); }; /** @@ -451,11 +665,24 @@ Opcode.prototype.toSymbol = function toSymbol() { */ Opcode.isOpcode = function isOpcode(obj) { - return obj - && typeof obj.value === 'number' - && (Buffer.isBuffer(obj.data) || obj.data === null); + return obj instanceof Opcode; }; +/* + * Fill Cache + */ + +PARSE_ERROR = Object.freeze(new Opcode(-1)); + +for (let value = 0x00; value <= 0xff; value++) { + if (value >= 0x01 && value <= 0x4e) { + opCache.push(null); + continue; + } + const op = new Opcode(value); + opCache.push(Object.freeze(op)); +} + /* * Expose */ diff --git a/lib/script/program.js b/lib/script/program.js index 8c7e63212..fedee361a 100644 --- a/lib/script/program.js +++ b/lib/script/program.js @@ -29,9 +29,9 @@ function Program(version, data) { if (!(this instanceof Program)) return new Program(version, data); - assert(util.isNumber(version)); - assert(Buffer.isBuffer(data)); + assert(util.isU8(version)); assert(version >= 0 && version <= 16); + assert(Buffer.isBuffer(data)); assert(data.length >= 2 && data.length <= 40); this.version = version; @@ -74,7 +74,7 @@ Program.prototype.getType = function getType() { */ Program.prototype.isUnknown = function isUnknown() { - let type = this.getType(); + const type = this.getType(); return type === scriptTypes.WITNESSMALFORMED || type === scriptTypes.NONSTANDARD; }; @@ -94,8 +94,8 @@ Program.prototype.isMalformed = function isMalformed() { */ Program.prototype.inspect = function inspect() { - let data = this.data.toString('hex'); - let type = common.typesByVal[this.getType()].toLowerCase(); + const data = this.data.toString('hex'); + const type = common.typesByVal[this.getType()].toLowerCase(); return ``; }; diff --git a/lib/script/script.js b/lib/script/script.js index 6cf5853ba..751ea81ea 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -8,7 +8,6 @@ 'use strict'; const assert = require('assert'); -const BN = require('../crypto/bn'); const consensus = require('../protocol/consensus'); const policy = require('../protocol/policy'); const util = require('../utils/util'); @@ -20,16 +19,15 @@ const StaticWriter = require('../utils/staticwriter'); const Program = require('./program'); const Opcode = require('./opcode'); const Stack = require('./stack'); +const ScriptError = require('./scripterror'); +const ScriptNum = require('./scriptnum'); const common = require('./common'); const encoding = require('../utils/encoding'); const secp256k1 = require('../crypto/secp256k1'); const Address = require('../primitives/address'); const opcodes = common.opcodes; const scriptTypes = common.types; -const ScriptError = common.ScriptError; -const STACK_TRUE = common.STACK_TRUE; -const STACK_FALSE = common.STACK_FALSE; -const STACK_NEGATE = common.STACK_NEGATE; +const EMPTY_BUFFER = Buffer.alloc(0); /** * Represents a input or output script. @@ -46,7 +44,7 @@ function Script(options) { if (!(this instanceof Script)) return new Script(options); - this.raw = STACK_FALSE; + this.raw = EMPTY_BUFFER; this.code = []; if (options) @@ -104,29 +102,18 @@ Script.types = common.types; Script.typesByVal = common.typesByVal; -/** - * Getter to retrieve code length. - * @name module:script.Script#length_getter - * @method - * @private - * @returns {Number} - */ - -Script.prototype.__defineGetter__('length', function() { - return this.code.length; -}); - -/** - * Setter to set code length. - * @name module:script.Script#length_setter - * @method - * @private - * @param {Number} value - * @returns {Number} +/* + * Expose length setter and getter. */ -Script.prototype.__defineSetter__('length', function(length) { - return this.code.length = length; +Object.defineProperty(Script.prototype, 'length', { + get() { + return this.code.length; + }, + set(length) { + this.code.length = length; + return this.code.length; + } }); /** @@ -153,7 +140,7 @@ Script.prototype.fromOptions = function fromOptions(options) { if (options.code) { if (!options.raw) - return this.fromCode(options.code); + return this.fromArray(options.code); assert(Array.isArray(options.code), 'Code must be an array.'); this.code = options.code; } @@ -171,6 +158,33 @@ Script.fromOptions = function fromOptions(options) { return new Script().fromOptions(options); }; +/** + * Instantiate a value-only iterator. + * @returns {ScriptIterator} + */ + +Script.prototype.values = function values() { + return this.code.values(); +}; + +/** + * Instantiate a key and value iterator. + * @returns {ScriptIterator} + */ + +Script.prototype.entries = function entries() { + return this.code.entries(); +}; + +/** + * Instantiate a value-only iterator. + * @returns {ScriptIterator} + */ + +Script.prototype[Symbol.iterator] = function() { + return this.code[Symbol.iterator](); +}; + /** * Convert the script to an array of * Buffers (pushdatas) and Numbers @@ -179,12 +193,7 @@ Script.fromOptions = function fromOptions(options) { */ Script.prototype.toArray = function toArray() { - let code = []; - - for (let op of this.code) - code.push(op.data || op.value); - - return code; + return this.code.slice(); }; /** @@ -198,28 +207,12 @@ Script.prototype.toArray = function toArray() { Script.prototype.fromArray = function fromArray(code) { assert(Array.isArray(code)); - if (code.length === 0) - return this; - - if (code[0] instanceof Opcode) - return this.fromCode(code); - - for (let op of code) { - if (Buffer.isBuffer(op)) { - this.code.push(Opcode.fromData(op)); - continue; - } - if (typeof op === 'string') { - this.code.push(Opcode.fromSymbol(op)); - continue; - } - assert(typeof op === 'number'); - this.code.push(Opcode.fromOp(op)); - } + this.clear(); - this.compile(); + for (const op of code) + this.push(op); - return this; + return this.compile(); }; /** @@ -234,42 +227,81 @@ Script.fromArray = function fromArray(code) { }; /** - * Return an array of opcodes. - * @returns {Opcode[]} + * Convert script to stack items. + * @returns {Buffer[]} */ -Script.prototype.toCode = function toCode() { - return this.code.slice(); +Script.prototype.toItems = function toItems() { + const items = []; + + for (const op of this.code) { + const data = op.toPush(); + + if (!data) + throw new Error('Non-push opcode in script.'); + + items.push(data); + } + + return items; }; /** - * Inject properties from an array of opcodes. - * @param {Opcode[]} code + * Inject data from stack items. * @private + * @param {Buffer[]} items + * @returns {Script} */ -Script.prototype.fromCode = function fromCode(code) { - assert(Array.isArray(code)); +Script.prototype.fromItems = function fromItems(items) { + assert(Array.isArray(items)); - if (code.length === 0) - return this; + this.clear(); - assert(code[0] instanceof Opcode); + for (const item of items) + this.pushData(item); - this.code = code; - this.compile(); + return this.compile(); +}; - return this; +/** + * Instantiate script from stack items. + * @param {Buffer[]} items + * @returns {Script} + */ + +Script.fromItems = function fromItems(items) { + return new Script().fromItems(items); +}; + +/** + * Convert script to stack. + * @returns {Stack} + */ + +Script.prototype.toStack = function toStack() { + return new Stack(this.toItems()); }; /** - * Instantiate script from an array of opcodes. - * @param {Opcode[]} code + * Inject data from stack. + * @private + * @param {Stack} stack + * @returns {Script} + */ + +Script.prototype.fromStack = function fromStack(stack) { + return this.fromItems(stack.items); +}; + +/** + * Instantiate script from stack. + * @param {Stack} stack * @returns {Script} */ -Script.fromCode = function fromCode(code) { - return new Script().fromCode(code); +Script.fromStack = function fromStack(stack) { + return new Script().fromStack(stack); }; /** @@ -290,8 +322,41 @@ Script.prototype.clone = function clone() { */ Script.prototype.inject = function inject(script) { - this.code = script.code.slice(); this.raw = script.raw; + this.code = script.code.slice(); + return this; +}; + +/** + * Test equality against script. + * @param {Script} script + * @returns {Boolean} + */ + +Script.prototype.equals = function equals(script) { + assert(Script.isScript(script)); + return this.raw.equals(script.raw); +}; + +/** + * Compare against another script. + * @param {Script} script + * @returns {Number} + */ + +Script.prototype.compare = function compare(script) { + assert(Script.isScript(script)); + return this.raw.compare(script.raw); +}; + +/** + * Clear the script. + * @returns {Script} + */ + +Script.prototype.clear = function clear() { + this.raw = EMPTY_BUFFER; + this.code.length = 0; return this; }; @@ -310,7 +375,12 @@ Script.prototype.inspect = function inspect() { */ Script.prototype.toString = function toString() { - return common.formatCode(this.code); + const out = []; + + for (const op of this.code) + out.push(op.toFormat()); + + return out.join(' '); }; /** @@ -320,33 +390,35 @@ Script.prototype.toString = function toString() { */ Script.prototype.toASM = function toASM(decode) { - return common.formatASM(this.code, decode); -}; - -/** - * Calculate size of code to be compiled. - * @returns {Number} - */ + if (this.isNulldata()) + decode = false; -Script.prototype.getCodeSize = function getCodeSize() { - let size = 0; + const out = []; - for (let op of this.code) - size += op.getSize(); + for (const op of this.code) + out.push(op.toASM(decode)); - return size; + return out.join(' '); }; /** * Re-encode the script internally. Useful if you * changed something manually in the `code` array. + * @returns {Script} */ Script.prototype.compile = function compile() { - let size = this.getCodeSize(); - let bw = new StaticWriter(size); + if (this.code.length === 0) + return this.clear(); + + let size = 0; - for (let op of this.code) + for (const op of this.code) + size += op.getSize(); + + const bw = new StaticWriter(size); + + for (const op of this.code) op.toWriter(bw); this.raw = bw.render(); @@ -406,26 +478,26 @@ Script.fromJSON = function fromJSON(json) { /** * Get the script's "subscript" starting at a separator. - * @param {Number?} lastSep - The last separator to sign/verify beyond. + * @param {Number} index - The last separator to sign/verify beyond. * @returns {Script} Subscript. */ -Script.prototype.getSubscript = function getSubscript(lastSep) { - let code = []; - - if (lastSep === 0) +Script.prototype.getSubscript = function getSubscript(index) { + if (index === 0) return this.clone(); - for (let i = lastSep; i < this.code.length; i++) { - let op = this.code[i]; + const script = new Script(); + + for (let i = index; i < this.code.length; i++) { + const op = this.code[i]; if (op.value === -1) break; - code.push(op); + script.code.push(op); } - return Script.fromCode(code); + return script.compile(); }; /** @@ -438,11 +510,10 @@ Script.prototype.getSubscript = function getSubscript(lastSep) { Script.prototype.removeSeparators = function removeSeparators() { let found = false; - let code; // Optimizing for the common case: // Check for any separators first. - for (let op of this.code) { + for (const op of this.code) { if (op.value === -1) break; @@ -458,17 +529,17 @@ Script.prototype.removeSeparators = function removeSeparators() { // Uncommon case: someone actually // has a code separator. Go through // and remove them all. - code = []; + const script = new Script(); - for (let op of this.code) { + for (const op of this.code) { if (op.value === -1) break; if (op.value !== opcodes.OP_CODESEPARATOR) - code.push(op); + script.code.push(op); } - return Script.fromCode(code); + return script.compile(); }; /** @@ -480,47 +551,37 @@ Script.prototype.removeSeparators = function removeSeparators() { * @param {Amount?} value - Previous output value. * @param {Number?} version - Signature hash version (0=legacy, 1=segwit). * @throws {ScriptError} Will be thrown on VERIFY failures, among other things. - * @returns {Boolean} Whether the execution was successful. */ Script.prototype.execute = function execute(stack, flags, tx, index, value, version) { - let lastSep = 0; - let opCount = 0; - let negate = 0; - let minimal = false; - let state = []; - let alt = []; - if (flags == null) flags = Script.flags.STANDARD_VERIFY_FLAGS; if (version == null) version = 0; + if (this.raw.length > consensus.MAX_SCRIPT_SIZE) + throw new ScriptError('SCRIPT_SIZE'); + + const state = []; + const alt = []; + + let lastSep = 0; + let opCount = 0; + let negate = 0; + let minimal = false; + if (flags & Script.flags.VERIFY_MINIMALDATA) minimal = true; - if (this.getSize() > consensus.MAX_SCRIPT_SIZE) - throw new ScriptError('SCRIPT_SIZE'); - for (let ip = 0; ip < this.code.length; ip++) { - let op = this.code[ip]; + const op = this.code[ip]; if (op.value === -1) throw new ScriptError('BAD_OPCODE', op, ip); - if (op.data) { - if (op.data.length > consensus.MAX_SCRIPT_PUSH) - throw new ScriptError('PUSH_SIZE', op, ip); - - if (negate === 0) { - if (minimal && !op.isMinimal()) - throw new ScriptError('MINIMALDATA', op, ip); - stack.push(op.data); - } - - continue; - } + if (op.data && op.data.length > consensus.MAX_SCRIPT_PUSH) + throw new ScriptError('PUSH_SIZE', op, ip); if (op.value > opcodes.OP_16 && ++opCount > consensus.MAX_SCRIPT_OPS) throw new ScriptError('OP_COUNT', op, ip); @@ -528,22 +589,34 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (op.isDisabled()) throw new ScriptError('DISABLED_OPCODE', op, ip); - if (negate !== 0 && !op.isBranch()) + if (negate && !op.isBranch()) { + if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK) + throw new ScriptError('STACK_SIZE', op, ip); + continue; + } + + if (op.data) { + if (minimal && !op.isMinimal()) + throw new ScriptError('MINIMALDATA', op, ip); + + stack.push(op.data); + + if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK) + throw new ScriptError('STACK_SIZE', op, ip); + continue; + } switch (op.value) { case opcodes.OP_0: { - stack.push(STACK_FALSE); + stack.pushInt(0); break; } case opcodes.OP_1NEGATE: { - stack.push(STACK_NEGATE); - break; - } - case opcodes.OP_1: { - stack.push(STACK_TRUE); + stack.pushInt(-1); break; } + case opcodes.OP_1: case opcodes.OP_2: case opcodes.OP_3: case opcodes.OP_4: @@ -559,15 +632,13 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers case opcodes.OP_14: case opcodes.OP_15: case opcodes.OP_16: { - stack.push(Buffer.from([op.value - 0x50])); + stack.pushInt(op.value - 0x50); break; } case opcodes.OP_NOP: { break; } case opcodes.OP_CHECKLOCKTIMEVERIFY: { - let locktime; - // OP_CHECKLOCKTIMEVERIFY = OP_NOP2 if (!(flags & Script.flags.VERIFY_CHECKLOCKTIMEVERIFY)) { if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -581,12 +652,12 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - locktime = Script.num(stack.top(-1), minimal, 5); + const num = stack.getNum(-1, minimal, 5); - if (locktime.cmpn(0) < 0) + if (num.isNeg()) throw new ScriptError('NEGATIVE_LOCKTIME', op, ip); - locktime = locktime.toNumber(); + const locktime = num.toDouble(); if (!tx.verifyLocktime(index, locktime)) throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip); @@ -594,8 +665,6 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers break; } case opcodes.OP_CHECKSEQUENCEVERIFY: { - let locktime; - // OP_CHECKSEQUENCEVERIFY = OP_NOP3 if (!(flags & Script.flags.VERIFY_CHECKSEQUENCEVERIFY)) { if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -609,12 +678,12 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - locktime = Script.num(stack.top(-1), minimal, 5); + const num = stack.getNum(-1, minimal, 5); - if (locktime.cmpn(0) < 0) + if (num.isNeg()) throw new ScriptError('NEGATIVE_LOCKTIME', op, ip); - locktime = locktime.toNumber(); + const locktime = num.toDouble(); if (!tx.verifySequence(index, locktime)) throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip); @@ -637,21 +706,21 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers case opcodes.OP_NOTIF: { let val = false; - if (negate === 0) { + if (!negate) { if (stack.length < 1) throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip); - val = stack.top(-1); - if (version === 1 && (flags & Script.flags.VERIFY_MINIMALIF)) { - if (val.length > 1) + const item = stack.get(-1); + + if (item.length > 1) throw new ScriptError('MINIMALIF'); - if (val.length === 1 && val[0] !== 1) + if (item.length === 1 && item[0] !== 1) throw new ScriptError('MINIMALIF'); } - val = Script.bool(val); + val = stack.getBool(-1); if (op.value === opcodes.OP_NOTIF) val = !val; @@ -662,7 +731,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers state.push(val); if (!val) - negate++; + negate += 1; break; } @@ -673,9 +742,9 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers state[state.length - 1] = !state[state.length - 1]; if (!state[state.length - 1]) - negate++; + negate += 1; else - negate--; + negate -= 1; break; } @@ -684,7 +753,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip); if (!state.pop()) - negate--; + negate -= 1; break; } @@ -692,7 +761,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - if (!Script.bool(stack.top(-1))) + if (!stack.getBool(-1)) throw new ScriptError('VERIFY', op, ip); stack.pop(); @@ -725,27 +794,23 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers break; } case opcodes.OP_2DUP: { - let v1, v2; - if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - v1 = stack.top(-2); - v2 = stack.top(-1); + const v1 = stack.get(-2); + const v2 = stack.get(-1); stack.push(v1); stack.push(v2); break; } case opcodes.OP_3DUP: { - let v1, v2, v3; - if (stack.length < 3) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - v1 = stack.top(-3); - v2 = stack.top(-2); - v3 = stack.top(-1); + const v1 = stack.get(-3); + const v2 = stack.get(-2); + const v3 = stack.get(-1); stack.push(v1); stack.push(v2); @@ -753,26 +818,22 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers break; } case opcodes.OP_2OVER: { - let v1, v2; - if (stack.length < 4) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - v1 = stack.top(-4); - v2 = stack.top(-3); + const v1 = stack.get(-4); + const v2 = stack.get(-3); stack.push(v1); stack.push(v2); break; } case opcodes.OP_2ROT: { - let v1, v2; - if (stack.length < 6) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - v1 = stack.top(-6); - v2 = stack.top(-5); + const v1 = stack.get(-6); + const v2 = stack.get(-5); stack.erase(-6, -4); stack.push(v1); @@ -788,19 +849,18 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers break; } case opcodes.OP_IFDUP: { - let val; - if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - val = stack.top(-1); - - if (Script.bool(val)) + if (stack.getBool(-1)) { + const val = stack.get(-1); stack.push(val); + } + break; } case opcodes.OP_DEPTH: { - stack.push(Script.array(stack.length)); + stack.pushInt(stack.length); break; } case opcodes.OP_DROP: { @@ -814,7 +874,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(stack.top(-1)); + stack.push(stack.get(-1)); break; } case opcodes.OP_NIP: { @@ -828,23 +888,21 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(stack.top(-2)); + stack.push(stack.get(-2)); break; } case opcodes.OP_PICK: case opcodes.OP_ROLL: { - let num, val; - if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - num = Script.num(stack.top(-1), minimal).toNumber(); + const num = stack.getInt(-1, minimal, 4); stack.pop(); if (num < 0 || num >= stack.length) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - val = stack.top(-num - 1); + const val = stack.get(-num - 1); if (op.value === opcodes.OP_ROLL) stack.remove(-num - 1); @@ -871,32 +929,30 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.insert(-2, stack.top(-1)); + stack.insert(-2, stack.get(-1)); break; } case opcodes.OP_SIZE: { if (stack.length < 1) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(Script.array(stack.top(-1).length)); + stack.pushInt(stack.get(-1).length); break; } case opcodes.OP_EQUAL: case opcodes.OP_EQUALVERIFY: { - let v1, v2, res; - if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - v1 = stack.top(-2); - v2 = stack.top(-1); + const v1 = stack.get(-2); + const v2 = stack.get(-1); - res = v1.equals(v2); + const res = v1.equals(v2); stack.pop(); stack.pop(); - stack.push(res ? STACK_TRUE : STACK_FALSE); + stack.pushBool(res); if (op.value === opcodes.OP_EQUALVERIFY) { if (!res) @@ -912,12 +968,11 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers case opcodes.OP_ABS: case opcodes.OP_NOT: case opcodes.OP_0NOTEQUAL: { - let num; - if (stack.length < 1) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - num = Script.num(stack.top(-1), minimal); + let num = stack.getNum(-1, minimal, 4); + let cmp; switch (op.value) { case opcodes.OP_1ADD: @@ -933,12 +988,12 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers num.iabs(); break; case opcodes.OP_NOT: - num = num.cmpn(0) === 0; - num = new BN(num ? 1 : 0); + cmp = num.isZero(); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_0NOTEQUAL: - num = num.cmpn(0) !== 0; - num = new BN(num ? 1 : 0); + cmp = !num.isZero(); + num = ScriptNum.fromBool(cmp); break; default: assert(false, 'Fatal script error.'); @@ -946,7 +1001,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers } stack.pop(); - stack.push(Script.array(num)); + stack.pushNum(num); break; } @@ -963,13 +1018,12 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers case opcodes.OP_GREATERTHANOREQUAL: case opcodes.OP_MIN: case opcodes.OP_MAX: { - let n1, n2, num; - if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - n1 = Script.num(stack.top(-2), minimal); - n2 = Script.num(stack.top(-1), minimal); + const n1 = stack.getNum(-2, minimal, 4); + const n2 = stack.getNum(-1, minimal, 4); + let num, cmp; switch (op.value) { case opcodes.OP_ADD: @@ -979,46 +1033,46 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers num = n1.isub(n2); break; case opcodes.OP_BOOLAND: - num = n1.cmpn(0) !== 0 && n2.cmpn(0) !== 0; - num = new BN(num ? 1 : 0); + cmp = n1.toBool() && n2.toBool(); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_BOOLOR: - num = n1.cmpn(0) !== 0 || n2.cmpn(0) !== 0; - num = new BN(num ? 1 : 0); + cmp = n1.toBool() || n2.toBool(); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_NUMEQUAL: - num = n1.cmp(n2) === 0; - num = new BN(num ? 1 : 0); + cmp = n1.eq(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_NUMEQUALVERIFY: - num = n1.cmp(n2) === 0; - num = new BN(num ? 1 : 0); + cmp = n1.eq(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_NUMNOTEQUAL: - num = n1.cmp(n2) !== 0; - num = new BN(num ? 1 : 0); + cmp = !n1.eq(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_LESSTHAN: - num = n1.cmp(n2) < 0; - num = new BN(num ? 1 : 0); + cmp = n1.lt(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_GREATERTHAN: - num = n1.cmp(n2) > 0; - num = new BN(num ? 1 : 0); + cmp = n1.gt(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_LESSTHANOREQUAL: - num = n1.cmp(n2) <= 0; - num = new BN(num ? 1 : 0); + cmp = n1.lte(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_GREATERTHANOREQUAL: - num = n1.cmp(n2) >= 0; - num = new BN(num ? 1 : 0); + cmp = n1.gte(n2); + num = ScriptNum.fromBool(cmp); break; case opcodes.OP_MIN: - num = n1.cmp(n2) < 0 ? n1 : n2; + num = ScriptNum.min(n1, n2); break; case opcodes.OP_MAX: - num = n1.cmp(n2) > 0 ? n1 : n2; + num = ScriptNum.max(n1, n2); break; default: assert(false, 'Fatal script error.'); @@ -1027,10 +1081,10 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers stack.pop(); stack.pop(); - stack.push(Script.array(num)); + stack.pushNum(num); if (op.value === opcodes.OP_NUMEQUALVERIFY) { - if (!Script.bool(stack.top(-1))) + if (!stack.getBool(-1)) throw new ScriptError('NUMEQUALVERIFY', op, ip); stack.pop(); } @@ -1038,22 +1092,20 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers break; } case opcodes.OP_WITHIN: { - let val, n1, n2, n3; - if (stack.length < 3) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - n1 = Script.num(stack.top(-3), minimal); - n2 = Script.num(stack.top(-2), minimal); - n3 = Script.num(stack.top(-1), minimal); + const n1 = stack.getNum(-3, minimal, 4); + const n2 = stack.getNum(-2, minimal, 4); + const n3 = stack.getNum(-1, minimal, 4); - val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0; + const val = n2.lte(n1) && n1.lt(n3); stack.pop(); stack.pop(); stack.pop(); - stack.push(val ? STACK_TRUE : STACK_FALSE); + stack.pushBool(val); break; } case opcodes.OP_RIPEMD160: { @@ -1097,29 +1149,28 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers } case opcodes.OP_CHECKSIG: case opcodes.OP_CHECKSIGVERIFY: { - let sig, key, res, subscript; - if (!tx) throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.'); if (stack.length < 2) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - sig = stack.top(-2); - key = stack.top(-1); - res = false; + const sig = stack.get(-2); + const key = stack.get(-1); - subscript = this.getSubscript(lastSep); + const subscript = this.getSubscript(lastSep); if (version === 0) - subscript.removeData(sig); + subscript.findAndDelete(sig); validateSignature(sig, flags); validateKey(key, flags, version); + let res = false; + if (sig.length > 0) { - let type = sig[sig.length - 1]; - let hash = tx.signatureHash(index, subscript, value, type, version); + const type = sig[sig.length - 1]; + const hash = tx.signatureHash(index, subscript, value, type, version); res = checksig(hash, sig, key); } @@ -1131,7 +1182,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers stack.pop(); stack.pop(); - stack.push(res ? STACK_TRUE : STACK_FALSE); + stack.pushBool(res); if (op.value === opcodes.OP_CHECKSIGVERIFY) { if (!res) @@ -1143,19 +1194,18 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers } case opcodes.OP_CHECKMULTISIG: case opcodes.OP_CHECKMULTISIGVERIFY: { - let i, m, n, isig, ikey, ikey2, subscript, res; - if (!tx) throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.'); - i = 1; + let i = 1; if (stack.length < i) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - n = Script.num(stack.top(-i), minimal).toNumber(); - ikey2 = n + 2; + let n = stack.getInt(-i, minimal, 4); + let okey = n + 2; + let ikey, isig; - if (!(n >= 0 && n <= consensus.MAX_MULTISIG_PUBKEYS)) + if (n < 0 || n > consensus.MAX_MULTISIG_PUBKEYS) throw new ScriptError('PUBKEY_COUNT', op, ip); opCount += n; @@ -1163,79 +1213,89 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (opCount > consensus.MAX_SCRIPT_OPS) throw new ScriptError('OP_COUNT', op, ip); - i++; + i += 1; ikey = i; i += n; if (stack.length < i) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - m = Script.num(stack.top(-i), minimal).toNumber(); + let m = stack.getInt(-i, minimal, 4); - if (!(m >= 0 && m <= n)) + if (m < 0 || m > n) throw new ScriptError('SIG_COUNT', op, ip); - i++; + i += 1; isig = i; i += m; if (stack.length < i) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - subscript = this.getSubscript(lastSep); + const subscript = this.getSubscript(lastSep); for (let j = 0; j < m; j++) { - let sig = stack.top(-isig - j); + const sig = stack.get(-isig - j); if (version === 0) - subscript.removeData(sig); + subscript.findAndDelete(sig); } - res = true; + let res = true; while (res && m > 0) { - let sig = stack.top(-isig); - let key = stack.top(-ikey); + const sig = stack.get(-isig); + const key = stack.get(-ikey); validateSignature(sig, flags); validateKey(key, flags, version); if (sig.length > 0) { - let type = sig[sig.length - 1]; - let hash = tx.signatureHash(index, subscript, value, type, version); + const type = sig[sig.length - 1]; + const hash = tx.signatureHash( + index, + subscript, + value, + type, + version + ); if (checksig(hash, sig, key)) { - isig++; - m--; + isig += 1; + m -= 1; } } - ikey++; - n--; + ikey += 1; + n -= 1; if (m > n) res = false; } - while (i-- > 1) { + while (i > 1) { if (!res && (flags & Script.flags.VERIFY_NULLFAIL)) { - if (ikey2 === 0 && stack.top(-1).length !== 0) + if (okey === 0 && stack.get(-1).length !== 0) throw new ScriptError('NULLFAIL', op, ip); } - if (ikey2 > 0) - ikey2--; + + if (okey > 0) + okey -= 1; + stack.pop(); + + i -= 1; } if (stack.length < 1) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); if (flags & Script.flags.VERIFY_NULLDUMMY) { - if (stack.top(-1).length !== 0) + if (stack.get(-1).length !== 0) throw new ScriptError('SIG_NULLDUMMY', op, ip); } stack.pop(); - stack.push(res ? STACK_TRUE : STACK_FALSE); + stack.pushBool(res); if (op.value === opcodes.OP_CHECKMULTISIGVERIFY) { if (!res) @@ -1249,67 +1309,13 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers throw new ScriptError('BAD_OPCODE', op, ip); } } - } - if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK) - throw new ScriptError('STACK_SIZE'); + if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK) + throw new ScriptError('STACK_SIZE', op, ip); + } if (state.length !== 0) throw new ScriptError('UNBALANCED_CONDITIONAL'); - - return true; -}; - -/** - * Cast a big number or Buffer to a bool. - * @see CastToBool - * @param {BN|Buffer} value - * @returns {Boolean} - */ - -Script.bool = function bool(value) { - assert(Buffer.isBuffer(value)); - - for (let i = 0; i < value.length; i++) { - if (value[i] !== 0) { - // Cannot be negative zero - if (i === value.length - 1 && value[i] === 0x80) - return false; - return true; - } - } - - return false; -}; - -/** - * Create a CScriptNum. - * @param {Buffer} value - * @param {Boolean?} minimal - * @param {Number?} size - Max size in bytes. - * @returns {BN} - * @throws {ScriptError} - */ - -Script.num = function num(value, minimal, size) { - return common.num(value, minimal, size); -}; - -/** - * Create a script array. Will convert Numbers and big - * numbers to a little-endian buffer while taking into - * account negative zero, minimaldata, etc. - * @example - * assert.deepEqual(Script.array(0), Buffer.alloc(0)); - * assert.deepEqual(Script.array(0xffee), Buffer.from('eeff00', 'hex')); - * assert.deepEqual(Script.array(new BN(0xffee)), Buffer.from('eeff00', 'hex')); - * assert.deepEqual(Script.array(new BN(0x1e).ineg()), Buffer.from('9e', 'hex')); - * @param {Number|BN} value - * @returns {Buffer} - */ - -Script.array = function array(value) { - return common.array(value); }; /** @@ -1327,43 +1333,47 @@ Script.array = function array(value) { * @returns {Number} Total. */ -Script.prototype.removeData = function removeData(data) { - let index = []; +Script.prototype.findAndDelete = function findAndDelete(data) { + const target = Opcode.fromPush(data); - // We need to go forward first. We can't go - // backwards (this is consensus code and we - // need to be aware of bad pushes). - for (let i = 0; i < this.code.length; i++) { - let op = this.code[i]; + if (this.raw.length < target.getSize()) + return 0; + + let found = false; + + for (const op of this.code) { + if (op.value === -1) + break; - if (op.value === -1) { - // Can't reserialize - // a parse error. - if (index.length > 0) - index.push(i); + if (op.equals(target)) { + found = true; break; } + } - if (!op.data) - continue; + if (!found) + return 0; - if (!op.isMinimal()) - continue; + const code = []; - if (op.data.equals(data)) - index.push(i); - } + let total = 0; - if (index.length === 0) - return 0; + for (const op of this.code) { + if (op.value === -1) + break; + + if (op.equals(target)) { + total += 1; + continue; + } - // Go backwards and splice out the data. - for (let i = index.length - 1; i >= 0; i--) - this.code.splice(index[i], 1); + code.push(op); + } + this.code = code; this.compile(); - return index.length; + return total; }; /** @@ -1374,7 +1384,7 @@ Script.prototype.removeData = function removeData(data) { Script.prototype.indexOf = function indexOf(data) { for (let i = 0; i < this.code.length; i++) { - let op = this.code[i]; + const op = this.code[i]; if (op.value === -1) break; @@ -1390,20 +1400,32 @@ Script.prototype.indexOf = function indexOf(data) { }; /** - * Test a script to see if it is valid - * script code (no non-existent opcodes). + * Test a script to see if it is likely + * to be script code (no weird opcodes). * @returns {Boolean} */ Script.prototype.isCode = function isCode() { - for (let op of this.code) { - if (op.data) - continue; - + for (const op of this.code) { if (op.value === -1) return false; - if (op.value > opcodes.OP_NOP10) + if (op.isDisabled()) + return false; + + switch (op.value) { + case opcodes.OP_RESERVED: + case opcodes.OP_NOP: + case opcodes.OP_VER: + case opcodes.OP_VERIF: + case opcodes.OP_VERNOTIF: + case opcodes.OP_RESERVED1: + case opcodes.OP_RESERVED2: + case opcodes.OP_NOP1: + return false; + } + + if (op.value > opcodes.OP_CHECKSEQUENCEVERIFY) return false; } @@ -1417,7 +1439,7 @@ Script.prototype.isCode = function isCode() { */ Script.prototype.fromPubkey = function fromPubkey(key) { - assert(Buffer.isBuffer(key) && key.length >= 33 && key.length <= 65); + assert(Buffer.isBuffer(key) && (key.length === 33 || key.length === 65)); this.raw = Buffer.allocUnsafe(1 + key.length + 1); this.raw[0] = key.length; @@ -1426,8 +1448,9 @@ Script.prototype.fromPubkey = function fromPubkey(key) { key = this.raw.slice(1, 1 + key.length); - this.code.push(new Opcode(key.length, key)); - this.code.push(new Opcode(opcodes.OP_CHECKSIG)); + this.code.length = 0; + this.code.push(Opcode.fromPush(key)); + this.code.push(Opcode.fromOp(opcodes.OP_CHECKSIG)); return this; }; @@ -1461,11 +1484,12 @@ Script.prototype.fromPubkeyhash = function fromPubkeyhash(hash) { hash = this.raw.slice(3, 23); - this.code.push(new Opcode(opcodes.OP_DUP)); - this.code.push(new Opcode(opcodes.OP_HASH160)); - this.code.push(new Opcode(0x14, hash)); - this.code.push(new Opcode(opcodes.OP_EQUALVERIFY)); - this.code.push(new Opcode(opcodes.OP_CHECKSIG)); + this.code.length = 0; + this.code.push(Opcode.fromOp(opcodes.OP_DUP)); + this.code.push(Opcode.fromOp(opcodes.OP_HASH160)); + this.code.push(Opcode.fromPush(hash)); + this.code.push(Opcode.fromOp(opcodes.OP_EQUALVERIFY)); + this.code.push(Opcode.fromOp(opcodes.OP_CHECKSIG)); return this; }; @@ -1489,25 +1513,23 @@ Script.fromPubkeyhash = function fromPubkeyhash(hash) { */ Script.prototype.fromMultisig = function fromMultisig(m, n, keys) { - assert(util.isNumber(m) && util.isNumber(n)); + assert(util.isU8(m) && util.isU8(n)); assert(Array.isArray(keys)); assert(keys.length === n, '`n` keys are required for multisig.'); assert(m >= 1 && m <= n); assert(n >= 1 && n <= 15); - keys = sortKeys(keys); + this.clear(); - this.push(Opcode.fromSmall(m)); + this.pushSmall(m); - for (let key of keys) - this.push(key); + for (const key of sortKeys(keys)) + this.pushData(key); - this.push(Opcode.fromSmall(n)); - this.push(opcodes.OP_CHECKMULTISIG); + this.pushSmall(n); + this.pushOp(opcodes.OP_CHECKMULTISIG); - this.compile(); - - return this; + return this.compile(); }; /** @@ -1539,9 +1561,10 @@ Script.prototype.fromScripthash = function fromScripthash(hash) { hash = this.raw.slice(2, 22); - this.code.push(new Opcode(opcodes.OP_HASH160)); - this.code.push(new Opcode(0x14, hash)); - this.code.push(new Opcode(opcodes.OP_EQUAL)); + this.code.length = 0; + this.code.push(Opcode.fromOp(opcodes.OP_HASH160)); + this.code.push(Opcode.fromPush(hash)); + this.code.push(Opcode.fromOp(opcodes.OP_EQUAL)); return this; }; @@ -1565,10 +1588,12 @@ Script.fromScripthash = function fromScripthash(hash) { Script.prototype.fromNulldata = function fromNulldata(flags) { assert(Buffer.isBuffer(flags)); assert(flags.length <= policy.MAX_OP_RETURN, 'Nulldata too large.'); - this.push(opcodes.OP_RETURN); - this.push(flags); - this.compile(); - return this; + + this.clear(); + this.pushOp(opcodes.OP_RETURN); + this.pushData(flags); + + return this.compile(); }; /** @@ -1589,22 +1614,19 @@ Script.fromNulldata = function fromNulldata(flags) { */ Script.prototype.fromProgram = function fromProgram(version, data) { - let op; - - assert(util.isNumber(version) && version >= 0 && version <= 16); + assert(util.isU8(version) && version >= 0 && version <= 16); assert(Buffer.isBuffer(data) && data.length >= 2 && data.length <= 40); - op = Opcode.fromSmall(version); - this.raw = Buffer.allocUnsafe(2 + data.length); - this.raw[0] = op.value; + this.raw[0] = version === 0 ? 0 : version + 0x50; this.raw[1] = data.length; data.copy(this.raw, 2); data = this.raw.slice(2, 2 + data.length); - this.code.push(op); - this.code.push(new Opcode(data.length, data)); + this.code.length = 0; + this.code.push(Opcode.fromSmall(version)); + this.code.push(Opcode.fromPush(data)); return this; }; @@ -1662,20 +1684,19 @@ Script.fromAddress = function fromAddress(address) { */ Script.prototype.fromCommitment = function fromCommitment(hash, flags) { - let bw = new StaticWriter(36); + const bw = new StaticWriter(36); bw.writeU32BE(0xaa21a9ed); bw.writeHash(hash); - this.push(opcodes.OP_RETURN); - this.push(bw.render()); + this.clear(); + this.pushOp(opcodes.OP_RETURN); + this.pushData(bw.render()); if (flags) - this.push(flags); + this.pushData(flags); - this.compile(); - - return this; + return this.compile(); }; /** @@ -1695,20 +1716,22 @@ Script.fromCommitment = function fromCommitment(hash, flags) { */ Script.prototype.getRedeem = function getRedeem() { - let redeem; + let data = null; - if (this.code.length === 0) - return; + for (const op of this.code) { + if (op.value === -1) + return null; - if (!this.isPushOnly()) - return; + if (op.value > opcodes.OP_16) + return null; - redeem = this.code[this.code.length - 1]; + data = op.data; + } - if (!redeem.data) - return; + if (!data) + return null; - return Script.fromRaw(redeem.data); + return Script.fromRaw(data); }; /** @@ -1759,30 +1782,22 @@ Script.prototype.isUnknown = function isUnknown() { */ Script.prototype.isStandard = function isStandard() { - let type = this.getType(); - - switch (type) { - case scriptTypes.MULTISIG: { - let m = this.getSmall(0); - let n = this.getSmall(this.code.length - 2); + const [m, n] = this.getMultisig(); - if (n < 1 || n > 3) - return false; + if (m !== -1) { + if (n < 1 || n > 3) + return false; - if (m < 1 || m > n) - return false; + if (m < 1 || m > n) + return false; - return true; - } - case scriptTypes.NULLDATA: { - if (this.raw.length > policy.MAX_OP_RETURN_BYTES) - return false; - return true; - } - default: { - return type !== scriptTypes.NONSTANDARD; - } + return true; } + + if (this.isNulldata()) + return this.raw.length <= policy.MAX_OP_RETURN_BYTES; + + return this.getType() !== scriptTypes.NONSTANDARD; }; /** @@ -1861,15 +1876,34 @@ Script.prototype.sha256 = function sha256(enc) { Script.prototype.isPubkey = function isPubkey(minimal) { if (minimal) { return this.raw.length >= 35 - && this.raw[0] >= 33 && this.raw[0] <= 65 + && (this.raw[0] === 33 || this.raw[0] === 65) && this.raw[0] + 2 === this.raw.length && this.raw[this.raw.length - 1] === opcodes.OP_CHECKSIG; } - return this.code.length === 2 - && this.code[0].data - && common.isKey(this.code[0].data) - && this.code[1].value === opcodes.OP_CHECKSIG; + if (this.code.length !== 2) + return false; + + const size = this.getLength(0); + + return (size === 33 || size === 65) + && this.getOp(1) === opcodes.OP_CHECKSIG; +}; + +/** + * Get P2PK key if present. + * @param {Boolean} [minimal=false] - Minimaldata only. + * @returns {Buffer|null} + */ + +Script.prototype.getPubkey = function getPubkey(minimal) { + if (!this.isPubkey(minimal)) + return null; + + if (minimal) + return this.raw.slice(1, 1 + this.raw[0]); + + return this.getData(0); }; /** @@ -1879,7 +1913,7 @@ Script.prototype.isPubkey = function isPubkey(minimal) { */ Script.prototype.isPubkeyhash = function isPubkeyhash(minimal) { - if (minimal) { + if (minimal || this.raw.length === 25) { return this.raw.length === 25 && this.raw[0] === opcodes.OP_DUP && this.raw[1] === opcodes.OP_HASH160 @@ -1888,12 +1922,30 @@ Script.prototype.isPubkeyhash = function isPubkeyhash(minimal) { && this.raw[24] === opcodes.OP_CHECKSIG; } - return this.code.length === 5 - && this.code[0].value === opcodes.OP_DUP - && this.code[1].value === opcodes.OP_HASH160 - && common.isHash(this.code[2].data) - && this.code[3].value === opcodes.OP_EQUALVERIFY - && this.code[4].value === opcodes.OP_CHECKSIG; + if (this.code.length !== 5) + return false; + + return this.getOp(0) === opcodes.OP_DUP + && this.getOp(1) === opcodes.OP_HASH160 + && this.getLength(2) === 20 + && this.getOp(3) === opcodes.OP_EQUALVERIFY + && this.getOp(4) === opcodes.OP_CHECKSIG; +}; + +/** + * Get P2PKH hash if present. + * @param {Boolean} [minimal=false] - Minimaldata only. + * @returns {Buffer|null} + */ + +Script.prototype.getPubkeyhash = function getPubkeyhash(minimal) { + if (!this.isPubkeyhash(minimal)) + return null; + + if (minimal) + return this.raw.slice(3, 23); + + return this.getData(2); }; /** @@ -1903,31 +1955,30 @@ Script.prototype.isPubkeyhash = function isPubkeyhash(minimal) { */ Script.prototype.isMultisig = function isMultisig(minimal) { - let m, n; - - if (this.raw.length < 41) + if (this.code.length < 4 || this.code.length > 19) return false; - if (this.raw[this.raw.length - 1] !== opcodes.OP_CHECKMULTISIG) + if (this.getOp(-1) !== opcodes.OP_CHECKMULTISIG) return false; - n = common.getSmall(this.raw[this.raw.length - 2]); + const m = this.getSmall(0); - if (n < 1) + if (m < 1) return false; - m = common.getSmall(this.raw[0]); + const n = this.getSmall(-2); - if (!(m >= 1 && m <= n)) + if (n < 1 || m > n) return false; - if (n + 3 !== this.code.length) + if (this.code.length !== n + 3) return false; for (let i = 1; i < n + 1; i++) { - let op = this.code[i]; + const op = this.code[i]; + const size = op.toLength(); - if (!common.isKey(op.data)) + if (size !== 33 && size !== 65) return false; if (minimal && !op.isMinimal()) @@ -1937,6 +1988,19 @@ Script.prototype.isMultisig = function isMultisig(minimal) { return true; }; +/** + * Get multisig m and n values if present. + * @param {Boolean} [minimal=false] - Minimaldata only. + * @returns {Array} [m, n] + */ + +Script.prototype.getMultisig = function getMultisig(minimal) { + if (!this.isMultisig(minimal)) + return [-1, -1]; + + return [this.getSmall(0), this.getSmall(-2)]; +}; + /** * Test whether the output script is pay-to-scripthash. Note that * bitcoin itself requires scripthashes to be in strict minimaldata @@ -1952,6 +2016,18 @@ Script.prototype.isScripthash = function isScripthash() { && this.raw[22] === opcodes.OP_EQUAL; }; +/** + * Get P2SH hash if present. + * @returns {Buffer|null} + */ + +Script.prototype.getScripthash = function getScripthash() { + if (!this.isScripthash()) + return null; + + return this.getData(1); +}; + /** * Test whether the output script is nulldata/opreturn. * @param {Boolean} [minimal=false] - Minimaldata only. @@ -1959,47 +2035,56 @@ Script.prototype.isScripthash = function isScripthash() { */ Script.prototype.isNulldata = function isNulldata(minimal) { - if (this.raw.length === 0) + if (this.code.length === 0) return false; - if (this.raw[0] !== opcodes.OP_RETURN) + if (this.getOp(0) !== opcodes.OP_RETURN) return false; - if (this.raw.length === 1) + if (this.code.length === 1) return true; if (minimal) { if (this.raw.length > policy.MAX_OP_RETURN_BYTES) return false; - - if (this.raw.length === 2) - return common.getSmall(this.raw[1]) !== -1; - - if (this.raw[1] >= 0x01 && this.raw[1] <= 0x4b) - return this.raw[1] + 2 === this.raw.length; - - if (this.raw[1] === opcodes.OP_PUSHDATA1) - return this.raw[2] > 75 && this.raw[2] + 3 === this.raw.length; - - return false; } for (let i = 1; i < this.code.length; i++) { - let op = this.code[i]; - - if (op.data) - continue; + const op = this.code[i]; if (op.value === -1) return false; if (op.value > opcodes.OP_16) return false; + + if (minimal && !op.isMinimal()) + return false; } return true; }; +/** + * Get OP_RETURN data if present. + * @param {Boolean} [minimal=false] - Minimaldata only. + * @returns {Buffer|null} + */ + +Script.prototype.getNulldata = function getNulldata(minimal) { + if (!this.isNulldata(minimal)) + return null; + + for (let i = 1; i < this.code.length; i++) { + const op = this.code[i]; + const data = op.toPush(); + if (data) + return data; + } + + return EMPTY_BUFFER; +}; + /** * Test whether the output script is a segregated witness * commitment. @@ -2018,9 +2103,9 @@ Script.prototype.isCommitment = function isCommitment() { * @returns {Buffer|null} */ -Script.prototype.getCommitmentHash = function getCommitmentHash() { +Script.prototype.getCommitment = function getCommitment() { if (!this.isCommitment()) - return; + return null; return this.raw.slice(6, 38); }; @@ -2033,11 +2118,11 @@ Script.prototype.getCommitmentHash = function getCommitmentHash() { */ Script.prototype.isProgram = function isProgram() { - if (!(this.raw.length >= 4 && this.raw.length <= 42)) + if (this.raw.length < 4 || this.raw.length > 42) return false; if (this.raw[0] !== opcodes.OP_0 - && !(this.raw[0] >= opcodes.OP_1 && this.raw[0] <= opcodes.OP_16)) { + && (this.raw[0] < opcodes.OP_1 || this.raw[0] > opcodes.OP_16)) { return false; } @@ -2052,14 +2137,12 @@ Script.prototype.isProgram = function isProgram() { * @returns {Program|null} */ -Script.prototype.toProgram = function toProgram() { - let version, data; - +Script.prototype.getProgram = function getProgram() { if (!this.isProgram()) - return; + return null; - version = common.getSmall(this.raw[0]); - data = this.raw.slice(2); + const version = this.getSmall(0); + const data = this.getData(1); return new Program(version, data); }; @@ -2067,20 +2150,22 @@ Script.prototype.toProgram = function toProgram() { /** * Get the script to the equivalent witness * program (mimics bitcoind's scriptForWitness). - * @returns {Program|null} + * @returns {Script|null} */ Script.prototype.forWitness = function forWitness() { if (this.isProgram()) - return this; + return this.clone(); - if (this.isPubkey()) { - let hash = digest.hash160(this.get(0)); + const pk = this.getPubkey(); + if (pk) { + const hash = digest.hash160(pk); return Script.fromProgram(0, hash); } - if (this.isPubkeyhash()) - return Script.fromProgram(0, this.get(2)); + const pkh = this.getPubkeyhash(); + if (pkh) + return Script.fromProgram(0, pkh); return Script.fromProgram(0, this.sha256()); }; @@ -2097,6 +2182,18 @@ Script.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() { && this.raw[1] === 0x14; }; +/** + * Get P2WPKH hash if present. + * @returns {Buffer|null} + */ + +Script.prototype.getWitnessPubkeyhash = function getWitnessPubkeyhash() { + if (!this.isWitnessPubkeyhash()) + return null; + + return this.getData(1); +}; + /** * Test whether the output script is * a pay-to-witness-scripthash program. @@ -2109,6 +2206,18 @@ Script.prototype.isWitnessScripthash = function isWitnessScripthash() { && this.raw[1] === 0x20; }; +/** + * Get P2WSH hash if present. + * @returns {Buffer|null} + */ + +Script.prototype.getWitnessScripthash = function getWitnessScripthash() { + if (!this.isWitnessScripthash()) + return null; + + return this.getData(1); +}; + /** * Test whether the output script * is a pay-to-mast program. @@ -2121,6 +2230,18 @@ Script.prototype.isWitnessMasthash = function isWitnessMasthash() { && this.raw[1] === 0x20; }; +/** + * Get P2WMH hash if present. + * @returns {Buffer|null} + */ + +Script.prototype.getWitnessMasthash = function getWitnessMasthash() { + if (!this.isWitnessMasthash()) + return null; + + return this.getData(1); +}; + /** * Test whether the output script is unspendable. * @returns {Boolean} @@ -2172,18 +2293,24 @@ Script.prototype.isUnknownInput = function isUnknownInput() { */ Script.prototype.isPubkeyInput = function isPubkeyInput() { - if (this.raw.length < 10) + if (this.code.length !== 1) return false; - if (this.raw.length > 78) - return false; + const size = this.getLength(0); - if (this.raw[0] > opcodes.OP_PUSHDATA4) - return false; + return size >= 9 && size <= 73; +}; + +/** + * Get P2PK signature if present. + * @returns {Buffer|null} + */ + +Script.prototype.getPubkeyInput = function getPubkeyInput() { + if (!this.isPubkeyInput()) + return null; - return this.code.length === 1 - && this.code[1].data - && common.isSignature(this.code[0].data); + return this.getData(0); }; /** @@ -2193,20 +2320,26 @@ Script.prototype.isPubkeyInput = function isPubkeyInput() { */ Script.prototype.isPubkeyhashInput = function isPubkeyhashInput() { - if (this.raw.length < 44) + if (this.code.length !== 2) return false; - if (this.raw.length > 148) - return false; + const sig = this.getLength(0); + const key = this.getLength(1); - if (this.raw[0] > opcodes.OP_PUSHDATA4) - return false; + return sig >= 9 && sig <= 73 + && (key === 33 || key === 65); +}; + +/** + * Get P2PKH signature and key if present. + * @returns {Array} [sig, key] + */ - return this.code.length === 2 - && this.code[0].data - && common.isSignature(this.code[0].data) - && this.code[1].data - && common.isKey(this.code[1].data); +Script.prototype.getPubkeyhashInput = function getPubkeyhashInput() { + if (!this.isPubkeyhashInput()) + return [null, null]; + + return [this.getData(0), this.getData(1)]; }; /** @@ -2216,13 +2349,13 @@ Script.prototype.isPubkeyhashInput = function isPubkeyhashInput() { */ Script.prototype.isMultisigInput = function isMultisigInput() { - if (this.raw.length < 20) + if (this.code.length < 2) return false; - if (this.raw[0] !== opcodes.OP_0) + if (this.getOp(0) !== opcodes.OP_0) return false; - if (this.raw[1] > opcodes.OP_PUSHDATA4) + if (this.getOp(1) > opcodes.OP_PUSHDATA4) return false; // We need to rule out scripthash @@ -2230,22 +2363,32 @@ Script.prototype.isMultisigInput = function isMultisigInput() { if (this.isScripthashInput()) return false; - if (this.code.length < 3) - return false; - for (let i = 1; i < this.code.length; i++) { - let op = this.code[i]; - - if (!op.data) - return false; - - if (!common.isSignature(op.data)) + const size = this.getLength(i); + if (size < 9 || size > 73) return false; } return true; }; +/** + * Get multisig signatures if present. + * @returns {Buffer[]|null} + */ + +Script.prototype.getMultisigInput = function getMultisigInput() { + if (!this.isMultisigInput()) + return null; + + const sigs = []; + + for (let i = 1; i < this.code.length; i++) + sigs.push(this.getData(i)); + + return sigs; +}; + /** * "Guess" whether the input script is pay-to-scripthash. * This method is not 100% reliable. @@ -2253,17 +2396,15 @@ Script.prototype.isMultisigInput = function isMultisigInput() { */ Script.prototype.isScripthashInput = function isScripthashInput() { - let op, redeem; - - if (this.raw.length < 2) + if (this.code.length < 2) return false; // Grab the raw redeem script. - op = this.code[this.code.length - 1]; + const raw = this.getData(-1); // Last data element should be an array // for the redeem script. - if (!op.data) + if (!raw) return false; // Testing for scripthash inputs requires @@ -2275,23 +2416,41 @@ Script.prototype.isScripthashInput = function isScripthashInput() { // key, and we ensure that it is at least // a script that does not use undefined // opcodes. - if (op.data.length === 0) + if (raw.length === 0) return false; - if (common.isSignatureEncoding(op.data)) + if (common.isSignatureEncoding(raw)) return false; - if (common.isKeyEncoding(op.data)) + if (common.isKeyEncoding(raw)) return false; - redeem = Script.fromRaw(op.data); + const redeem = Script.fromRaw(raw); if (!redeem.isCode()) return false; + if (redeem.isUnspendable()) + return false; + + if (!this.isPushOnly()) + return false; + return true; }; +/** + * Get P2SH redeem script if present. + * @returns {Buffer|null} + */ + +Script.prototype.getScripthashInput = function getScripthashInput() { + if (!this.isScripthashInput()) + return null; + + return this.getData(-1); +}; + /** * Get coinbase height. * @returns {Number} `-1` if not present. @@ -2308,49 +2467,28 @@ Script.prototype.getCoinbaseHeight = function getCoinbaseHeight() { */ Script.getCoinbaseHeight = function getCoinbaseHeight(raw) { - let data, height, op; - if (raw.length === 0) return -1; - // Small ints are allowed. - height = common.getSmall(raw[0]); + if (raw[0] >= opcodes.OP_1 && raw[0] <= opcodes.OP_16) + return raw[0] - 0x50; - if (height !== -1) - return height; - - // No more than 6 bytes (we can't - // handle 7 byte JS numbers and - // height 281 trillion is far away). if (raw[0] > 0x06) return -1; - // No bad pushes allowed. - if (raw.length < 1 + raw[0]) - return -1; - - data = raw.slice(1, 1 + raw[0]); - - // Deserialize the height. - try { - height = Script.num(data, true, 6); - } catch (e) { - return -1; - } + const op = Opcode.fromRaw(raw); + const num = op.toNum(); - // Reserialize the height. - op = Opcode.fromNumber(height); + if (!num) + return 1; - // Should have been OP_0-OP_16. - if (!op.data) + if (num.isNeg()) return -1; - // Ensure the miner serialized the - // number in the most minimal fashion. - if (!data.equals(op.data)) + if (!op.equals(Opcode.fromNum(num))) return -1; - return height.toNumber(); + return num.toDouble(); }; /** @@ -2360,7 +2498,7 @@ Script.getCoinbaseHeight = function getCoinbaseHeight(raw) { */ Script.prototype.test = function test(filter) { - for (let op of this.code) { + for (const op of this.code) { if (op.value === -1) break; @@ -2375,323 +2513,552 @@ Script.prototype.test = function test(filter) { }; /** - * Unshift an item onto the `code` array. - * @param {Number|String|BN|Buffer} data - * @returns {Number} Length. + * Test the script to see if it contains only push ops. + * Push ops are: OP_1NEGATE, OP_0-OP_16 and all PUSHDATAs. + * @returns {Boolean} */ -Script.prototype.unshift = function unshift(data) { - return this.code.unshift(Opcode.from(data)); -}; +Script.prototype.isPushOnly = function isPushOnly() { + for (const op of this.code) { + if (op.value === -1) + return false; -/** - * Push an item onto the `code` array. - * @param {Number|String|BN|Buffer} data - * @returns {Number} Length. - */ + if (op.value > opcodes.OP_16) + return false; + } -Script.prototype.push = function push(data) { - return this.code.push(Opcode.from(data)); + return true; }; /** - * Shift an item off of the `code` array. - * @returns {Buffer} + * Count the sigops in the script. + * @param {Boolean} accurate - Whether to enable accurate counting. This will + * take into account the `n` value for OP_CHECKMULTISIG(VERIFY). + * @returns {Number} sigop count */ -Script.prototype.shift = function shift() { - let op = this.code.shift(); +Script.prototype.getSigops = function getSigops(accurate) { + let total = 0; + let lastOp = -1; - if (!op) - return null; + for (const op of this.code) { + if (op.value === -1) + break; + + switch (op.value) { + case opcodes.OP_CHECKSIG: + case opcodes.OP_CHECKSIGVERIFY: + total += 1; + break; + case opcodes.OP_CHECKMULTISIG: + case opcodes.OP_CHECKMULTISIGVERIFY: + if (accurate && lastOp >= opcodes.OP_1 && lastOp <= opcodes.OP_16) + total += lastOp - 0x50; + else + total += consensus.MAX_MULTISIG_PUBKEYS; + break; + } + + lastOp = op.value; + } - return op.data || op.value; + return total; }; /** - * Pop an item off of the `code` array. - * @returns {Buffer} + * Count the sigops in the script, taking into account redeem scripts. + * @param {Script} input - Input script, needed for access to redeem script. + * @returns {Number} sigop count */ -Script.prototype.pop = function push(data) { - let op = this.code.pop(); +Script.prototype.getScripthashSigops = function getScripthashSigops(input) { + if (!this.isScripthash()) + return this.getSigops(true); - if (!op) - return null; + const redeem = input.getRedeem(); - return op.data || op.value; + if (!redeem) + return 0; + + return redeem.getSigops(true); }; /** - * Remove an item from the `code` array. - * @param {Number} index - * @returns {Buffer|Number} + * Count the sigops in a script, taking into account witness programs. + * @param {Script} input + * @param {Witness} witness + * @returns {Number} sigop count */ -Script.prototype.remove = function remove(i) { - let op = this.code.splice(i, 1)[0]; +Script.prototype.getWitnessSigops = function getWitnessSigops(input, witness) { + let program = this.getProgram(); - if (!op) - return null; + if (!program) { + if (this.isScripthash()) { + const redeem = input.getRedeem(); + if (redeem) + program = redeem.getProgram(); + } + } - return op.data || op.value; -}; + if (!program) + return 0; -/** - * Insert an item into the `code` array. - * @param {Number} index - * @param {Number|String|BN|Buffer} data - */ + if (program.version === 0) { + if (program.data.length === 20) + return 1; + + if (program.data.length === 32 && witness.items.length > 0) { + const redeem = witness.getRedeem(); + return redeem.getSigops(true); + } + } -Script.prototype.insert = function insert(i, data) { - assert(i <= this.code.length, 'Index out of bounds.'); - this.code.splice(i, 0, Opcode.from(data)); + return 0; }; -/** - * Get an item from the `code` array. - * @param {Number} index - * @returns {Buffer} +/* + * Mutation */ -Script.prototype.get = function get(i) { - let op = this.code[i]; +Script.prototype.get = function get(index) { + if (index < 0) + index += this.code.length; - if (!op) + if (index < 0 || index >= this.code.length) return null; - return op.data || op.value; + return this.code[index]; }; -/** - * Get a small integer from an opcode (OP_0-OP_16). - * @param {Number} index - * @returns {Number} - */ +Script.prototype.pop = function pop() { + const op = this.code.pop(); + return op || null; +}; -Script.prototype.getSmall = function getSmall(i) { - let op = this.code[i]; +Script.prototype.shift = function shift() { + const op = this.code.shift(); + return op || null; +}; - if (!op) - return -1; +Script.prototype.remove = function remove(index) { + if (index < 0) + index += this.code.length; - return common.getSmall(op.value); + if (index < 0 || index >= this.code.length) + return null; + + const items = this.code.splice(index, 1); + + if (items.length === 0) + return null; + + return items[0]; }; -/** - * Get a number from the `code` array (5-byte limit). - * @params {Number} index - * @returns {BN} - */ +Script.prototype.set = function set(index, op) { + if (index < 0) + index += this.code.length; -Script.prototype.getNumber = function getNumber(i) { - let small = this.getSmall(i); - let op = this.code[i]; + assert(Opcode.isOpcode(op)); + assert(index >= 0 && index <= this.code.length); - if (small !== -1) - return new BN(small); + this.code[index] = op; - if (!op || !op.data || op.data.length > 5) - return null; + return this; +}; + +Script.prototype.push = function push(op) { + assert(Opcode.isOpcode(op)); + this.code.push(op); + return this; +}; - return Script.num(op.data, false, 5); +Script.prototype.unshift = function unshift(op) { + assert(Opcode.isOpcode(op)); + this.code.unshift(op); + return this; }; -/** - * Get a string from the `code` array (utf8). - * @params {Number} index - * @returns {String} - */ +Script.prototype.insert = function insert(index, op) { + if (index < 0) + index += this.code.length; -Script.prototype.getString = function getString(i) { - let op = this.code[i]; + assert(Opcode.isOpcode(op)); + assert(index >= 0 && index <= this.code.length); - if (!op || !op.data) - return null; + this.code.splice(index, 0, op); - return op.data.toString('utf8'); + return this; }; -/** - * Clear the script code. +/* + * Op */ -Script.prototype.clear = function clear() { - this.code.length = 0; +Script.prototype.getOp = function getOp(index) { + const op = this.get(index); + return op ? op.value : -1; }; -/** - * Set an item in the `code` array. - * @param {Number} index - * @param {Buffer|Number|String|BN} data +Script.prototype.popOp = function popOp() { + const op = this.pop(); + return op ? op.value : -1; +}; + +Script.prototype.shiftOp = function shiftOp() { + const op = this.shift(); + return op ? op.value : -1; +}; + +Script.prototype.removeOp = function removeOp(index) { + const op = this.remove(index); + return op ? op.value : -1; +}; + +Script.prototype.setOp = function setOp(index, value) { + return this.set(index, Opcode.fromOp(value)); +}; + +Script.prototype.pushOp = function pushOp(value) { + return this.push(Opcode.fromOp(value)); +}; + +Script.prototype.unshiftOp = function unshiftOp(value) { + return this.unshift(Opcode.fromOp(value)); +}; + +Script.prototype.insertOp = function insertOp(index, value) { + return this.insert(index, Opcode.fromOp(value)); +}; + +/* + * Data */ -Script.prototype.set = function set(i, data) { - assert(i <= this.code.length, 'Index out of bounds.'); - this.code[i] = Opcode.from(data); +Script.prototype.getData = function getData(index) { + const op = this.get(index); + return op ? op.data : null; }; -/** - * Test whether the data element is a public key. Note that - * this does not verify the format of the key, only the length. - * @param {Buffer?} key - * @returns {Boolean} +Script.prototype.popData = function popData() { + const op = this.pop(); + return op ? op.data : null; +}; + +Script.prototype.shiftData = function shiftData() { + const op = this.shift(); + return op ? op.data : null; +}; + +Script.prototype.removeData = function removeData(index) { + const op = this.remove(index); + return op ? op.data : null; +}; + +Script.prototype.setData = function setData(index, data) { + return this.set(index, Opcode.fromData(data)); +}; + +Script.prototype.pushData = function pushData(data) { + return this.push(Opcode.fromData(data)); +}; + +Script.prototype.unshiftData = function unshiftData(data) { + return this.unshift(Opcode.fromData(data)); +}; + +Script.prototype.insertData = function insertData(index, data) { + return this.insert(index, Opcode.fromData(data)); +}; + +/* + * Length */ -Script.isKey = function isKey(key) { - return common.isKey(key); +Script.prototype.getLength = function getLength(index) { + const op = this.get(index); + return op ? op.toLength() : -1; }; -/** - * Test whether the data element is a signature. Note that - * this does not verify the format of the signature, only the length. - * @param {Buffer?} sig - * @returns {Boolean} +/* + * Push */ -Script.isSignature = function isSignature(sig) { - return common.isSignature(sig); +Script.prototype.getPush = function getPush(index) { + const op = this.get(index); + return op ? op.toPush() : null; }; -/** - * Test the script to see if it contains only push ops. - * Push ops are: OP_1NEGATE, OP_0-OP_16 and all PUSHDATAs. - * @returns {Boolean} +Script.prototype.popPush = function popPush() { + const op = this.pop(); + return op ? op.toPush() : null; +}; + +Script.prototype.shiftPush = function shiftPush() { + const op = this.shift(); + return op ? op.toPush() : null; +}; + +Script.prototype.removePush = function removePush(index) { + const op = this.remove(index); + return op ? op.toPush() : null; +}; + +Script.prototype.setPush = function setPush(index, data) { + return this.set(index, Opcode.fromPush(data)); +}; + +Script.prototype.pushPush = function pushPush(data) { + return this.push(Opcode.fromPush(data)); +}; + +Script.prototype.unshiftPush = function unshiftPush(data) { + return this.unshift(Opcode.fromPush(data)); +}; + +Script.prototype.insertPush = function insertPush(index, data) { + return this.insert(index, Opcode.fromPush(data)); +}; + +/* + * String */ -Script.prototype.isPushOnly = function isPushOnly() { - for (let op of this.code) { - if (op.data) - continue; +Script.prototype.getString = function getString(index, enc) { + const op = this.get(index); + return op ? op.toString(enc) : null; +}; - if (op.value === -1) - return false; +Script.prototype.popString = function popString(enc) { + const op = this.pop(); + return op ? op.toString(enc) : null; +}; - if (op.value > opcodes.OP_16) - return false; - } +Script.prototype.shiftString = function shiftString(enc) { + const op = this.shift(); + return op ? op.toString(enc) : null; +}; - return true; +Script.prototype.removeString = function removeString(index, enc) { + const op = this.remove(index); + return op ? op.toString(enc) : null; }; -/** - * Count the sigops in the script. - * @param {Boolean} accurate - Whether to enable accurate counting. This will - * take into account the `n` value for OP_CHECKMULTISIG(VERIFY). - * @returns {Number} sigop count +Script.prototype.setString = function setString(index, str, enc) { + return this.set(index, Opcode.fromString(str, enc)); +}; + +Script.prototype.pushString = function pushString(str, enc) { + return this.push(Opcode.fromString(str, enc)); +}; + +Script.prototype.unshiftString = function unshiftString(str, enc) { + return this.unshift(Opcode.fromString(str, enc)); +}; + +Script.prototype.insertString = function insertString(index, str, enc) { + return this.insert(index, Opcode.fromString(str, enc)); +}; + +/* + * Small */ -Script.prototype.getSigops = function getSigops(accurate) { - let total = 0; - let lastOp = -1; +Script.prototype.getSmall = function getSmall(index) { + const op = this.get(index); + return op ? op.toSmall() : -1; +}; - for (let op of this.code) { - if (op.data) - continue; +Script.prototype.popSmall = function popSmall() { + const op = this.pop(); + return op ? op.toSmall() : -1; +}; - if (op.value === -1) - break; +Script.prototype.shiftSmall = function shiftSmall() { + const op = this.shift(); + return op ? op.toSmall() : -1; +}; - switch (op.value) { - case opcodes.OP_CHECKSIG: - case opcodes.OP_CHECKSIGVERIFY: - total++; - break; - case opcodes.OP_CHECKMULTISIG: - case opcodes.OP_CHECKMULTISIGVERIFY: - if (accurate && lastOp >= opcodes.OP_1 && lastOp <= opcodes.OP_16) - total += lastOp - 0x50; - else - total += consensus.MAX_MULTISIG_PUBKEYS; - break; - } +Script.prototype.removeSmall = function removeSmall(index) { + const op = this.remove(index); + return op ? op.toSmall() : -1; +}; - lastOp = op.value; - } +Script.prototype.setSmall = function setSmall(index, num) { + return this.set(index, Opcode.fromSmall(num)); +}; - return total; +Script.prototype.pushSmall = function pushSmall(num) { + return this.push(Opcode.fromSmall(num)); }; -/** - * Count the sigops in the script, taking into account redeem scripts. - * @param {Script} input - Input script, needed for access to redeem script. - * @returns {Number} sigop count +Script.prototype.unshiftSmall = function unshiftSmall(num) { + return this.unshift(Opcode.fromSmall(num)); +}; + +Script.prototype.insertSmall = function insertSmall(index, num) { + return this.insert(index, Opcode.fromSmall(num)); +}; + +/* + * Num */ -Script.prototype.getScripthashSigops = function getScripthashSigops(input) { - let op, redeem; +Script.prototype.getNum = function getNum(index, minimal, limit) { + const op = this.get(index); + return op ? op.toNum(minimal, limit) : null; +}; - if (!this.isScripthash()) - return this.getSigops(true); +Script.prototype.popNum = function popNum(minimal, limit) { + const op = this.pop(); + return op ? op.toNum(minimal, limit) : null; +}; - if (input.code.length === 0) - return 0; +Script.prototype.shiftNum = function shiftNum(minimal, limit) { + const op = this.shift(); + return op ? op.toNum(minimal, limit) : null; +}; - for (op of input.code) { - if (op.data) - continue; +Script.prototype.removeNum = function removeNum(index, minimal, limit) { + const op = this.remove(index); + return op ? op.toNum(minimal, limit) : null; +}; - if (op.value === -1) - return 0; +Script.prototype.setNum = function setNum(index, num) { + return this.set(index, Opcode.fromNum(num)); +}; - if (op.value > opcodes.OP_16) - return 0; - } +Script.prototype.pushNum = function pushNum(num) { + return this.push(Opcode.fromNum(num)); +}; - if (!op.data) - return 0; +Script.prototype.unshiftNum = function unshiftNum(num) { + return this.unshift(Opcode.fromNum(num)); +}; + +Script.prototype.insertNum = function insertNum(index, num) { + return this.insert(index, Opcode.fromNum(num)); +}; - redeem = new Script(op.data); +/* + * Int + */ - return redeem.getSigops(true); +Script.prototype.getInt = function getInt(index, minimal, limit) { + const op = this.get(index); + return op ? op.toInt(minimal, limit) : -1; }; -/** - * Count the sigops for a program. - * @param {Program} program - * @param {Witness} witness - * @returns {Number} sigop count +Script.prototype.popInt = function popInt(minimal, limit) { + const op = this.pop(); + return op ? op.toInt(minimal, limit) : -1; +}; + +Script.prototype.shiftInt = function shiftInt(minimal, limit) { + const op = this.shift(); + return op ? op.toInt(minimal, limit) : -1; +}; + +Script.prototype.removeInt = function removeInt(index, minimal, limit) { + const op = this.remove(index); + return op ? op.toInt(minimal, limit) : -1; +}; + +Script.prototype.setInt = function setInt(index, num) { + return this.set(index, Opcode.fromInt(num)); +}; + +Script.prototype.pushInt = function pushInt(num) { + return this.push(Opcode.fromInt(num)); +}; + +Script.prototype.unshiftInt = function unshiftInt(num) { + return this.unshift(Opcode.fromInt(num)); +}; + +Script.prototype.insertInt = function insertInt(index, num) { + return this.insert(index, Opcode.fromInt(num)); +}; + +/* + * Bool */ -Script.witnessSigops = function witnessSigops(program, witness) { - if (program.version === 0) { - if (program.data.length === 20) - return 1; +Script.prototype.getBool = function getBool(index) { + const op = this.get(index); + return op ? op.toBool() : false; +}; - if (program.data.length === 32 && witness.items.length > 0) { - let redeem = witness.getRedeem(); - return redeem.getSigops(true); - } - } +Script.prototype.popBool = function popBool() { + const op = this.pop(); + return op ? op.toBool() : false; +}; - return 0; +Script.prototype.shiftBool = function shiftBool() { + const op = this.shift(); + return op ? op.toBool() : false; }; -/** - * Count the sigops in a script, taking into account witness programs. - * @param {Script} input - * @param {Witness} witness - * @returns {Number} sigop count +Script.prototype.removeBool = function removeBool(index) { + const op = this.remove(index); + return op ? op.toBool() : false; +}; + +Script.prototype.setBool = function setBool(index, value) { + return this.set(index, Opcode.fromBool(value)); +}; + +Script.prototype.pushBool = function pushBool(value) { + return this.push(Opcode.fromBool(value)); +}; + +Script.prototype.unshiftBool = function unshiftBool(value) { + return this.unshift(Opcode.fromBool(value)); +}; + +Script.prototype.insertBool = function insertBool(index, value) { + return this.insert(index, Opcode.fromBool(value)); +}; + +/* + * Symbol */ -Script.prototype.getWitnessSigops = function getWitnessSigops(input, witness) { - if (this.isProgram()) - return Script.witnessSigops(this.toProgram(), witness); - - // This is a unique situation in terms of consensus - // rules. We can just grab the redeem script without - // "parsing" (i.e. checking for pushdata parse errors) - // the script. This is because isPushOnly is called - // which checks for parse errors and will return - // false if one is found. Even the bitcoind code - // does not check the return value of GetOp. - if (this.isScripthash() && input.isPushOnly()) { - let redeem = input.getRedeem(); - if (redeem && redeem.isProgram()) - return Script.witnessSigops(redeem.toProgram(), witness); - } +Script.prototype.getSym = function getSym(index) { + const op = this.get(index); + return op ? op.toSymbol() : null; +}; - return 0; +Script.prototype.popSym = function popSym() { + const op = this.pop(); + return op ? op.toSymbol() : null; +}; + +Script.prototype.shiftSym = function shiftSym() { + const op = this.shift(); + return op ? op.toSymbol() : null; +}; + +Script.prototype.removeSym = function removeSym(index) { + const op = this.remove(index); + return op ? op.toSymbol() : null; +}; + +Script.prototype.setSym = function setSym(index, symbol) { + return this.set(index, Opcode.fromSymbol(symbol)); +}; + +Script.prototype.pushSym = function pushSym(symbol) { + return this.push(Opcode.fromSymbol(symbol)); +}; + +Script.prototype.unshiftSym = function unshiftSym(symbol) { + return this.unshift(Opcode.fromSymbol(symbol)); +}; + +Script.prototype.insertSym = function insertSym(index, symbol) { + return this.insert(index, Opcode.fromSymbol(symbol)); }; /** @@ -2702,8 +3069,6 @@ Script.prototype.getWitnessSigops = function getWitnessSigops(input, witness) { */ Script.prototype.fromString = function fromString(code) { - let bw; - assert(typeof code === 'string'); code = code.trim(); @@ -2711,11 +3076,11 @@ Script.prototype.fromString = function fromString(code) { if (code.length === 0) return this; - code = code.split(/\s+/); - bw = new BufferWriter(); + const items = code.split(/\s+/); + const bw = new BufferWriter(); - for (let op of code) { - let symbol = op; + for (const item of items) { + let symbol = item; if (!util.isUpperCase(symbol)) symbol = symbol.toUpperCase(); @@ -2723,29 +3088,37 @@ Script.prototype.fromString = function fromString(code) { if (!util.startsWith(symbol, 'OP_')) symbol = `OP_${symbol}`; - if (opcodes[symbol] == null) { - if (op[0] === '\'') { - assert(op[op.length - 1] === '\'', 'Unknown opcode.'); - op = op.slice(1, -1); - op = Opcode.fromString(op); + const value = opcodes[symbol]; + + if (value == null) { + if (item[0] === '\'') { + assert(item[item.length - 1] === '\'', 'Invalid string.'); + const str = item.slice(1, -1); + const op = Opcode.fromString(str); bw.writeBytes(op.toRaw()); continue; } - if (/^-?\d+$/.test(op)) { - op = new BN(op, 10); - op = Opcode.fromNumber(op); + + if (/^-?\d+$/.test(item)) { + const num = ScriptNum.fromString(item, 10); + const op = Opcode.fromNum(num); bw.writeBytes(op.toRaw()); continue; } - assert(op.indexOf('0x') === 0, 'Unknown opcode.'); - op = op.substring(2); - assert(util.isHex(op), 'Unknown opcode.'); - op = Buffer.from(op, 'hex'); - bw.writeBytes(op); + + assert(item.indexOf('0x') === 0, 'Unknown opcode.'); + + const hex = item.substring(2); + const data = Buffer.from(hex, 'hex'); + + assert(data.length === hex.length / 2, 'Invalid hex string.'); + + bw.writeBytes(data); + continue; } - bw.writeU8(opcodes[symbol]); + bw.writeU8(value); } return this.fromRaw(bw.render()); @@ -2769,16 +3142,13 @@ Script.fromString = function fromString(code) { * @param {Witness} witness * @param {Script} output * @param {TX} tx - * @param {Number} i + * @param {Number} index * @param {Amount} value * @param {VerifyFlags} flags - * @returns {Boolean} * @throws {ScriptError} */ -Script.verify = function verify(input, witness, output, tx, i, value, flags) { - let stack, copy, raw, redeem, hadWitness; - +Script.verify = function verify(input, witness, output, tx, index, value, flags) { if (flags == null) flags = Script.flags.STANDARD_VERIFY_FLAGS; @@ -2788,22 +3158,25 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) { } // Setup a stack. - stack = new Stack(); + let stack = new Stack(); // Execute the input script - input.execute(stack, flags, tx, i, value, 0); + input.execute(stack, flags, tx, index, value, 0); // Copy the stack for P2SH + let copy; if (flags & Script.flags.VERIFY_P2SH) copy = stack.clone(); // Execute the previous output script. - output.execute(stack, flags, tx, i, value, 0); + output.execute(stack, flags, tx, index, value, 0); // Verify the stack values. - if (stack.length === 0 || !Script.bool(stack.top(-1))) + if (stack.length === 0 || !stack.getBool(-1)) throw new ScriptError('EVAL_FALSE'); + let hadWitness = false; + if ((flags & Script.flags.VERIFY_WITNESS) && output.isProgram()) { hadWitness = true; @@ -2812,7 +3185,7 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) { throw new ScriptError('WITNESS_MALLEATED'); // Verify the program in the output script. - Script.verifyProgram(witness, output, flags, tx, i, value); + Script.verifyProgram(witness, output, flags, tx, index, value); // Force a cleanstack stack.length = 1; @@ -2832,14 +3205,14 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) { throw new ScriptError('EVAL_FALSE'); // Grab the real redeem script - raw = stack.pop(); - redeem = new Script(raw); + const raw = stack.pop(); + const redeem = Script.fromRaw(raw); // Execute the redeem script. - redeem.execute(stack, flags, tx, i, value, 0); + redeem.execute(stack, flags, tx, index, value, 0); // Verify the the stack values. - if (stack.length === 0 || !Script.bool(stack.top(-1))) + if (stack.length === 0 || !stack.getBool(-1)) throw new ScriptError('EVAL_FALSE'); if ((flags & Script.flags.VERIFY_WITNESS) && redeem.isProgram()) { @@ -2850,7 +3223,7 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) { throw new ScriptError('WITNESS_MALLEATED_P2SH'); // Verify the program in the redeem script. - Script.verifyProgram(witness, redeem, flags, tx, i, value); + Script.verifyProgram(witness, redeem, flags, tx, index, value); // Force a cleanstack. stack.length = 1; @@ -2870,8 +3243,6 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) { if (!hadWitness && witness.items.length > 0) throw new ScriptError('WITNESS_UNEXPECTED'); } - - return true; }; /** @@ -2882,31 +3253,31 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) { * @param {Script} output * @param {VerifyFlags} flags * @param {TX} tx - * @param {Number} i + * @param {Number} index * @param {Amount} value - * @returns {Boolean} * @throws {ScriptError} */ -Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, value) { - let program = output.toProgram(); - let stack = witness.toStack(); - let j, witnessScript, redeem; +Script.verifyProgram = function verifyProgram(witness, output, flags, tx, index, value) { + const program = output.getProgram(); assert(program, 'verifyProgram called on non-witness-program.'); assert((flags & Script.flags.VERIFY_WITNESS) !== 0); + const stack = witness.toStack(); + let redeem; + if (program.version === 0) { if (program.data.length === 32) { if (stack.length === 0) throw new ScriptError('WITNESS_PROGRAM_WITNESS_EMPTY'); - witnessScript = stack.pop(); + const witnessScript = stack.pop(); if (!digest.sha256(witnessScript).equals(program.data)) throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); - redeem = new Script(witnessScript); + redeem = Script.fromRaw(witnessScript); } else if (program.data.length === 20) { if (stack.length !== 2) throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); @@ -2917,7 +3288,8 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, val throw new ScriptError('WITNESS_PROGRAM_WRONG_LENGTH'); } } else if ((flags & Script.flags.VERIFY_MAST) && program.version === 1) { - return Script.verifyMast(program, stack, output, flags, tx, i); + Script.verifyMast(program, stack, output, flags, tx, index); + return; } else { // Anyone can spend (we can return true here // if we want to always relay these transactions). @@ -2928,23 +3300,21 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, val // due to VERIFY_CLEANSTACK. if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) throw new ScriptError('DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM'); - return true; + return; } // Witnesses still have push limits. - for (j = 0; j < stack.length; j++) { + for (let j = 0; j < stack.length; j++) { if (stack.get(j).length > consensus.MAX_SCRIPT_PUSH) throw new ScriptError('PUSH_SIZE'); } // Verify the redeem script. - redeem.execute(stack, flags, tx, i, value, 1); + redeem.execute(stack, flags, tx, index, value, 1); // Verify the stack values. - if (stack.length !== 1 || !Script.bool(stack.top(-1))) + if (stack.length !== 1 || !stack.getBool(-1)) throw new ScriptError('EVAL_FALSE'); - - return true; }; /** @@ -2954,43 +3324,37 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, val * @param {Script} output * @param {VerifyFlags} flags * @param {TX} tx - * @param {Number} i + * @param {Number} index * @param {Amount} value - * @returns {Boolean} * @throws {ScriptError} */ -Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, value) { - let mastRoot = new BufferWriter(); - let scriptRoot = new BufferWriter(); - let scripts = new BufferWriter(); - let version = 0; - let pathdata, depth, path, posdata, pos; - let metadata, subscripts, ops, script; - let j; - +Script.verifyMast = function verifyMast(program, stack, output, flags, tx, index, value) { assert(program.version === 1); assert((flags & Script.flags.VERIFY_MAST) !== 0); if (stack.length < 4) throw new ScriptError('INVALID_MAST_STACK'); - metadata = stack.top(-1); + const metadata = stack.get(-1); if (metadata.length < 1 || metadata.length > 5) throw new ScriptError('INVALID_MAST_STACK'); - subscripts = metadata[0]; + const subscripts = metadata[0]; if (subscripts === 0 || stack.length < subscripts + 3) throw new ScriptError('INVALID_MAST_STACK'); - ops = subscripts; + let ops = subscripts; + let scriptRoot = new BufferWriter(); scriptRoot.writeU8(subscripts); if (metadata[metadata.length - 1] === 0x00) throw new ScriptError('INVALID_MAST_STACK'); - for (j = 1; j < metadata.length; j++) - version |= metadata[i] << 8 * (j - 1); + let version = 0; + + for (let j = 1; j < metadata.length; j++) + version |= metadata[j] << 8 * (j - 1); if (version < 0) version += 0x100000000; @@ -3000,14 +3364,15 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va throw new ScriptError('DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM'); } + let mastRoot = new BufferWriter(); mastRoot.writeU32(version); - pathdata = stack.top(-2); + const pathdata = stack.get(-2); if (pathdata.length & 0x1f) throw new ScriptError('INVALID_MAST_STACK'); - depth = pathdata.length >>> 5; + const depth = pathdata.length >>> 5; if (depth > 32) throw new ScriptError('INVALID_MAST_STACK'); @@ -3018,23 +3383,23 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va throw new ScriptError('OP_COUNT'); } - path = []; + const path = []; - for (j = 0; j < depth; j++) + for (let j = 0; j < depth; j++) path.push(pathdata.slice(j * 32, j * 32 + 32)); - posdata = stack.top(-3); + const posdata = stack.get(-3); if (posdata.length > 4) throw new ScriptError('INVALID_MAST_STACK'); - pos = 0; + let pos = 0; if (posdata.length > 0) { if (posdata[posdata.length - 1] === 0x00) throw new ScriptError('INVALID_MAST_STACK'); - for (j = 0; j < posdata.length; j++) - pos |= posdata[i] << 8 * j; + for (let j = 0; j < posdata.length; j++) + pos |= posdata[j] << 8 * j; if (pos < 0) pos += 0x100000000; @@ -3045,12 +3410,13 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va throw new ScriptError('INVALID_MAST_STACK'); } + let scripts = new BufferWriter(); scripts.writeBytes(output.raw); - for (j = 0; j < subscripts; j++) { - script = stack.top(-(4 + j)); + for (let j = 0; j < subscripts; j++) { + const script = stack.get(-(4 + j)); if (version === 0) { - if ((scripts.written + script.length) > consensus.MAX_SCRIPT_SIZE) + if ((scripts.offset + script.length) > consensus.MAX_SCRIPT_SIZE) throw new ScriptError('SCRIPT_SIZE'); } scriptRoot.writeBytes(digest.hash256(script)); @@ -3069,19 +3435,18 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va if (version === 0) { stack.length -= 3 + subscripts; - for (j = 0; j < stack.length; j++) { + for (let j = 0; j < stack.length; j++) { if (stack.get(j).length > consensus.MAX_SCRIPT_PUSH) throw new ScriptError('PUSH_SIZE'); } - output = new Script(scripts.render()); - output.execute(stack, flags, tx, i, value, 1); + scripts = scripts.render(); + output = Script.fromRaw(scripts); + output.execute(stack, flags, tx, index, value, 1); if (stack.length !== 0) throw new ScriptError('EVAL_FALSE'); } - - return true; }; /** @@ -3101,7 +3466,7 @@ Script.prototype.fromReader = function fromReader(br) { */ Script.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); + const br = new BufferReader(data, true); this.raw = data; @@ -3142,9 +3507,7 @@ Script.fromRaw = function fromRaw(data, enc) { */ Script.isScript = function isScript(obj) { - return obj - && Buffer.isBuffer(obj.raw) - && typeof obj.getSubscript === 'function'; + return obj instanceof Script; }; /* diff --git a/lib/script/scripterror.js b/lib/script/scripterror.js new file mode 100644 index 000000000..d910c5241 --- /dev/null +++ b/lib/script/scripterror.js @@ -0,0 +1,50 @@ +/*! + * scripterror.js - script error for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * An error thrown from the scripting system, + * potentially pertaining to Script execution. + * @alias module:script.ScriptError + * @constructor + * @extends Error + * @param {String} code - Error code. + * @param {Opcode} op - Opcode. + * @param {Number?} ip - Instruction pointer. + * @property {String} message - Error message. + * @property {String} code - Original code passed in. + * @property {Number} op - Opcode. + * @property {Number} ip - Instruction pointer. + */ + +function ScriptError(code, op, ip) { + if (!(this instanceof ScriptError)) + return new ScriptError(code, op, ip); + + Error.call(this); + + this.type = 'ScriptError'; + this.code = code; + this.message = code; + this.op = -1; + this.ip = -1; + + if (typeof op === 'string') { + this.message = op; + } else if (op) { + this.message = `${code} (op=${op.toSymbol()}, ip=${ip})`; + this.op = op.value; + this.ip = ip; + } + + if (Error.captureStackTrace) + Error.captureStackTrace(this, ScriptError); +}; + +Object.setPrototypeOf(ScriptError.prototype, Error.prototype); + +module.exports = ScriptError; diff --git a/lib/script/scriptnum.js b/lib/script/scriptnum.js index f4c8278e9..bd2cd0d7b 100644 --- a/lib/script/scriptnum.js +++ b/lib/script/scriptnum.js @@ -1,386 +1,255 @@ /*! - * scriptnum.js - script number for bcoin - * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * scriptnum.js - script number object for bcoin. + * Copyright (c) 2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; const assert = require('assert'); -const ScriptError = require('./common').ScriptError; +const {I64} = require('../utils/int64'); +const ScriptError = require('./scripterror'); + +/* + * Constants + */ + const EMPTY_ARRAY = Buffer.alloc(0); /** - * ScriptNum + * Script Number + * @see https://github.com/chjj/n64 * @alias module:script.ScriptNum * @constructor - * @ignore - * @param {Number} value + * @param {(Number|String|Buffer|Object)?} num + * @param {(String|Number)?} base + * @property {Number} hi + * @property {Number} lo + * @property {Number} sign */ -function ScriptNum(value) { +function ScriptNum(num, base) { if (!(this instanceof ScriptNum)) - return new ScriptNum(value); - - assert(!value || value <= 0xffffffffffff, 'Number exceeds 2^48-1.'); + return new ScriptNum(num, base); - this.value = value || 0; + I64.call(this, num, base); } -ScriptNum.prototype.clone = function clone() { - return new ScriptNum(this.value); -}; - -ScriptNum.prototype.add = function add(num) { - return this.clone().iadd(num); -}; - -ScriptNum.prototype.sub = function sub(num) { - return this.clone().isub(num); -}; - -ScriptNum.prototype.mul = function mul(num) { - return this.clone().imul(num); -}; - -ScriptNum.prototype.div = function div(num) { - return this.clone().idiv(num); -}; - -ScriptNum.prototype.iadd = function iadd(num) { - return this.iaddn(num.value); -}; - -ScriptNum.prototype.isub = function isub(num) { - return this.isubn(num.value); -}; - -ScriptNum.prototype.imul = function imul(num) { - return this.imuln(num.value); -}; - -ScriptNum.prototype.idiv = function idiv(num) { - return this.idivn(num.value); -}; - -ScriptNum.prototype.addn = function addn(value) { - return this.clone().iaddn(value); -}; - -ScriptNum.prototype.subn = function subn(value) { - return this.clone().isubn(value); -}; - -ScriptNum.prototype.muln = function muln(value) { - return this.clone().imuln(value); -}; - -ScriptNum.prototype.divn = function divn(value) { - return this.clone().idivn(value); -}; - -ScriptNum.prototype.ushln = function ushln(value) { - return this.clone().iushln(value); -}; - -ScriptNum.prototype.ushrn = function ushrn(value) { - return this.clone().iushrn(value); -}; - -ScriptNum.prototype.iaddn = function addn(value) { - this.value += value; - return this; -}; - -ScriptNum.prototype.isubn = function subn(value) { - this.value -= value; - return this; -}; - -ScriptNum.prototype.imuln = function muln(value) { - this.value *= value; - return this; -}; - -ScriptNum.prototype.idivn = function divn(value) { - this.value = Math.floor(this.value / value); - return this; -}; - -ScriptNum.prototype.iushln = function iushln(value) { - this.value *= Math.pow(2, value); - return this; -}; - -ScriptNum.prototype.iushrn = function iushrn(value) { - this.value = Math.floor(this.value / Math.pow(2, value)); - return this; -}; - -ScriptNum.prototype.cmp = function cmp(num) { - return this.cmpn(num.value); -}; - -ScriptNum.prototype.cmpn = function cmpn(value) { - if (this.value === value) - return 0; - return this.value < value ? -1 : 1; -}; +Object.setPrototypeOf(ScriptNum, I64); +Object.setPrototypeOf(ScriptNum.prototype, I64.prototype); -ScriptNum.prototype.neg = function neg() { - return this.clone().ineg(); -}; - -ScriptNum.prototype.ineg = function ineg() { - this.value = -this.value; - return this; -}; - -ScriptNum.prototype.toNumber = function toNumber() { - return this.value; -}; - -ScriptNum.prototype.toString = function toString(base) { - if (!base) - base = 10; +/** + * Cast to int32. + * @returns {Number} + */ - if (base === 10 || base === 'dec') - return this.value.toString(10); +ScriptNum.prototype.getInt = function getInt() { + if (this.lt(I64.INT32_MIN)) + return I64.LONG_MIN; - if (base === 16 || base === 'hex') { - let str = this.value.toString(16); - if (str.length % 2 !== 0) - str = '0' + str; - return str; - } + if (this.gt(I64.INT32_MAX)) + return I64.LONG_MAX; - assert(false, `Base ${base} not supported.`); + return this.toInt(); }; -ScriptNum.prototype.toJSON = function toJSON() { - return this.toString(16); -}; +/** + * Serialize script number. + * @returns {Buffer} + */ -ScriptNum.prototype.fromString = function fromString(str, base) { - let nonzero = 0; - let negative = false; +ScriptNum.prototype.toRaw = function toRaw() { + let num = this; - if (!base) - base = 10; + // Zeroes are always empty arrays. + if (num.isZero()) + return EMPTY_ARRAY; - if (str[0] === '-') { - assert(str.length > 1, 'Non-numeric string passed.'); - str = str.substring(1); - negative = true; - } else { - assert(str.length > 0, 'Non-numeric string passed.'); + // Need to append sign bit. + let neg = false; + if (num.isNeg()) { + num = num.neg(); + neg = true; } - this.value = 0; - - if (base === 10 || base === 'dec') { - for (let i = 0; i < str.length; i++) { - let ch = str[i]; - - if (nonzero === 0 && ch === '0') - continue; - - if (!(ch >= '0' && ch <= '9')) - throw new Error('Parse error.'); - - ch = ch.charCodeAt(0) - 48; + // Calculate size. + const size = num.byteLength(); - nonzero++; - assert(nonzero <= 15, 'Number exceeds 2^48-1.'); + let offset = 0; - this.value *= 10; - this.value += ch; - } + if (num.testn((size * 8) - 1)) + offset = 1; - if (negative) - this.value = -this.value; + // Write number. + const data = Buffer.allocUnsafe(size + offset); - return this; + switch (size) { + case 8: + data[7] = (num.hi >>> 24) & 0xff; + case 7: + data[6] = (num.hi >> 16) & 0xff; + case 6: + data[5] = (num.hi >> 8) & 0xff; + case 5: + data[4] = num.hi & 0xff; + case 4: + data[3] = (num.lo >>> 24) & 0xff; + case 3: + data[2] = (num.lo >> 16) & 0xff; + case 2: + data[1] = (num.lo >> 8) & 0xff; + case 1: + data[0] = num.lo & 0xff; } - if (base === 16 || base === 'hex') { - for (let i = 0; i < str.length; i++) { - let ch = str[i]; - - if (nonzero === 0 && ch === '0') - continue; - - if (ch >= '0' && ch <= '9') { - ch = ch.charCodeAt(0); - ch -= 48; - } else if (ch >= 'a' && ch <= 'f') { - ch = ch.charCodeAt(0); - ch -= 87; - } else if (ch >= 'A' && ch <= 'F') { - ch = ch.charCodeAt(0); - ch -= 55; - } else { - throw new Error('Parse error.'); - } - - nonzero++; - assert(nonzero <= 12, 'Number exceeds 2^48-1.'); - - this.value *= 16; - this.value += ch; - } - - if (negative) - this.value = -this.value; - - return this; + // Append sign bit. + if (data[size - 1] & 0x80) { + assert(offset === 1); + assert(data.length === size + offset); + data[size] = neg ? 0x80 : 0; + } else if (neg) { + assert(offset === 0); + assert(data.length === size); + data[size - 1] |= 0x80; + } else { + assert(offset === 0); + assert(data.length === size); } - assert(false, `Base ${base} not supported.`); -}; - -ScriptNum.fromString = function fromString(str, base) { - return new ScriptNum(0).fromString(str, base); + return data; }; -ScriptNum.prototype.fromRaw = function fromRaw(data, minimal, limit) { - if (minimal == null) - minimal = true; - - if (limit == null) - limit = 4; - - // We can't handle more than 6 bytes. - assert(limit <= 6, 'Number exceeds 48 bits.'); +/** + * Instantiate script number from serialized data. + * @private + * @param {Buffer} data + * @returns {ScriptNum} + */ - // Max size is 4 bytes by default, 6 bytes max. - if (data.length > limit) - throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.'); +ScriptNum.prototype.fromRaw = function fromRaw(data) { + assert(Buffer.isBuffer(data)); // Empty arrays are always zero. - if (data.length === 0) { - this.value = 0; + if (data.length === 0) return this; - } - - // Ensure minimal serialization. - if (minimal) { - if ((data[data.length - 1] & 0x7f) === 0) { - if (data.length === 1 || !(data[data.length - 2] & 0x80)) { - throw new ScriptError( - 'UNKNOWN_ERROR', - 'Non-minimally encoded Script number.'); - } - } - } - this.value = 0; - - // Read number (6 bytes max). + // Read number (9 bytes max). switch (data.length) { + case 8: + this.hi |= data[7] << 24; + case 7: + this.hi |= data[6] << 16; case 6: - this.value += data[5] * 0x10000000000; + this.hi |= data[5] << 8; case 5: - this.value += data[4] * 0x100000000; + this.hi |= data[4]; case 4: - this.value += data[3] * 0x1000000; + this.lo |= data[3] << 24; case 3: - this.value += data[2] * 0x10000; + this.lo |= data[2] << 16; case 2: - this.value += data[1] * 0x100; + this.lo |= data[1] << 8; case 1: - this.value += data[0]; + this.lo |= data[0]; + break; + default: + for (let i = 0; i < data.length; i++) + this.orb(i, data[i]); + break; } // Remove high bit and flip sign. if (data[data.length - 1] & 0x80) { - switch (data.length) { - case 1: - case 2: - case 3: - case 4: - this.value &= ~(0x80 << (8 * (data.length - 1))); - break; - case 5: - this.value -= 0x8000000000; - break; - case 6: - this.value -= 0x800000000000; - break; - } - this.value = -this.value; + this.setn((data.length * 8) - 1, 0); + this.ineg(); } return this; }; -ScriptNum.fromRaw = function fromRaw(data, minimal, limit) { - return new ScriptNum(0).fromRaw(data, minimal, limit); -}; +/** + * Serialize script number. + * @returns {Buffer} + */ -ScriptNum.prototype.toRaw = function toRaw() { - let value = this.value; - let negative = false; - let data, offset, size; +ScriptNum.prototype.encode = function encode() { + return this.toRaw(); +}; - // Zeroes are always empty arrays. - if (value === 0) - return EMPTY_ARRAY; +/** + * Decode and verify script number. + * @private + * @param {Buffer} data + * @param {Boolean?} minimal - Require minimal encoding. + * @param {Number?} limit - Size limit. + * @returns {ScriptNum} + */ - // Need to append sign bit. - if (value < 0) { - negative = true; - value = -value; - } +ScriptNum.prototype.decode = function decode(data, minimal, limit) { + assert(Buffer.isBuffer(data)); - // Gauge buffer size. - if (value <= 0xff) { - offset = (value & 0x80) ? 1 : 0; - size = 1; - } else if (value <= 0xffff) { - offset = (value & 0x8000) ? 1 : 0; - size = 2; - } else if (value <= 0xffffff) { - offset = (value & 0x800000) ? 1 : 0; - size = 3; - } else if (value <= 0xffffffff) { - offset = (value & 0x80000000) ? 1 : 0; - size = 4; - } else if (value <= 0xffffffffff) { - offset = value >= 0x8000000000 ? 1 : 0; - size = 5; - } else if (value <= 0xffffffffffff) { - offset = value >= 0x800000000000 ? 1 : 0; - size = 6; - } else { + if (limit != null && data.length > limit) throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.'); - } - // Write number. - data = Buffer.allocUnsafe(size + offset); + if (minimal && !ScriptNum.isMinimal(data)) + throw new ScriptError('UNKNOWN_ERROR', 'Non-minimal script number.'); - switch (size) { - case 6: - data[5] = (value / 0x10000000000 | 0) & 0xff; - case 5: - data[4] = (value / 0x100000000 | 0) & 0xff; - case 4: - data[3] = (value >>> 24) & 0xff; - case 3: - data[2] = (value >> 16) & 0xff; - case 2: - data[1] = (value >> 8) & 0xff; - case 1: - data[0] = value & 0xff; + return this.fromRaw(data); +}; + +/** + * Inspect script number. + * @returns {String} + */ + +ScriptNum.prototype.inspect = function inspect() { + return ``; +}; + +/** + * Test wether a serialized script + * number is in its most minimal form. + * @param {Buffer} data + * @returns {Boolean} + */ + +ScriptNum.isMinimal = function isMinimal(data) { + assert(Buffer.isBuffer(data)); + + if (data.length === 0) + return true; + + if ((data[data.length - 1] & 0x7f) === 0) { + if (data.length === 1) + return false; + + if ((data[data.length - 2] & 0x80) === 0) + return false; } - // Append sign bit. - if (data[size - 1] & 0x80) - data[size] = negative ? 0x80 : 0; - else if (negative) - data[size - 1] |= 0x80; + return true; +}; - return data; +/** + * Decode and verify script number. + * @param {Buffer} data + * @param {Boolean?} minimal - Require minimal encoding. + * @param {Number?} limit - Size limit. + * @returns {ScriptNum} + */ + +ScriptNum.decode = function decode(data, minimal, limit) { + return new ScriptNum().decode(data, minimal, limit); +}; + +/** + * Test whether object is a script number. + * @param {Object} obj + * @returns {Boolean} + */ + +ScriptNum.isScriptNum = function isScriptNum(obj) { + return obj instanceof ScriptNum; }; /* diff --git a/lib/script/sigcache.js b/lib/script/sigcache.js index c9940f821..378613bd9 100644 --- a/lib/script/sigcache.js +++ b/lib/script/sigcache.js @@ -27,8 +27,7 @@ function SigCache(size) { if (size == null) size = 10000; - assert(util.isNumber(size)); - assert(size >= 0); + assert(util.isU32(size)); this.size = size; this.keys = []; @@ -41,8 +40,7 @@ function SigCache(size) { */ SigCache.prototype.resize = function resize(size) { - assert(util.isNumber(size)); - assert(size >= 0); + assert(util.isU32(size)); this.size = size; this.keys.length = 0; @@ -64,8 +62,8 @@ SigCache.prototype.add = function add(hash, sig, key) { this.valid.set(hash, new SigCacheEntry(sig, key)); if (this.keys.length >= this.size) { - let i = Math.floor(Math.random() * this.keys.length); - let k = this.keys[i]; + const i = Math.floor(Math.random() * this.keys.length); + const k = this.keys[i]; this.valid.delete(k); this.keys[i] = hash; } else { @@ -82,12 +80,12 @@ SigCache.prototype.add = function add(hash, sig, key) { */ SigCache.prototype.has = function has(hash, sig, key) { - let entry = this.valid.get(hash); + const entry = this.valid.get(hash); if (!entry) return false; - return entry.equal(sig, key); + return entry.equals(sig, key); }; /** @@ -100,17 +98,15 @@ SigCache.prototype.has = function has(hash, sig, key) { */ SigCache.prototype.verify = function verify(msg, sig, key) { - let hash, result; - if (this.size === 0) return secp256k1.verify(msg, sig, key); - hash = msg.toString('hex'); + const hash = msg.toString('hex'); if (this.has(hash, sig, key)) return true; - result = secp256k1.verify(msg, sig, key); + const result = secp256k1.verify(msg, sig, key); if (!result) return false; @@ -142,7 +138,7 @@ function SigCacheEntry(sig, key) { * @returns {Boolean} */ -SigCacheEntry.prototype.equal = function equal(sig, key) { +SigCacheEntry.prototype.equals = function equals(sig, key) { return this.sig.equals(sig) && this.key.equals(key); }; diff --git a/lib/script/stack.js b/lib/script/stack.js index 5a5b9c727..49e708902 100644 --- a/lib/script/stack.js +++ b/lib/script/stack.js @@ -7,7 +7,9 @@ 'use strict'; +const assert = require('assert'); const common = require('./common'); +const ScriptNum = require('./scriptnum'); /** * Represents the stack of a Script during execution. @@ -25,30 +27,46 @@ function Stack(items) { this.items = items || []; } -/** - * Getter to retrieve stack items length. - * @name module:script.Stack#length_getter - * @method - * @private - * @returns {Number} +/* + * Expose length setter and getter. */ -Stack.prototype.__defineGetter__('length', function() { - return this.items.length; +Object.defineProperty(Stack.prototype, 'length', { + get() { + return this.items.length; + }, + set(length) { + this.items.length = length; + return this.items.length; + } }); /** - * Setter to set stack items length. - * @name module:script.Stack#length_setter - * @method - * @private - * @param {Number} value - * @returns {Number} + * Instantiate a key and value iterator. + * @returns {StackIterator} */ -Stack.prototype.__defineSetter__('length', function(length) { - return this.items.length = length; -}); +Stack.prototype[Symbol.iterator] = function iterator() { + return this.items[Symbol.iterator](); +}; + +/** + * Instantiate a value-only iterator. + * @returns {StackIterator} + */ + +Stack.prototype.values = function values() { + return this.items.values(); +}; + +/** + * Instantiate a key and value iterator. + * @returns {StackIterator} + */ + +Stack.prototype.entries = function entries() { + return this.items.entries(); +}; /** * Inspect the stack. @@ -65,7 +83,12 @@ Stack.prototype.inspect = function inspect() { */ Stack.prototype.toString = function toString() { - return common.formatStack(this.items); + const out = []; + + for (const item of this.items) + out.push(item.toString('hex')); + + return out.join(' '); }; /** @@ -75,7 +98,12 @@ Stack.prototype.toString = function toString() { */ Stack.prototype.toASM = function toASM(decode) { - return common.formatStackASM(this.items, decode); + const out = []; + + for (const item of this.items) + out.push(common.toASM(item, decode)); + + return out.join(' '); }; /** @@ -87,6 +115,94 @@ Stack.prototype.clone = function clone() { return new Stack(this.items.slice()); }; +/** + * Clear the stack. + * @returns {Stack} + */ + +Stack.prototype.clear = function clear() { + this.items.length = 0; + return this; +}; + +/** + * Get a stack item by index. + * @param {Number} index + * @returns {Buffer|null} + */ + +Stack.prototype.get = function get(index) { + if (index < 0) + index += this.items.length; + + if (index < 0 || index >= this.items.length) + return null; + + return this.items[index]; +}; + +/** + * Pop a stack item. + * @see Array#pop + * @returns {Buffer|null} + */ + +Stack.prototype.pop = function pop() { + const item = this.items.pop(); + return item || null; +}; + +/** + * Shift a stack item. + * @see Array#shift + * @returns {Buffer|null} + */ + +Stack.prototype.shift = function shift() { + const item = this.items.shift(); + return item || null; +}; + +/** + * Remove an item. + * @param {Number} index + * @returns {Buffer} + */ + +Stack.prototype.remove = function remove(index) { + if (index < 0) + index += this.items.length; + + if (index < 0 || index >= this.items.length) + return null; + + const items = this.items.splice(index, 1); + + if (items.length === 0) + return null; + + return items[0]; +}; + +/** + * Set stack item at index. + * @param {Number} index + * @param {Buffer} value + * @returns {Buffer} + */ + +Stack.prototype.set = function set(index, item) { + if (index < 0) + index += this.items.length; + + assert(Buffer.isBuffer(item)); + assert(index >= 0 && index <= this.items.length); + + this.items[index] = item; + + return this; +}; + /** * Push item onto stack. * @see Array#push @@ -95,7 +211,9 @@ Stack.prototype.clone = function clone() { */ Stack.prototype.push = function push(item) { - return this.items.push(item); + assert(Buffer.isBuffer(item)); + this.items.push(item); + return this; }; /** @@ -106,39 +224,28 @@ Stack.prototype.push = function push(item) { */ Stack.prototype.unshift = function unshift(item) { - return this.items.unshift(item); -}; - -/** - * Slice out part of the stack items. - * @param {Number} start - * @param {Number} end - * @see Array#slice - * @returns {Stack} - */ - -Stack.prototype.slice = function slice(start, end) { - this.items = this.items.slice(start, end); + assert(Buffer.isBuffer(item)); + this.items.unshift(item); return this; }; /** - * Splice stack items. - * @see Array#splice + * Insert an item. * @param {Number} index - * @param {Number} remove - * @param {Buffer?} insert - * @returns {Buffer[]} + * @param {Buffer} item + * @returns {Buffer} */ -Stack.prototype.splice = function splice(i, remove, insert) { - if (i < 0) - i = this.items.length + i; +Stack.prototype.insert = function insert(index, item) { + if (index < 0) + index += this.items.length; + + assert(Buffer.isBuffer(item)); + assert(index >= 0 && index <= this.items.length); - if (insert === undefined) - return this.items.splice(i, remove); + this.items.splice(index, 0, item); - return this.items.splice(i, remove, insert); + return this; }; /** @@ -159,120 +266,228 @@ Stack.prototype.erase = function erase(start, end) { }; /** - * Insert an item. - * @param {Number} index - * @param {Buffer} item - * @returns {Buffer} + * Swap stack values. + * @param {Number} i1 - Index 1. + * @param {Number} i2 - Index 2. */ -Stack.prototype.insert = function insert(i, item) { - if (i < 0) - i = this.items.length + i; +Stack.prototype.swap = function swap(i1, i2) { + if (i1 < 0) + i1 = this.items.length + i1; - this.items.splice(i, 0, item); + if (i2 < 0) + i2 = this.items.length + i2; + + const v1 = this.items[i1]; + const v2 = this.items[i2]; + + this.items[i1] = v2; + this.items[i2] = v1; }; -/** - * Remove an item. - * @param {Number} index - * @returns {Buffer} +/* + * Data */ -Stack.prototype.remove = function remove(i) { - if (i < 0) - i = this.items.length + i; +Stack.prototype.getData = function getData(index) { + return this.get(index); +}; - if (i >= this.items.length) - return; +Stack.prototype.popData = function popData() { + return this.pop(); +}; - return this.items.splice(i, 1)[0]; +Stack.prototype.shiftData = function shiftData() { + return this.shift(); }; -/** - * Pop a stack item. - * @see Array#pop - * @returns {Buffer|null} - */ +Stack.prototype.removeData = function removeData(index) { + return this.remove(index); +}; -Stack.prototype.pop = function pop() { - return this.items.pop(); +Stack.prototype.setData = function setData(index, data) { + return this.set(index, data); }; -/** - * Shift a stack item. - * @see Array#shift - * @returns {Buffer|null} - */ +Stack.prototype.pushData = function pushData(data) { + return this.push(data); +}; -Stack.prototype.shift = function shift() { - return this.items.shift(); +Stack.prototype.unshiftData = function unshiftData(data) { + return this.unshift(data); }; -/** - * Get a stack item by index. - * @param {Number} index - * @returns {Buffer|null} +Stack.prototype.insertData = function insertData(index, data) { + return this.insert(index, data); +}; + +/* + * Length */ -Stack.prototype.get = function get(i) { - return this.items[i]; +Stack.prototype.getLength = function getLength(index) { + const item = this.get(index); + return item ? item.length : -1; }; -/** - * Get a stack item relative to - * the top of the stack. - * @example - * stack.top(-1); - * @param {Number} index - * @returns {Buffer|null} +/* + * String */ -Stack.prototype.top = function top(i) { - return this.items[this.items.length + i]; +Stack.prototype.getString = function getString(index, enc) { + const item = this.get(index); + return item ? Stack.toString(item, enc) : null; }; -/** - * Clear the stack. +Stack.prototype.popString = function popString(enc) { + const item = this.pop(); + return item ? Stack.toString(item, enc) : null; +}; + +Stack.prototype.shiftString = function shiftString(enc) { + const item = this.shift(); + return item ? Stack.toString(item, enc) : null; +}; + +Stack.prototype.removeString = function removeString(index, enc) { + const item = this.remove(index); + return item ? Stack.toString(item, enc) : null; +}; + +Stack.prototype.setString = function setString(index, str, enc) { + return this.set(index, Stack.fromString(str, enc)); +}; + +Stack.prototype.pushString = function pushString(str, enc) { + return this.push(Stack.fromString(str, enc)); +}; + +Stack.prototype.unshiftString = function unshiftString(str, enc) { + return this.unshift(Stack.fromString(str, enc)); +}; + +Stack.prototype.insertString = function insertString(index, str, enc) { + return this.insert(index, Stack.fromString(str, enc)); +}; + +/* + * Num */ -Stack.prototype.clear = function clear() { - this.items.length = 0; +Stack.prototype.getNum = function getNum(index, minimal, limit) { + const item = this.get(index); + return item ? Stack.toNum(item, minimal, limit) : null; }; -/** - * Set stack item at index. - * @param {Number} index - * @param {Buffer} value - * @returns {Buffer} +Stack.prototype.popNum = function popNum(minimal, limit) { + const item = this.pop(); + return item ? Stack.toNum(item, minimal, limit) : null; +}; + +Stack.prototype.shiftNum = function shiftNum(minimal, limit) { + const item = this.shift(); + return item ? Stack.toNum(item, minimal, limit) : null; +}; + +Stack.prototype.removeNum = function removeNum(index, minimal, limit) { + const item = this.remove(index); + return item ? Stack.toNum(item, minimal, limit) : null; +}; + +Stack.prototype.setNum = function setNum(index, num) { + return this.set(index, Stack.fromNum(num)); +}; + +Stack.prototype.pushNum = function pushNum(num) { + return this.push(Stack.fromNum(num)); +}; + +Stack.prototype.unshiftNum = function unshiftNum(num) { + return this.unshift(Stack.fromNum(num)); +}; + +Stack.prototype.insertNum = function insertNum(index, num) { + return this.insert(index, Stack.fromNum(num)); +}; + +/* + * Int */ -Stack.prototype.set = function set(i, value) { - if (i < 0) - i = this.items.length + i; +Stack.prototype.getInt = function getInt(index, minimal, limit) { + const item = this.get(index); + return item ? Stack.toInt(item, minimal, limit) : -1; +}; - return this.items[i] = value; +Stack.prototype.popInt = function popInt(minimal, limit) { + const item = this.pop(); + return item ? Stack.toInt(item, minimal, limit) : -1; }; -/** - * Swap stack values. - * @param {Number} i1 - Index 1. - * @param {Number} i2 - Index 2. +Stack.prototype.shiftInt = function shiftInt(minimal, limit) { + const item = this.shift(); + return item ? Stack.toInt(item, minimal, limit) : -1; +}; + +Stack.prototype.removeInt = function removeInt(index, minimal, limit) { + const item = this.remove(index); + return item ? Stack.toInt(item, minimal, limit) : -1; +}; + +Stack.prototype.setInt = function setInt(index, num) { + return this.set(index, Stack.fromInt(num)); +}; + +Stack.prototype.pushInt = function pushInt(num) { + return this.push(Stack.fromInt(num)); +}; + +Stack.prototype.unshiftInt = function unshiftInt(num) { + return this.unshift(Stack.fromInt(num)); +}; + +Stack.prototype.insertInt = function insertInt(index, num) { + return this.insert(index, Stack.fromInt(num)); +}; + +/* + * Bool */ -Stack.prototype.swap = function swap(i1, i2) { - let v1, v2; +Stack.prototype.getBool = function getBool(index) { + const item = this.get(index); + return item ? Stack.toBool(item) : false; +}; - if (i1 < 0) - i1 = this.items.length + i1; +Stack.prototype.popBool = function popBool() { + const item = this.pop(); + return item ? Stack.toBool(item) : false; +}; - if (i2 < 0) - i2 = this.items.length + i2; +Stack.prototype.shiftBool = function shiftBool() { + const item = this.shift(); + return item ? Stack.toBool(item) : false; +}; - v1 = this.items[i1]; - v2 = this.items[i2]; +Stack.prototype.removeBool = function removeBool(index) { + const item = this.remove(index); + return item ? Stack.toBool(item) : false; +}; - this.items[i1] = v2; - this.items[i2] = v1; +Stack.prototype.setBool = function setBool(index, value) { + return this.set(index, Stack.fromBool(value)); +}; + +Stack.prototype.pushBool = function pushBool(value) { + return this.push(Stack.fromBool(value)); +}; + +Stack.prototype.unshiftBool = function unshiftBool(value) { + return this.unshift(Stack.fromBool(value)); +}; + +Stack.prototype.insertBool = function insertBool(index, value) { + return this.insert(index, Stack.fromBool(value)); }; /** @@ -282,7 +497,73 @@ Stack.prototype.swap = function swap(i1, i2) { */ Stack.isStack = function isStack(obj) { - return obj && Array.isArray(obj.items) && typeof obj.swap === 'function'; + return obj instanceof Stack; +}; + +/* + * Encoding + */ + +Stack.toString = function toString(item, enc) { + assert(Buffer.isBuffer(item)); + return item.toString(enc || 'utf8'); +}; + +Stack.fromString = function fromString(str, enc) { + assert(typeof str === 'string'); + return Buffer.from(str, enc || 'utf8'); +}; + +Stack.toNum = function toNum(item, minimal, limit) { + assert(Buffer.isBuffer(item)); + return ScriptNum.decode(item, minimal, limit); +}; + +Stack.fromNum = function fromNum(num) { + assert(ScriptNum.isScriptNum(num)); + return num.encode(); +}; + +Stack.toInt = function toInt(item, minimal, limit) { + assert(Buffer.isBuffer(item)); + + const num = Stack.toNum(item, minimal, limit); + + if (!num) + return -1; + + return num.getInt(); +}; + +Stack.fromInt = function fromInt(int) { + assert(typeof int === 'number'); + + if (int >= -1 && int <= 16) + return common.small[int + 1]; + + const num = ScriptNum.fromNumber(int); + + return Stack.fromNum(num); +}; + +Stack.toBool = function toBool(item) { + assert(Buffer.isBuffer(item)); + + for (let i = 0; i < item.length; i++) { + if (item[i] !== 0) { + // Cannot be negative zero + if (i === item.length - 1 && item[i] === 0x80) + return false; + return true; + } + } + + return false; +}; + +Stack.fromBool = function fromBool(value) { + assert(typeof value === 'boolean'); + return Stack.fromInt(value ? 1 : 0); }; /* diff --git a/lib/script/witness.js b/lib/script/witness.js index aaa45643e..001f9ef34 100644 --- a/lib/script/witness.js +++ b/lib/script/witness.js @@ -8,20 +8,15 @@ 'use strict'; const assert = require('assert'); -const BN = require('../crypto/bn'); const util = require('../utils/util'); const Script = require('./script'); const common = require('./common'); const encoding = require('../utils/encoding'); -const Opcode = require('./opcode'); const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); const Address = require('../primitives/address'); const Stack = require('./stack'); -const opcodes = common.opcodes; const scriptTypes = common.types; -const STACK_FALSE = common.STACK_FALSE; -const STACK_NEGATE = common.STACK_NEGATE; /** * Refers to the witness field of segregated witness transactions. @@ -38,36 +33,13 @@ function Witness(options) { if (!(this instanceof Witness)) return new Witness(options); - this.items = []; + Stack.call(this, []); if (options) this.fromOptions(options); } -/** - * Getter to retrieve witness vector length. - * @name module:script.Witness#length_getter - * @method - * @private - * @returns {Number} - */ - -Witness.prototype.__defineGetter__('length', function() { - return this.items.length; -}); - -/** - * Setter to set witness vector length. - * @name module:script.Witness#length_setter - * @method - * @private - * @param {Number} value - * @returns {Number} - */ - -Witness.prototype.__defineSetter__('length', function(length) { - return this.items.length = length; -}); +Object.setPrototypeOf(Witness.prototype, Stack.prototype); /** * Inject properties from options object. @@ -76,17 +48,13 @@ Witness.prototype.__defineSetter__('length', function(length) { */ Witness.prototype.fromOptions = function fromOptions(options) { - let items; - assert(options, 'Witness data is required.'); - items = options.items; - - if (!items) - items = options; + if (Array.isArray(options)) + return this.fromArray(options); - if (items) - this.fromArray(items); + if (options.items) + return this.fromArray(options.items); return this; }; @@ -133,31 +101,72 @@ Witness.fromArray = function fromArray(items) { }; /** - * Inspect a Witness object. - * @returns {String} Human-readable script. + * Convert witness to an array of buffers. + * @returns {Buffer[]} */ -Witness.prototype.inspect = function inspect() { - return ``; +Witness.prototype.toItems = function toItems() { + return this.items.slice(); }; /** - * Convert a Witness object to a String. - * @returns {String} Human-readable script. + * Inject properties from an array of buffers. + * @private + * @param {Buffer[]} items + */ + +Witness.prototype.fromItems = function fromItems(items) { + assert(Array.isArray(items)); + this.items = items; + return this; +}; + +/** + * Insantiate witness from an array of buffers. + * @param {Buffer[]} items + * @returns {Witness} + */ + +Witness.fromItems = function fromItems(items) { + return new Witness().fromItems(items); +}; + +/** + * Convert witness to a stack. + * @returns {Stack} + */ + +Witness.prototype.toStack = function toStack() { + return new Stack(this.toArray()); +}; + +/** + * Inject properties from a stack. + * @private + * @param {Stack} stack */ -Witness.prototype.toString = function toString() { - return common.formatStack(this.items); +Witness.prototype.fromStack = function fromStack(stack) { + return this.fromArray(stack.items); }; /** - * Format the witness object as bitcoind asm. - * @param {Boolean?} decode - Attempt to decode hash types. + * Insantiate witness from a stack. + * @param {Stack} stack + * @returns {Witness} + */ + +Witness.fromStack = function fromStack(stack) { + return new Witness().fromStack(stack); +}; + +/** + * Inspect a Witness object. * @returns {String} Human-readable script. */ -Witness.prototype.toASM = function toASM(decode) { - return common.formatStackASM(this.items, decode); +Witness.prototype.inspect = function inspect() { + return ``; }; /** @@ -183,14 +192,12 @@ Witness.prototype.inject = function inject(witness) { }; /** - * Convert the Witness to a Stack object. - * This is usually done before executing - * a witness program. - * @returns {Stack} + * Compile witness (NOP). + * @returns {Witness} */ -Witness.prototype.toStack = function toStack() { - return new Stack(this.items.slice()); +Witness.prototype.compile = function compile() { + return this; }; /** @@ -229,6 +236,16 @@ Witness.prototype.isPubkeyInput = function isPubkeyInput() { return false; }; +/** + * Get P2PK signature if present. + * Always returns null. + * @returns {Buffer|null} + */ + +Witness.prototype.getPubkeyInput = function getPubkeyInput() { + return null; +}; + /** * "Guess" whether the witness is a pubkeyhash input. * This method is not 100% reliable. @@ -241,6 +258,17 @@ Witness.prototype.isPubkeyhashInput = function isPubkeyhashInput() { && common.isKeyEncoding(this.items[1]); }; +/** + * Get P2PKH signature and key if present. + * @returns {Array} [sig, key] + */ + +Witness.prototype.getPubkeyhashInput = function getPubkeyhashInput() { + if (!this.isPubkeyhashInput()) + return [null, null]; + return [this.items[0], this.items[1]]; +}; + /** * "Test" whether the witness is a multisig input. * Always returns false. @@ -251,6 +279,16 @@ Witness.prototype.isMultisigInput = function isMultisigInput() { return false; }; +/** + * Get multisig signatures key if present. + * Always returns null. + * @returns {Buffer[]|null} + */ + +Witness.prototype.getMultisigInput = function getMultisigInput() { + return null; +}; + /** * "Guess" whether the witness is a scripthash input. * This method is not 100% reliable. @@ -261,6 +299,17 @@ Witness.prototype.isScripthashInput = function isScripthashInput() { return this.items.length > 0 && !this.isPubkeyhashInput(); }; +/** + * Get P2SH redeem script if present. + * @returns {Buffer|null} + */ + +Witness.prototype.getScripthashInput = function getScripthashInput() { + if (!this.isScripthashInput()) + return null; + return this.items[this.items.length - 1]; +}; + /** * "Guess" whether the witness is an unknown/non-standard type. * This method is not 100% reliable. @@ -278,7 +327,7 @@ Witness.prototype.isUnknownInput = function isUnknownInput() { */ Witness.prototype.test = function test(filter) { - for (let item of this.items) { + for (const item of this.items) { if (item.length === 0) continue; @@ -295,27 +344,17 @@ Witness.prototype.test = function test(filter) { */ Witness.prototype.getRedeem = function getRedeem() { - let redeem; - if (this.items.length === 0) - return; + return null; - redeem = this.items[this.items.length - 1]; + const redeem = this.items[this.items.length - 1]; if (!redeem) - return; + return null; return Script.fromRaw(redeem); }; -/** - * Does nothing currently. - */ - -Witness.prototype.compile = function compile() { - // NOP -}; - /** * Find a data element in a witness. * @param {Buffer} data - Data element to match against. @@ -335,7 +374,7 @@ Witness.prototype.indexOf = function indexOf(data) { Witness.prototype.getSize = function getSize() { let size = 0; - for (let item of this.items) + for (const item of this.items) size += encoding.sizeVarBytes(item); return size; @@ -357,11 +396,9 @@ Witness.prototype.getVarSize = function getVarSize() { */ Witness.prototype.toWriter = function toWriter(bw) { - let item; - bw.writeVarint(this.items.length); - for (item of this.items) + for (const item of this.items) bw.writeVarBytes(item); return bw; @@ -374,7 +411,7 @@ Witness.prototype.toWriter = function toWriter(bw) { */ Witness.prototype.toRaw = function toRaw() { - let size = this.getVarSize(); + const size = this.getVarSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -408,169 +445,6 @@ Witness.fromJSON = function fromJSON(json) { return new Witness().fromJSON(json); }; -/** - * Unshift an item onto the witness vector. - * @param {Number|String|Buffer|BN} data - * @returns {Number} - */ - -Witness.prototype.unshift = function unshift(data) { - return this.items.unshift(Witness.encodeItem(data)); -}; - -/** - * Push an item onto the witness vector. - * @param {Number|String|Buffer|BN} data - * @returns {Number} - */ - -Witness.prototype.push = function push(data) { - return this.items.push(Witness.encodeItem(data)); -}; - -/** - * Shift an item off the witness vector. - * @returns {Buffer} - */ - -Witness.prototype.shift = function shift() { - return this.items.shift(); -}; - -/** - * Shift an item off the witness vector. - * @returns {Buffer} - */ - -Witness.prototype.pop = function push(data) { - return this.items.pop(); -}; - -/** - * Remove an item from the witness vector. - * @param {Number} index - * @returns {Buffer} - */ - -Witness.prototype.remove = function remove(i) { - return this.items.splice(i, 1)[0]; -}; - -/** - * Insert an item into the witness vector. - * @param {Number} index - * @param {Number|String|Buffer|BN} data - */ - -Witness.prototype.insert = function insert(i, data) { - assert(i <= this.items.length, 'Index out of bounds.'); - this.items.splice(i, 0, Witness.encodeItem(data))[0]; -}; - -/** - * Get an item from the witness vector. - * @param {Number} index - * @returns {Buffer} - */ - -Witness.prototype.get = function get(i) { - return this.items[i]; -}; - -/** - * Get a small int (0-16) from the witness vector. - * @param {Number} index - * @returns {Number} `-1` on non-existent. - */ - -Witness.prototype.getSmall = function getSmall(i) { - let item = this.items[i]; - if (!item || item.length > 1) - return -1; - if (item.length === 0) - return 0; - if (!(item[0] >= 1 && item[1] <= 16)) - return -1; - return item[0]; -}; - -/** - * Get a number from the witness vector. - * @param {Number} index - * @returns {BN} - */ - -Witness.prototype.getNumber = function getNumber(i) { - let item = this.items[i]; - if (!item || item.length > 5) - return; - return common.num(item, false, 5); -}; - -/** - * Get a string from the witness vector. - * @param {Number} index - * @returns {String} - */ - -Witness.prototype.getString = function getString(i) { - let item = this.items[i]; - if (!item) - return; - return item.toString('utf8'); -}; - -/** - * Clear the witness items. - */ - -Witness.prototype.clear = function clear() { - this.items.length = 0; -}; - -/** - * Set an item in the witness vector. - * @param {Number} index - * @param {Number|String|Buffer|BN} data - */ - -Witness.prototype.set = function set(i, data) { - assert(i <= this.items.length, 'Index out of bounds.'); - this.items[i] = Witness.encodeItem(data); -}; - -/** - * Encode a witness item. - * @param {Number|String|Buffer|BN} data - * @returns {Buffer} - */ - -Witness.encodeItem = function encodeItem(data) { - if (data instanceof Opcode) - data = data.data || data.value; - - if (typeof data === 'number') { - if (data === opcodes.OP_1NEGATE) - return STACK_NEGATE; - - if (data === opcodes.OP_0) - return STACK_FALSE; - - if (data >= opcodes.OP_1 && data <= opcodes.OP_16) - return Buffer.from([data - 0x50]); - - throw new Error('Non-push opcode in witness.'); - } - - if (BN.isBN(data)) - return common.array(data); - - if (typeof data === 'string') - return Buffer.from(data, 'utf8'); - - return data; -}; - /** * Inject properties from buffer reader. * @private @@ -578,7 +452,7 @@ Witness.encodeItem = function encodeItem(data) { */ Witness.prototype.fromReader = function fromReader(br) { - let count = br.readVarint(); + const count = br.readVarint(); for (let i = 0; i < count; i++) this.items.push(br.readVarBytes()); @@ -636,7 +510,7 @@ Witness.prototype.fromString = function fromString(items) { items = items.split(/\s+/); } - for (let item of items) + for (const item of items) this.items.push(Buffer.from(item, 'hex')); return this; @@ -663,9 +537,7 @@ Witness.fromString = function fromString(items) { */ Witness.isWitness = function isWitness(obj) { - return obj - && Array.isArray(obj.items) - && typeof obj.toStack === 'function'; + return obj instanceof Witness; }; /* diff --git a/lib/types.js b/lib/types.js index f26b5c7d6..fac6ea310 100644 --- a/lib/types.js +++ b/lib/types.js @@ -133,7 +133,7 @@ * This value will never be negative. * @property {Hash} prevBlock * @property {Hash} merkleRoot - * @property {Number} ts + * @property {Number} time * @property {Number} bits * @property {Number} nonce * @property {Number} height diff --git a/lib/utils/asn1.js b/lib/utils/asn1.js index cde6e0ced..8dae485b0 100644 --- a/lib/utils/asn1.js +++ b/lib/utils/asn1.js @@ -45,11 +45,10 @@ const ASN1 = exports; ASN1.readTag = function readTag(br) { let type = br.readU8(); - let primitive = (type & 0x20) === 0; - let oct; + const primitive = (type & 0x20) === 0; if ((type & 0x1f) === 0x1f) { - oct = type; + let oct = type; type = 0; while ((oct & 0x80) === 0x80) { oct = br.readU8(); @@ -77,7 +76,6 @@ ASN1.readTag = function readTag(br) { ASN1.readSize = function readSize(br, primitive) { let size = br.readU8(); - let bytes, i, j; // Indefinite form if (!primitive && size === 0x80) @@ -90,16 +88,15 @@ ASN1.readSize = function readSize(br, primitive) { } // Long form - bytes = size & 0x7f; + const bytes = size & 0x7f; if (bytes > 3) throw new Error('Length octet is too long.'); size = 0; - for (i = 0; i < bytes; i++) { + for (let i = 0; i < bytes; i++) { size <<= 8; - j = br.readU8(); - size |= j; + size |= br.readU8(); } return size; @@ -112,7 +109,7 @@ ASN1.readSize = function readSize(br, primitive) { */ ASN1.readSeq = function readSeq(br) { - let tag = ASN1.implicit(br, 0x10); + const tag = ASN1.implicit(br, 0x10); return br.readBytes(tag.size); }; @@ -125,9 +122,11 @@ ASN1.readSeq = function readSeq(br) { */ ASN1.implicit = function implicit(br, type) { - let tag = ASN1.readTag(br); + const tag = ASN1.readTag(br); + if (tag.type !== type) throw new Error(`Unexpected tag: ${tag.type}.`); + return tag; }; @@ -139,12 +138,14 @@ ASN1.implicit = function implicit(br, type) { */ ASN1.explicit = function explicit(br, type) { - let offset = br.offset; - let tag = ASN1.readTag(br); + const offset = br.offset; + const tag = ASN1.readTag(br); + if (tag.type !== type) { br.offset = offset; return false; } + return true; }; @@ -161,15 +162,15 @@ ASN1.seq = function seq(br) { /** * Read implicit int. * @param {BufferReader} br - * @param {Boolean?} readNum + * @param {Boolean?} cast * @returns {Buffer|Number} */ -ASN1.readInt = function readInt(br, readNum) { - let tag = ASN1.implicit(br, 0x02); - let num = br.readBytes(tag.size); +ASN1.readInt = function readInt(br, cast) { + const tag = ASN1.implicit(br, 0x02); + const num = br.readBytes(tag.size); - if (readNum) + if (cast) return num.readUIntBE(0, num.length); return num; @@ -186,6 +187,7 @@ ASN1.readInt = function readInt(br, readNum) { ASN1.readExplicitInt = function readExplicitInt(br, type, readNum) { if (!ASN1.explicit(br, type)) return -1; + return ASN1.readInt(br, readNum); }; @@ -196,8 +198,8 @@ ASN1.readExplicitInt = function readExplicitInt(br, type, readNum) { */ ASN1.readBitstr = function readBitstr(br) { - let tag = ASN1.implicit(br, 0x03); - let str = br.readBytes(tag.size); + const tag = ASN1.implicit(br, 0x03); + const str = br.readBytes(tag.size); return ASN1.alignBitstr(str); }; @@ -208,13 +210,13 @@ ASN1.readBitstr = function readBitstr(br) { */ ASN1.readString = function readString(br) { - let tag = ASN1.readTag(br); - let str; + const tag = ASN1.readTag(br); switch (tag.type) { - case 0x03: // bitstr - str = br.readBytes(tag.size); - return ASN1.alignBitstr(str); + case 0x03: { // bitstr + const str = br.readBytes(tag.size); + return ASN1.alignBitstr(str).toString('utf8'); + } // Note: // Fuck all these. case 0x04: // octstr @@ -229,10 +231,12 @@ ASN1.readString = function readString(br) { case 0x1b: // genstr case 0x1c: // unistr case 0x1d: // charstr - case 0x1e: // bmpstr + case 0x1e: { // bmpstr return br.readString('utf8', tag.size); - default: + } + default: { throw new Error(`Unexpected tag: ${tag.type}.`); + } } }; @@ -243,19 +247,18 @@ ASN1.readString = function readString(br) { */ ASN1.alignBitstr = function alignBitstr(data) { - let padding = data[0]; - let bits = (data.length - 1) * 8 - padding; - let buf = data.slice(1); - let shift = 8 - (bits % 8); - let i, out; + const padding = data[0]; + const bits = (data.length - 1) * 8 - padding; + const buf = data.slice(1); + const shift = 8 - (bits % 8); if (shift === 8 || buf.length === 0) return buf; - out = Buffer.allocUnsafe(buf.length); + const out = Buffer.allocUnsafe(buf.length); out[0] = buf[0] >>> shift; - for (i = 1; i < buf.length; i++) { + for (let i = 1; i < buf.length; i++) { out[i] = buf[i - 1] << (8 - shift); out[i] |= buf[i] >>> shift; } @@ -270,7 +273,7 @@ ASN1.alignBitstr = function alignBitstr(data) { */ ASN1.readCert = function readCert(br) { - let buf = br; + const buf = br; buf.start(); @@ -291,7 +294,7 @@ ASN1.readCert = function readCert(br) { */ ASN1.readTBS = function readTBS(br) { - let buf = br; + const buf = br; buf.start(); @@ -330,7 +333,7 @@ ASN1.readPubkey = function readPubkey(br) { */ ASN1.readName = function readName(br) { - let values = []; + const values = []; br = ASN1.seq(br); @@ -367,8 +370,8 @@ ASN1.readValidity = function readValidity(br) { */ ASN1.readTime = function readTime(br) { - let tag = ASN1.readTag(br); - let str = br.readString('ascii', tag.size); + const tag = ASN1.readTag(br); + const str = br.readString('ascii', tag.size); let year, mon, day, hour, min, sec; switch (tag.type) { @@ -406,8 +409,8 @@ ASN1.readTime = function readTime(br) { */ ASN1.readOID = function readOID(br) { - let tag = ASN1.implicit(br, 0x06); - let data = br.readBytes(tag.size); + const tag = ASN1.implicit(br, 0x06); + const data = br.readBytes(tag.size); return ASN1.formatOID(data); }; @@ -418,11 +421,10 @@ ASN1.readOID = function readOID(br) { */ ASN1.formatOID = function formatOID(data) { - let br = new BufferReader(data); - let ids = []; + const br = new BufferReader(data); + const ids = []; let ident = 0; let subident = 0; - let result, first, second; while (br.left()) { subident = br.readU8(); @@ -437,9 +439,9 @@ ASN1.formatOID = function formatOID(data) { if (subident & 0x80) ids.push(ident); - first = (ids[0] / 40) | 0; - second = ids[0] % 40; - result = [first, second].concat(ids.slice(1)); + const first = (ids[0] / 40) | 0; + const second = ids[0] % 40; + const result = [first, second].concat(ids.slice(1)); return result.join('.'); }; @@ -452,14 +454,13 @@ ASN1.formatOID = function formatOID(data) { ASN1.readAlgIdent = function readAlgIdent(br) { let params = null; - let alg, tag; br = ASN1.seq(br); - alg = ASN1.readOID(br); + const alg = ASN1.readOID(br); if (br.left() > 0) { - tag = ASN1.readTag(br); + const tag = ASN1.readTag(br); params = br.readBytes(tag.size); if (params.length === 0) params = null; diff --git a/lib/utils/asyncemitter.js b/lib/utils/asyncemitter.js index 3e6c18f3f..3f1c32780 100644 --- a/lib/utils/asyncemitter.js +++ b/lib/utils/asyncemitter.js @@ -116,18 +116,17 @@ AsyncEmitter.prototype._unshift = function _unshift(type, handler, once) { */ AsyncEmitter.prototype.removeListener = function removeListener(type, handler) { - let i, listeners, listener; - let index = -1; - assert(typeof type === 'string', '`type` must be a string.'); - listeners = this._events[type]; + const listeners = this._events[type]; if (!listeners) return; - for (i = 0; i < listeners.length; i++) { - listener = listeners[i]; + let index = -1; + + for (let i = 0; i < listeners.length; i++) { + const listener = listeners[i]; if (listener.handler === handler) { index = i; break; @@ -153,7 +152,7 @@ AsyncEmitter.prototype.removeListener = function removeListener(type, handler) { AsyncEmitter.prototype.setMaxListeners = function setMaxListeners(max) { assert(typeof max === 'number', '`max` must be a number.'); assert(max >= 0, '`max` must be non-negative.'); - assert(max % 1 === 0, '`max` must be an integer.'); + assert(Number.isSafeInteger(max), '`max` must be an integer.'); }; /** @@ -179,17 +178,16 @@ AsyncEmitter.prototype.removeAllListeners = function removeAllListeners(type) { */ AsyncEmitter.prototype.listeners = function listeners(type) { - let listeners, listener; - let result = []; - assert(typeof type === 'string', '`type` must be a string.'); - listeners = this._events[type]; + const listeners = this._events[type]; if (!listeners) - return result; + return []; + + const result = []; - for (listener of listeners) + for (const listener of listeners) result.push(listener.handler); return result; @@ -201,11 +199,9 @@ AsyncEmitter.prototype.listeners = function listeners(type) { */ AsyncEmitter.prototype.listenerCount = function listenerCount(type) { - let listeners; - assert(typeof type === 'string', '`type` must be a string.'); - listeners = this._events[type]; + const listeners = this._events[type]; if (!listeners) return 0; @@ -222,29 +218,29 @@ AsyncEmitter.prototype.listenerCount = function listenerCount(type) { */ AsyncEmitter.prototype.emit = function emit(type) { - let i, j, listeners, error, err, args, listener, handler; - assert(typeof type === 'string', '`type` must be a string.'); - listeners = this._events[type]; + const listeners = this._events[type]; if (!listeners || listeners.length === 0) { if (type === 'error') { - error = arguments[1]; + const error = arguments[1]; if (error instanceof Error) throw error; - err = new Error(`Uncaught, unspecified "error" event. (${error})`); + const err = new Error(`Uncaught, unspecified "error" event. (${error})`); err.context = error; throw err; } return; } - for (i = 0; i < listeners.length; i++) { - listener = listeners[i]; - handler = listener.handler; + let args; + + for (let i = 0; i < listeners.length; i++) { + const listener = listeners[i]; + const handler = listener.handler; if (listener.once) { listeners.splice(i, 1); @@ -267,7 +263,7 @@ AsyncEmitter.prototype.emit = function emit(type) { default: if (!args) { args = new Array(arguments.length - 1); - for (j = 1; j < arguments.length; j++) + for (let j = 1; j < arguments.length; j++) args[j - 1] = arguments[j]; } handler.apply(null, args); @@ -285,29 +281,29 @@ AsyncEmitter.prototype.emit = function emit(type) { */ AsyncEmitter.prototype.fire = async function fire(type) { - let i, j, listeners, error, err, args, listener, handler; - assert(typeof type === 'string', '`type` must be a string.'); - listeners = this._events[type]; + const listeners = this._events[type]; if (!listeners || listeners.length === 0) { if (type === 'error') { - error = arguments[1]; + const error = arguments[1]; if (error instanceof Error) throw error; - err = new Error(`Uncaught, unspecified "error" event. (${error})`); + const err = new Error(`Uncaught, unspecified "error" event. (${error})`); err.context = error; throw err; } return; } - for (i = 0; i < listeners.length; i++) { - listener = listeners[i]; - handler = listener.handler; + let args; + + for (let i = 0; i < listeners.length; i++) { + const listener = listeners[i]; + const handler = listener.handler; if (listener.once) { listeners.splice(i, 1); @@ -330,7 +326,7 @@ AsyncEmitter.prototype.fire = async function fire(type) { default: if (!args) { args = new Array(arguments.length - 1); - for (j = 1; j < arguments.length; j++) + for (let j = 1; j < arguments.length; j++) args[j - 1] = arguments[j]; } await handler.apply(null, args); diff --git a/lib/utils/asyncobject.js b/lib/utils/asyncobject.js index e7546180b..3e306f421 100644 --- a/lib/utils/asyncobject.js +++ b/lib/utils/asyncobject.js @@ -8,7 +8,6 @@ const assert = require('assert'); const EventEmitter = require('events'); -const util = require('./util'); const Lock = require('./lock'); /** @@ -34,7 +33,7 @@ function AsyncObject() { this.loaded = false; } -util.inherits(AsyncObject, EventEmitter); +Object.setPrototypeOf(AsyncObject.prototype, EventEmitter.prototype); /** * Open the object (recallable). @@ -43,7 +42,7 @@ util.inherits(AsyncObject, EventEmitter); */ AsyncObject.prototype.open = async function open() { - let unlock = await this._asyncLock.lock(); + const unlock = await this._asyncLock.lock(); try { return await this.__open(); } finally { @@ -58,7 +57,7 @@ AsyncObject.prototype.open = async function open() { * @returns {Promise} */ -AsyncObject.prototype.__open = async function open() { +AsyncObject.prototype.__open = async function __open() { if (this.loaded) return; @@ -87,7 +86,7 @@ AsyncObject.prototype.__open = async function open() { */ AsyncObject.prototype.close = async function close() { - let unlock = await this._asyncLock.lock(); + const unlock = await this._asyncLock.lock(); try { return await this.__close(); } finally { @@ -102,7 +101,7 @@ AsyncObject.prototype.close = async function close() { * @returns {Promise} */ -AsyncObject.prototype.__close = async function close() { +AsyncObject.prototype.__close = async function __close() { if (!this.loaded) return; @@ -190,16 +189,16 @@ AsyncObject.prototype.fire = async function fire() { */ AsyncObject.prototype.fireHook = async function fireHook(type) { - let listeners, args; - assert(typeof type === 'string', '`type` must be a string.'); - listeners = this._hooks[type]; + const listeners = this._hooks[type]; if (!listeners || listeners.length === 0) return; - for (let handler of listeners) { + let args; + + for (const handler of listeners) { switch (arguments.length) { case 1: await handler(); diff --git a/lib/utils/base32.js b/lib/utils/base32.js index b6c41f357..a70f4f92a 100644 --- a/lib/utils/base32.js +++ b/lib/utils/base32.js @@ -27,10 +27,9 @@ exports.encode = function encode(data) { let str = ''; let mode = 0; let left = 0; - let i, ch; - for (i = 0; i < data.length; i++) { - ch = data[i]; + for (let i = 0; i < data.length; i++) { + const ch = data[i]; switch (mode) { case 0: str += base32[ch >>> 3]; @@ -64,7 +63,7 @@ exports.encode = function encode(data) { if (mode > 0) { str += base32[left]; - for (i = 0; i < padding[mode]; i++) + for (let i = 0; i < padding[mode]; i++) str += '='; } @@ -78,14 +77,14 @@ exports.encode = function encode(data) { */ exports.decode = function decode(str) { - let data = Buffer.allocUnsafe(str.length * 5 / 8 | 0); + const data = Buffer.allocUnsafe(str.length * 5 / 8 | 0); let mode = 0; let left = 0; let j = 0; - let i, ch; + let i; for (i = 0; i < str.length; i++) { - ch = unbase32[str[i]]; + const ch = unbase32[str[i]]; if (ch == null) break; diff --git a/lib/utils/base58.js b/lib/utils/base58.js index 235d3690a..5ef9baf2a 100644 --- a/lib/utils/base58.js +++ b/lib/utils/base58.js @@ -37,24 +37,24 @@ for (let i = 0; i < base58.length; i++) exports.encode = function encode(data) { let zeroes = 0; - let length = 0; - let str = ''; - let i, b58, carry, j, k; + let i = 0; - for (i = 0; i < data.length; i++) { + for (; i < data.length; i++) { if (data[i] !== 0) break; zeroes++; } - b58 = Buffer.allocUnsafe(((data.length * 138 / 100) | 0) + 1); + const b58 = Buffer.allocUnsafe(((data.length * 138 / 100) | 0) + 1); b58.fill(0); + let length = 0; + for (; i < data.length; i++) { - carry = data[i]; - j = 0; + let carry = data[i]; + let j = 0; - for (k = b58.length - 1; k >= 0; k--, j++) { + for (let k = b58.length - 1; k >= 0; k--, j++) { if (carry === 0 && j >= length) break; carry += 256 * b58[k]; @@ -70,7 +70,9 @@ exports.encode = function encode(data) { while (i < b58.length && b58[i] === 0) i++; - for (j = 0; j < zeroes; j++) + let str = ''; + + for (let j = 0; j < zeroes; j++) str += '1'; for (; i < b58.length; i++) @@ -92,28 +94,29 @@ if (native) exports.decode = function decode(str) { let zeroes = 0; - let length = 0; let i = 0; - let b256, ch, carry, j, k, out; - for (i = 0; i < str.length; i++) { + for (; i < str.length; i++) { if (str[i] !== '1') break; zeroes++; } - b256 = Buffer.allocUnsafe(((str.length * 733) / 1000 | 0) + 1); + const b256 = Buffer.allocUnsafe(((str.length * 733) / 1000 | 0) + 1); b256.fill(0); + let length = 0; + for (; i < str.length; i++) { - ch = unbase58[str[i]]; + const ch = unbase58[str[i]]; + if (ch == null) throw new Error('Non-base58 character.'); - carry = ch; - j = 0; + let carry = ch; + let j = 0; - for (k = b256.length - 1; k >= 0; k--, j++) { + for (let k = b256.length - 1; k >= 0; k--, j++) { if (carry === 0 && j >= length) break; carry += 58 * b256[k]; @@ -129,8 +132,9 @@ exports.decode = function decode(str) { while (i < b256.length && b256[i] === 0) i++; - out = Buffer.allocUnsafe(zeroes + (b256.length - i)); + const out = Buffer.allocUnsafe(zeroes + (b256.length - i)); + let j; for (j = 0; j < zeroes; j++) out[j] = 0; diff --git a/lib/utils/bech32.js b/lib/utils/bech32.js index f827de096..b4d08df69 100644 --- a/lib/utils/bech32.js +++ b/lib/utils/bech32.js @@ -56,7 +56,7 @@ const TABLE = [ */ function polymod(pre) { - let b = pre >>> 25; + const b = pre >>> 25; return ((pre & 0x1ffffff) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2) ^ (-((b >> 1) & 1) & 0x26508e6d) @@ -74,12 +74,11 @@ function polymod(pre) { */ function serialize(hrp, data) { - let str = ''; let chk = 1; - let i, ch; + let i; for (i = 0; i < hrp.length; i++) { - ch = hrp.charCodeAt(i); + const ch = hrp.charCodeAt(i); if ((ch >> 5) === 0) throw new Error('Invalid bech32 character.'); @@ -92,16 +91,18 @@ function serialize(hrp, data) { chk = polymod(chk); - for (i = 0; i < hrp.length; i++) { - ch = hrp.charCodeAt(i); + let str = ''; + + for (let i = 0; i < hrp.length; i++) { + const ch = hrp.charCodeAt(i); chk = polymod(chk) ^ (ch & 0x1f); str += hrp[i]; } str += '1'; - for (i = 0; i < data.length; i++) { - ch = data[i]; + for (let i = 0; i < data.length; i++) { + const ch = data[i]; if ((ch >> 5) !== 0) throw new Error('Invalid bech32 value.'); @@ -110,12 +111,12 @@ function serialize(hrp, data) { str += CHARSET[ch]; } - for (i = 0; i < 6; i++) + for (let i = 0; i < 6; i++) chk = polymod(chk); chk ^= 1; - for (i = 0; i < 6; i++) + for (let i = 0; i < 6; i++) str += CHARSET[(chk >>> ((5 - i) * 5)) & 0x1f]; return str; @@ -128,12 +129,7 @@ function serialize(hrp, data) { */ function deserialize(str) { - let chk = 1; - let lower = false; - let upper = false; - let hrp = ''; let dlen = 0; - let i, hlen, ch, v, data; if (str.length < 8 || str.length > 90) throw new Error('Invalid bech32 string length.'); @@ -141,16 +137,22 @@ function deserialize(str) { while (dlen < str.length && str[(str.length - 1) - dlen] !== '1') dlen++; - hlen = str.length - (1 + dlen); + const hlen = str.length - (1 + dlen); if (hlen < 1 || dlen < 6) throw new Error('Invalid bech32 data length.'); dlen -= 6; - data = Buffer.allocUnsafe(dlen); - for (i = 0; i < hlen; i++) { - ch = str.charCodeAt(i); + const data = Buffer.allocUnsafe(dlen); + + let chk = 1; + let lower = false; + let upper = false; + let hrp = ''; + + for (let i = 0; i < hlen; i++) { + let ch = str.charCodeAt(i); if (ch < 0x21 || ch > 0x7e) throw new Error('Invalid bech32 character.'); @@ -168,14 +170,15 @@ function deserialize(str) { chk = polymod(chk); + let i; for (i = 0; i < hlen; i++) chk = polymod(chk) ^ (str.charCodeAt(i) & 0x1f); i++; while (i < str.length) { - ch = str.charCodeAt(i); - v = (ch & 0x80) ? -1 : TABLE[ch]; + const ch = str.charCodeAt(i); + const v = (ch & 0x80) ? -1 : TABLE[ch]; if (ch >= 0x61 && ch <= 0x7a) lower = true; @@ -215,17 +218,16 @@ function deserialize(str) { */ function convert(data, output, frombits, tobits, pad, off) { + const maxv = (1 << tobits) - 1; let acc = 0; let bits = 0; - let maxv = (1 << tobits) - 1; let j = 0; - let i, value; if (pad !== -1) output[j++] = pad; - for (i = off; i < data.length; i++) { - value = data[i]; + for (let i = off; i < data.length; i++) { + const value = data[i]; if ((value >> frombits) !== 0) throw new Error('Invalid bech32 bits.'); @@ -259,8 +261,7 @@ function convert(data, output, frombits, tobits, pad, off) { */ function encode(hrp, version, hash) { - let output = POOL65; - let data; + const output = POOL65; if (version < 0 || version > 16) throw new Error('Invalid bech32 version.'); @@ -268,7 +269,7 @@ function encode(hrp, version, hash) { if (hash.length < 2 || hash.length > 40) throw new Error('Invalid bech32 data length.'); - data = convert(hash, output, 8, 5, version, 0); + const data = convert(hash, output, 8, 5, version, 0); return serialize(hrp, data); } @@ -283,8 +284,7 @@ if (native) */ function decode(str) { - let [hrp, data] = deserialize(str); - let version, hash, output; + const [hrp, data] = deserialize(str); if (data.length === 0 || data.length > 65) throw new Error('Invalid bech32 data length.'); @@ -292,9 +292,9 @@ function decode(str) { if (data[0] > 16) throw new Error('Invalid bech32 version.'); - version = data[0]; - output = data; - hash = convert(data, output, 5, 8, -1, 1); + const version = data[0]; + const output = data; + const hash = convert(data, output, 5, 8, -1, 1); if (hash.length < 2 || hash.length > 40) throw new Error('Invalid bech32 data length.'); diff --git a/lib/utils/bloom.js b/lib/utils/bloom.js index fe7a6181b..1452bc596 100644 --- a/lib/utils/bloom.js +++ b/lib/utils/bloom.js @@ -117,15 +117,13 @@ Bloom.flagsByVal = { */ Bloom.prototype.fromOptions = function fromOptions(size, n, tweak, update) { - let filter; - assert(typeof size === 'number', '`size` must be a number.'); assert(size > 0, '`size` must be greater than zero.'); - assert(size % 1 === 0, '`size` must be an integer.'); + assert(Number.isSafeInteger(size), '`size` must be an integer.'); size -= size % 8; - filter = Buffer.allocUnsafe(size / 8); + const filter = Buffer.allocUnsafe(size / 8); filter.fill(0); if (tweak == null || tweak === -1) @@ -141,9 +139,9 @@ Bloom.prototype.fromOptions = function fromOptions(size, n, tweak, update) { assert(size > 0, '`size` must be greater than zero.'); assert(n > 0, '`n` must be greater than zero.'); - assert(n % 1 === 0, '`n` must be an integer.'); + assert(Number.isSafeInteger(n), '`n` must be an integer.'); assert(typeof tweak === 'number', '`tweak` must be a number.'); - assert(tweak % 1 === 0, '`tweak` must be an integer.'); + assert(Number.isSafeInteger(tweak), '`tweak` must be an integer.'); assert(Bloom.flagsByVal[update], 'Unknown update flag.'); this.filter = filter; @@ -198,7 +196,7 @@ Bloom.prototype.add = function add(val, enc) { val = Buffer.from(val, enc); for (let i = 0; i < this.n; i++) { - let index = this.hash(val, i); + const index = this.hash(val, i); this.filter[index >>> 3] |= 1 << (7 & index); } }; @@ -215,7 +213,7 @@ Bloom.prototype.test = function test(val, enc) { val = Buffer.from(val, enc); for (let i = 0; i < this.n; i++) { - let index = this.hash(val, i); + const index = this.hash(val, i); if ((this.filter[index >>> 3] & (1 << (7 & index))) === 0) return false; } @@ -238,7 +236,7 @@ Bloom.prototype.added = function added(val, enc) { val = Buffer.from(val, enc); for (let i = 0; i < this.n; i++) { - let index = this.hash(val, i); + const index = this.hash(val, i); if (!ret && (this.filter[index >>> 3] & (1 << (7 & index))) === 0) ret = true; this.filter[index >>> 3] |= 1 << (7 & index); @@ -258,23 +256,21 @@ Bloom.prototype.added = function added(val, enc) { */ Bloom.fromRate = function fromRate(items, rate, update) { - let size, n; - assert(typeof items === 'number', '`items` must be a number.'); assert(items > 0, '`items` must be greater than zero.'); - assert(items % 1 === 0, '`items` must be an integer.'); + assert(Number.isSafeInteger(items), '`items` must be an integer.'); assert(typeof rate === 'number', '`rate` must be a number.'); assert(rate >= 0 && rate <= 1, '`rate` must be between 0.0 and 1.0.'); - size = (-1 / LN2SQUARED * items * Math.log(rate)) | 0; - size = Math.max(8, size); + const bits = (-1 / LN2SQUARED * items * Math.log(rate)) | 0; + const size = Math.max(8, bits); if (update !== -1) { assert(size <= Bloom.MAX_BLOOM_FILTER_SIZE * 8, 'Bloom filter size violates policy limits!'); } - n = Math.max(1, (size / items * LN2) | 0); + const n = Math.max(1, (size / items * LN2) | 0); if (update !== -1) { assert(n <= Bloom.MAX_HASH_FUNCS, @@ -327,7 +323,7 @@ Bloom.prototype.toWriter = function toWriter(bw) { */ Bloom.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; diff --git a/lib/utils/co.js b/lib/utils/co.js index a3ef99cc6..20b24e1d8 100644 --- a/lib/utils/co.js +++ b/lib/utils/co.js @@ -21,7 +21,7 @@ const assert = require('assert'); function exec(gen) { return new Promise((resolve, reject) => { - let step = (value, rejection) => { + const step = (value, rejection) => { let next; try { @@ -44,14 +44,15 @@ function exec(gen) { return; } + // eslint-disable-next-line no-use-before-define next.value.then(succeed, fail); }; - let succeed = (value) => { + const succeed = (value) => { step(value, false); }; - let fail = (value) => { + const fail = (value) => { step(value, true); }; @@ -68,7 +69,7 @@ function exec(gen) { */ function spawn(generator, self) { - let gen = generator.call(self); + const gen = generator.call(self); return exec(gen); } @@ -82,7 +83,7 @@ function spawn(generator, self) { function co(generator) { return function() { - let gen = generator.apply(this, arguments); + const gen = generator.apply(this, arguments); return exec(gen); }; } @@ -103,7 +104,7 @@ function isPromise(obj) { */ function wait() { - return new Promise((resolve) => setImmediate(resolve)); + return new Promise(resolve => setImmediate(resolve)); }; /** @@ -113,7 +114,7 @@ function wait() { */ function timeout(time) { - return new Promise((resolve) => setTimeout(resolve, time)); + return new Promise(resolve => setTimeout(resolve, time)); } /** @@ -161,14 +162,12 @@ function promisify(func) { function callbackify(func) { return function(...args) { - let callback; - if (args.length === 0 || typeof args[args.length - 1] !== 'function') { throw new Error(`${func.name || 'Function'} requires a callback.`); } - callback = args.pop(); + const callback = args.pop(); func.call(this, ...args).then((value) => { setImmediate(() => callback(null, value)); @@ -187,9 +186,9 @@ function callbackify(func) { */ async function every(jobs) { - let result = await Promise.all(jobs); + const result = await Promise.all(jobs); - for (let item of result) { + for (const item of result) { if (!item) return false; } @@ -207,12 +206,12 @@ async function every(jobs) { */ function startInterval(func, time, self) { - let ctx = { + const ctx = { timer: null, stopped: false }; - let cb = async () => { + const cb = async () => { assert(ctx.timer != null); ctx.timer = null; diff --git a/lib/utils/encoding.js b/lib/utils/encoding.js index 2176f8081..87253d2c0 100644 --- a/lib/utils/encoding.js +++ b/lib/utils/encoding.js @@ -11,7 +11,8 @@ * @module utils/encoding */ -const BN = require('bn.js'); +const {U64, I64} = require('./int64'); +const UINT128_MAX = U64.UINT64_MAX.shrn(7); const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; const encoding = exports; @@ -254,7 +255,7 @@ encoding.readU53BE = function readU53BE(data, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding._read64 = function _read64(data, off, force53, be) { +encoding._readI64 = function _readI64(data, off, force53, be) { let hi, lo; if (be) { @@ -293,8 +294,8 @@ encoding._read64 = function _read64(data, off, force53, be) { * @throws on num > MAX_SAFE_INTEGER */ -encoding.read64 = function read64(data, off) { - return encoding._read64(data, off, false, false); +encoding.readI64 = function readI64(data, off) { + return encoding._readI64(data, off, false, false); }; /** @@ -305,8 +306,8 @@ encoding.read64 = function read64(data, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding.read64BE = function read64BE(data, off) { - return encoding._read64(data, off, false, true); +encoding.readI64BE = function readI64BE(data, off) { + return encoding._readI64(data, off, false, true); }; /** @@ -317,8 +318,8 @@ encoding.read64BE = function read64BE(data, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding.read53 = function read53(data, off) { - return encoding._read64(data, off, true, false); +encoding.readI53 = function readI53(data, off) { + return encoding._readI64(data, off, true, false); }; /** @@ -329,8 +330,8 @@ encoding.read53 = function read53(data, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding.read53BE = function read53BE(data, off) { - return encoding._read64(data, off, true, true); +encoding.readI53BE = function readI53BE(data, off) { + return encoding._readI64(data, off, true, true); }; /** @@ -344,21 +345,20 @@ encoding.read53BE = function read53BE(data, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding._write64 = function _write64(dst, num, off, be) { - let negative = num < 0; - let hi, lo; +encoding._writeI64 = function _writeI64(dst, num, off, be) { + const neg = num < 0; - if (negative) { + if (neg) { num = -num; num -= 1; } enforce(num <= MAX_SAFE_INTEGER, off, 'Number exceeds 2^53-1'); - hi = (num * (1 / 0x100000000)) | 0; - lo = num | 0; + let hi = (num * (1 / 0x100000000)) | 0; + let lo = num | 0; - if (negative) { + if (neg) { hi = ~hi; lo = ~lo; } @@ -398,7 +398,7 @@ encoding._write64 = function _write64(dst, num, off, be) { */ encoding.writeU64 = function writeU64(dst, num, off) { - return encoding._write64(dst, num, off, false); + return encoding._writeI64(dst, num, off, false); }; /** @@ -411,7 +411,7 @@ encoding.writeU64 = function writeU64(dst, num, off) { */ encoding.writeU64BE = function writeU64BE(dst, num, off) { - return encoding._write64(dst, num, off, true); + return encoding._writeI64(dst, num, off, true); }; /** @@ -423,8 +423,8 @@ encoding.writeU64BE = function writeU64BE(dst, num, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding.write64 = function write64(dst, num, off) { - return encoding._write64(dst, num, off, false); +encoding.writeI64 = function writeI64(dst, num, off) { + return encoding._writeI64(dst, num, off, false); }; /** @@ -436,141 +436,103 @@ encoding.write64 = function write64(dst, num, off) { * @throws on num > MAX_SAFE_INTEGER */ -encoding.write64BE = function write64BE(dst, num, off) { - return encoding._write64(dst, num, off, true); +encoding.writeI64BE = function writeI64BE(dst, num, off) { + return encoding._writeI64(dst, num, off, true); }; /** * Read uint64le. * @param {Buffer} data * @param {Number} off - * @returns {BN} + * @returns {U64} */ -encoding.readU64BN = function readU64BN(data, off) { - let num = data.slice(off, off + 8); - return new BN(num, 'le'); +encoding.readU64N = function readU64N(data, off) { + return U64.readLE(data, off); }; /** * Read uint64be. * @param {Buffer} data * @param {Number} off - * @returns {BN} + * @returns {U64} */ -encoding.readU64BEBN = function readU64BEBN(data, off) { - let num = data.slice(off, off + 8); - return new BN(num, 'be'); +encoding.readU64BEN = function readU64BEN(data, off) { + return U64.readBE(data, off); }; /** * Read int64le. * @param {Buffer} data * @param {Number} off - * @returns {BN} + * @returns {I64} */ -encoding.read64BN = function read64BN(data, off) { - let num = data.slice(off, off + 8); - - if (num[num.length - 1] & 0x80) - return new BN(num, 'le').notn(64).addn(1).neg(); - - return new BN(num, 'le'); +encoding.readI64N = function readI64N(data, off) { + return I64.readLE(data, off); }; /** * Read int64be. * @param {Buffer} data * @param {Number} off - * @returns {BN} - */ - -encoding.read64BEBN = function read64BEBN(data, off) { - let num = data.slice(off, off + 8); - - if (num[0] & 0x80) - return new BN(num, 'be').notn(64).addn(1).neg(); - - return new BN(num, 'be'); -}; - -/** - * Write int64le. - * @private - * @param {Buffer} dst - * @param {BN} num - * @param {Number} off - * @param {Boolean} be - * @returns {Number} Buffer offset. + * @returns {I64} */ -encoding._write64BN = function _write64BN(dst, num, off, be) { - let bits = num.bitLength(); - - if (bits <= 53) - return encoding._write64(dst, num.toNumber(), off, be); - - if (bits > 64) - num = num.maskn(64); - - if (num.isNeg()) - num = num.neg().inotn(64).iaddn(1); - - num = num.toArray(be ? 'be' : 'le', 8); - - for (let i = 0; i < num.length; i++) - dst[off++] = num[i]; - - return off; +encoding.readI64BEN = function readI64BEN(data, off) { + return I64.readBE(data, off); }; /** * Write uint64le. * @param {Buffer} dst - * @param {BN} num + * @param {U64} num * @param {Number} off * @returns {Number} Buffer offset. */ -encoding.writeU64BN = function writeU64BN(dst, num, off) { - return encoding._write64BN(dst, num, off, false); +encoding.writeU64N = function writeU64N(dst, num, off) { + enforce(!num.sign, off, 'Signed'); + return num.writeLE(dst, off); }; /** * Write uint64be. * @param {Buffer} dst - * @param {BN} num + * @param {U64} num * @param {Number} off * @returns {Number} Buffer offset. */ -encoding.writeU64BEBN = function writeU64BEBN(dst, num, off) { - return encoding._write64BN(dst, num, off, true); +encoding.writeU64BEN = function writeU64BEN(dst, num, off) { + enforce(!num.sign, off, 'Signed'); + return num.writeBE(dst, off); }; /** * Write int64le. * @param {Buffer} dst - * @param {BN} num + * @param {U64} num * @param {Number} off * @returns {Number} Buffer offset. */ -encoding.write64BN = function write64BN(dst, num, off) { - return encoding._write64BN(dst, num, off, false); +encoding.writeI64N = function writeI64N(dst, num, off) { + enforce(num.sign, off, 'Not signed'); + return num.writeLE(dst, off); }; /** * Write int64be. * @param {Buffer} dst - * @param {BN} num + * @param {I64} num * @param {Number} off * @returns {Number} Buffer offset. */ -encoding.write64BEBN = function write64BEBN(dst, num, off) { - return encoding._write64BN(dst, num, off, true); +encoding.writeI64BEN = function writeI64BEN(dst, num, off) { + enforce(num.sign, off, 'Not signed'); + return num.writeBE(dst, off); }; /** @@ -696,54 +658,54 @@ encoding.sizeVarint = function sizeVarint(num) { * @returns {Object} */ -encoding.readVarintBN = function readVarintBN(data, off) { - let result, value, size; - +encoding.readVarintN = function readVarintN(data, off) { assert(off < data.length, off); - switch (data[off]) { - case 0xff: - size = 9; - assert(off + size <= data.length, off); - value = encoding.readU64BN(data, off + 1); - enforce(value.bitLength() > 32, off, 'Non-canonical varint'); - return new Varint(size, value); - default: - result = encoding.readVarint(data, off); - result.value = new BN(result.value); - return result; + if (data[off] === 0xff) { + const size = 9; + assert(off + size <= data.length, off); + const value = encoding.readU64N(data, off + 1); + enforce(value.gtn(0xffffffff), off, 'Non-canonical varint'); + return new Varint(size, value); } + + const result = encoding.readVarint(data, off); + result.value = U64.fromInt(result.value); + return result; }; /** * Write a varint. * @param {Buffer} dst - * @param {BN} num + * @param {U64} num * @param {Number} off * @returns {Number} Buffer offset. */ -encoding.writeVarintBN = function writeVarintBN(dst, num, off) { - if (num.bitLength() > 32) { +encoding.writeVarintN = function writeVarintN(dst, num, off) { + enforce(!num.sign, off, 'Signed'); + + if (num.hi !== 0) { dst[off++] = 0xff; - off = encoding.writeU64BN(dst, num, off); - return off; + return encoding.writeU64N(dst, num, off); } - return encoding.writeVarint(dst, num.toNumber(), off); + return encoding.writeVarint(dst, num.toInt(), off); }; /** * Calculate size of varint. - * @param {BN} num + * @param {U64} num * @returns {Number} size */ -encoding.sizeVarintBN = function sizeVarintBN(num) { - if (num.bitLength() > 32) +encoding.sizeVarintN = function sizeVarintN(num) { + enforce(!num.sign, 0, 'Signed'); + + if (num.hi !== 0) return 9; - return encoding.sizeVarint(num.toNumber()); + return encoding.sizeVarint(num.toInt()); }; /** @@ -756,21 +718,23 @@ encoding.sizeVarintBN = function sizeVarintBN(num) { encoding.readVarint2 = function readVarint2(data, off) { let num = 0; let size = 0; - let ch; for (;;) { assert(off < data.length, off); - ch = data[off++]; + const ch = data[off++]; size++; - enforce(num < 0x3fffffffffff, off, 'Number exceeds 2^53-1'); + // Number.MAX_SAFE_INTEGER >>> 7 + enforce(num <= 0x3fffffffffff - (ch & 0x7f), off, 'Number exceeds 2^53-1'); + // num = (num << 7) | (ch & 0x7f); num = (num * 0x80) + (ch & 0x7f); if ((ch & 0x80) === 0) break; + enforce(num !== MAX_SAFE_INTEGER, off, 'Number exceeds 2^53-1'); num++; } @@ -786,18 +750,20 @@ encoding.readVarint2 = function readVarint2(data, off) { */ encoding.writeVarint2 = function writeVarint2(dst, num, off) { - let tmp = []; + const tmp = []; + let len = 0; for (;;) { tmp[len] = (num & 0x7f) | (len ? 0x80 : 0x00); if (num <= 0x7f) break; + // num = (num >>> 7) - 1; num = ((num - (num % 0x80)) / 0x80) - 1; len++; } - assert(off + len <= dst.length, off); + assert(off + len + 1 <= dst.length, off); do { dst[off++] = tmp[len]; @@ -815,11 +781,10 @@ encoding.writeVarint2 = function writeVarint2(dst, num, off) { encoding.skipVarint2 = function skipVarint2(data, off) { let size = 0; - let ch; for (;;) { assert(off < data.length, off); - ch = data[off++]; + const ch = data[off++]; size++; if ((ch & 0x80) === 0) break; @@ -841,6 +806,7 @@ encoding.sizeVarint2 = function sizeVarint2(num) { size++; if (num <= 0x7f) break; + // num = (num >>> 7) - 1; num = ((num - (num % 0x80)) / 0x80) - 1; } @@ -854,40 +820,25 @@ encoding.sizeVarint2 = function sizeVarint2(num) { * @returns {Object} */ -encoding.readVarint2BN = function readVarint2BN(data, off) { - let num = 0; - let size = 0; - let ch; - - while (num < 0x3fffffffffff) { - assert(off < data.length, off); - - ch = data[off++]; - size++; - - num = (num * 0x80) + (ch & 0x7f); - - if ((ch & 0x80) === 0) - return new Varint(size, new BN(num)); - - num++; - } +encoding.readVarint2N = function readVarint2N(data, off) { + const num = new U64(); - num = new BN(num); + let size = 0; for (;;) { assert(off < data.length, off); - ch = data[off++]; + const ch = data[off++]; size++; - enforce(num.bitLength() <= 64, off, 'Number exceeds 64 bits'); + enforce(num.lte(UINT128_MAX), off, 'Number exceeds 2^64-1'); - num.iushln(7).iaddn(ch & 0x7f); + num.ishln(7).iorn(ch & 0x7f); if ((ch & 0x80) === 0) break; + enforce(!num.eq(U64.UINT64_MAX), off, 'Number exceeds 2^64-1'); num.iaddn(1); } @@ -897,27 +848,32 @@ encoding.readVarint2BN = function readVarint2BN(data, off) { /** * Write a varint (type 2). * @param {Buffer} dst - * @param {BN} num + * @param {U64} num * @param {Number} off * @returns {Number} Buffer offset. */ -encoding.writeVarint2BN = function writeVarint2BN(dst, num, off) { - let tmp = []; - let len = 0; +encoding.writeVarint2N = function writeVarint2N(dst, num, off) { + enforce(!num.sign, off, 'Signed'); - if (num.bitLength() <= 53) - return encoding.writeVarint2(dst, num.toNumber()); + if (num.hi === 0) + return encoding.writeVarint2(dst, num.toInt(), off); + + num = num.clone(); + + const tmp = []; + + let len = 0; for (;;) { - tmp[len] = (num.words[0] & 0x7f) | (len ? 0x80 : 0x00); - if (num.cmpn(0x7f) <= 0) + tmp[len] = num.andln(0x7f) | (len ? 0x80 : 0x00); + if (num.lten(0x7f)) break; - num.iushrn(7).isubn(1); + num.ishrn(7).isubn(1); len++; } - enforce(off + len <= dst.length, off, 'Out of bounds write'); + enforce(off + len + 1 <= dst.length, off, 'Out of bounds write'); do { dst[off++] = tmp[len]; @@ -928,23 +884,25 @@ encoding.writeVarint2BN = function writeVarint2BN(dst, num, off) { /** * Calculate size of varint (type 2). - * @param {BN} num + * @param {U64} num * @returns {Number} size */ -encoding.sizeVarint2BN = function sizeVarint2BN(num) { - let size = 0; +encoding.sizeVarint2N = function sizeVarint2N(num) { + enforce(!num.sign, 0, 'Signed'); - if (num.bitLength() <= 53) - return encoding.sizeVarint(num.toNumber()); + if (num.hi === 0) + return encoding.sizeVarint2(num.toInt()); num = num.clone(); + let size = 0; + for (;;) { size++; - if (num.cmpn(0x7f) <= 0) + if (num.lten(0x7f)) break; - num.iushrn(7).isubn(1); + num.ishrn(7).isubn(1); } return size; @@ -957,7 +915,7 @@ encoding.sizeVarint2BN = function sizeVarint2BN(num) { */ encoding.U8 = function U8(num) { - let data = Buffer.allocUnsafe(1); + const data = Buffer.allocUnsafe(1); data[0] = num >>> 0; return data; }; @@ -969,7 +927,7 @@ encoding.U8 = function U8(num) { */ encoding.U32 = function U32(num) { - let data = Buffer.allocUnsafe(4); + const data = Buffer.allocUnsafe(4); data.writeUInt32LE(num, 0, true); return data; }; @@ -981,7 +939,7 @@ encoding.U32 = function U32(num) { */ encoding.U32BE = function U32BE(num) { - let data = Buffer.allocUnsafe(4); + const data = Buffer.allocUnsafe(4); data.writeUInt32BE(num, 0, true); return data; }; @@ -1013,12 +971,10 @@ encoding.sizeVarlen = function sizeVarlen(len) { */ encoding.sizeVarString = function sizeVarString(str, enc) { - let len; - if (typeof str !== 'string') return encoding.sizeVarBytes(str); - len = Buffer.byteLength(str, enc); + const len = Buffer.byteLength(str, enc); return encoding.sizeVarint(len) + len; }; @@ -1043,7 +999,7 @@ encoding.EncodingError = function EncodingError(offset, reason) { Error.captureStackTrace(this, EncodingError); }; -inherits(encoding.EncodingError, Error); +Object.setPrototypeOf(encoding.EncodingError.prototype, Error.prototype); /* * Helpers @@ -1054,15 +1010,6 @@ function Varint(size, value) { this.value = value; } -function inherits(child, parent) { - child.super_ = parent; - Object.setPrototypeOf(child.prototype, parent.prototype); - Object.defineProperty(child.prototype, 'constructor', { - value: child, - enumerable: false - }); -} - function enforce(value, offset, reason) { if (!value) throw new encoding.EncodingError(offset, reason); diff --git a/lib/utils/enforce.js b/lib/utils/enforce.js new file mode 100644 index 000000000..34b363bce --- /dev/null +++ b/lib/utils/enforce.js @@ -0,0 +1,165 @@ +/*! + * enforce.js - type enforcement for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +const util = require('./util'); + +function enforce(value, name, type, func) { + if (!value) { + if (!func) + func = enforce; + + if (name && !type) + throwError(name, func); + + if (!name) + name = 'value'; + + throwError(`'${name}' must be a(n) ${type}.`, func); + } +} + +function throwError(msg, func) { + const error = new TypeError(msg); + if (Error.captureStackTrace && func) + Error.captureStackTrace(error, func); + throw error; +} + +enforce.none = function none(value, name) { + enforce(value == null, name, 'object', none); +}; + +enforce.nul = function nul(value, name) { + enforce(value === null, name, 'object', nul); +}; + +enforce.undef = function undef(value, name) { + enforce(value === undefined, name, 'object', undef); +}; + +enforce.str = function str(value, name) { + enforce(typeof value === 'string', name, 'string', str); +}; + +enforce.bool = function bool(value, name) { + enforce(typeof value === 'boolean', name, 'boolean', bool); +}; + +enforce.num = function num(value, name) { + enforce(util.isNumber(value), name, 'number', num); +}; + +enforce.obj = function obj(v, name) { + enforce(v && typeof v === 'object' && !Array.isArray(v), name, 'object', obj); +}; + +enforce.array = function array(value, name) { + enforce(Array.isArray(value), name, 'object', array); +}; + +enforce.func = function func(value, name) { + enforce(typeof value === 'function', name, 'function', func); +}; + +enforce.error = function error(value, name) { + enforce(value instanceof Error, name, 'object', error); +}; + +enforce.regexp = function regexp(value, name) { + enforce(value && typeof value.exec === 'function' , name, 'object', regexp); +}; + +enforce.buf = function buf(value, name) { + enforce(Buffer.isBuffer(value), name, 'buffer', buf); +}; + +enforce.len = function len(value, length, name) { + if ((typeof value !== 'string' && !value) || value.length !== length) { + if (!name) + name = 'value'; + throwError(`'${name}' must have a length of ${length}.`, len); + } +}; + +enforce.instance = function instance(obj, parent, name) { + if (!(obj instanceof parent)) { + if (!name) + name = 'value'; + throwError(`'${name}' must be an instance of ${parent.name}.`, instance); + } +}; + +enforce.uint = function uint(value, name) { + enforce(util.isUInt(value), name, 'uint', uint); +}; + +enforce.int = function int(value, name) { + enforce(util.isInt(value), name, 'int', int); +}; + +enforce.u8 = function u8(value, name) { + enforce(util.isU8(value), name, 'uint8', u8); +}; + +enforce.u16 = function u16(value, name) { + enforce(util.isU16(value), name, 'uint16', u16); +}; + +enforce.u32 = function u32(value, name) { + enforce(util.isU32(value), name, 'uint32', u32); +}; + +enforce.u64 = function u64(value, name) { + enforce(util.isU64(value), name, 'uint64', u64); +}; + +enforce.i8 = function i8(value, name) { + enforce(util.isI8(value), name, 'int8', i8); +}; + +enforce.i16 = function i16(value, name) { + enforce(util.isI16(value), name, 'int16', i16); +}; + +enforce.i32 = function i32(value, name) { + enforce(util.isI32(value), name, 'int32', i32); +}; + +enforce.i64 = function i64(value, name) { + enforce(util.isI64(value), name, 'int64', i64); +}; + +enforce.ufloat = function ufloat(value, name) { + enforce(util.isUfloat(value), name, 'positive float', ufloat); +}; + +enforce.float = function float(value, name) { + enforce(util.isFloat(value), name, 'float', float); +}; + +enforce.ascii = function ascii(value, name) { + enforce(util.isAscii(value), name, 'ascii string', ascii); +}; + +enforce.hex = function hex(value, name) { + enforce(util.isHex(value), name, 'hex string', hex); +}; + +enforce.hex160 = function hex160(value, name) { + enforce(util.isHex160(value), name, '160 bit hex string', hex160); +}; + +enforce.hex256 = function hex256(value, name) { + enforce(util.isHex256(value), name, '256 bit hex string', hex256); +}; + +enforce.base58 = function base58(value, name) { + enforce(util.isBase58(value), name, 'base58 string', base58); +}; + +module.exports = enforce; diff --git a/lib/utils/fs.js b/lib/utils/fs.js index 0e35f3ecf..28f710675 100644 --- a/lib/utils/fs.js +++ b/lib/utils/fs.js @@ -85,16 +85,16 @@ exports.writeFile = co.promisify(fs.writeFile); exports.writeFileSync = fs.writeFileSync; exports.mkdirpSync = function mkdirpSync(dir, mode) { - let [path, parts] = getParts(dir); - if (mode == null) mode = 0o750; - for (let part of parts) { + let [path, parts] = getParts(dir); + + for (const part of parts) { path += part; try { - let stat = exports.statSync(path); + const stat = exports.statSync(path); if (!stat.isDirectory()) throw new Error('Could not create directory.'); } catch (e) { @@ -109,16 +109,16 @@ exports.mkdirpSync = function mkdirpSync(dir, mode) { }; exports.mkdirp = async function mkdirp(dir, mode) { - let [path, parts] = getParts(dir); - if (mode == null) mode = 0o750; - for (let part of parts) { + let [path, parts] = getParts(dir); + + for (const part of parts) { path += part; try { - let stat = await exports.stat(path); + const stat = await exports.stat(path); if (!stat.isDirectory()) throw new Error('Could not create directory.'); } catch (e) { @@ -133,13 +133,13 @@ exports.mkdirp = async function mkdirp(dir, mode) { }; function getParts(path) { - let root = ''; - let parts; - path = path.replace(/\\/g, '/'); path = path.replace(/(^|\/)\.\//, '$1'); path = path.replace(/\/+\.?$/, ''); - parts = path.split(/\/+/); + + const parts = path.split(/\/+/); + + let root = ''; if (process.platform === 'win32') { if (parts[0].indexOf(':') !== -1) diff --git a/lib/utils/gcs.js b/lib/utils/gcs.js index b11335472..a0881190b 100644 --- a/lib/utils/gcs.js +++ b/lib/utils/gcs.js @@ -7,12 +7,11 @@ 'use strict'; const assert = require('assert'); -const Int64 = require('./int64'); +const {U64} = require('./int64'); const digest = require('../crypto/digest'); -const siphash24 = require('../crypto/siphash'); -const SCRATCH = Buffer.allocUnsafe(64); -const DUMMY = Buffer.allocUnsafe(0); -const EOF = new Int64(-1); +const siphash = require('../crypto/siphash'); +const DUMMY = Buffer.alloc(0); +const EOF = new U64(-1); /** * GCSFilter @@ -23,30 +22,26 @@ const EOF = new Int64(-1); function GCSFilter() { this.n = 0; this.p = 0; - this.m = new Int64(0); + this.m = new U64(0); this.data = DUMMY; } -GCSFilter.prototype.hash = function _hash(enc) { - let hash = digest.hash256(this.data); - return enc === 'hex' ? hash.toString('hex') : hash; +GCSFilter.prototype.hash = function hash(enc) { + const h = digest.hash256(this.data); + return enc === 'hex' ? h.toString('hex') : h; }; GCSFilter.prototype.header = function header(prev) { - let data = SCRATCH; - let hash = this.hash(); - hash.copy(data, 0); - prev.copy(data, 32); - return digest.hash256(data); + return digest.root256(this.hash(), prev); }; GCSFilter.prototype.match = function match(key, data) { - let br = new BitReader(this.data); - let term = siphash(data, key).imod(this.m); - let last = new Int64(0); + const br = new BitReader(this.data); + const term = siphash24(data, key).imod(this.m); + let last = new U64(0); while (last.lt(term)) { - let value = this.readU64(br); + const value = this.readU64(br); if (value === EOF) return false; @@ -63,26 +58,24 @@ GCSFilter.prototype.match = function match(key, data) { }; GCSFilter.prototype.matchAny = function matchAny(key, items) { - let br = new BitReader(this.data); - let last1 = new Int64(0); - let values = []; - let i, last2; - assert(items.length > 0); - for (let item of items) { - let hash = siphash(item, key).imod(this.m); + const br = new BitReader(this.data); + const last1 = new U64(0); + const values = []; + + for (const item of items) { + const hash = siphash24(item, key).imod(this.m); values.push(hash); } values.sort(compare); - last2 = values[0]; - i = 1; + let last2 = values[0]; + let i = 1; for (;;) { - let cmp = last1.cmp(last2); - let value; + const cmp = last1.cmp(last2); if (cmp === 0) break; @@ -96,7 +89,7 @@ GCSFilter.prototype.matchAny = function matchAny(key, items) { return false; } - value = this.readU64(br); + const value = this.readU64(br); if (value === EOF) return false; @@ -118,14 +111,13 @@ GCSFilter.prototype.readU64 = function readU64(br) { }; GCSFilter.prototype._readU64 = function _readU64(br) { - let num = new Int64(0); - let rem; + const num = new U64(0); // Unary while (br.readBit()) num.iaddn(1); - rem = br.readBits64(this.p); + const rem = br.readBits64(this.p); return num.ishln(this.p).ior(rem); }; @@ -135,21 +127,21 @@ GCSFilter.prototype.toBytes = function toBytes() { }; GCSFilter.prototype.toNBytes = function toNBytes() { - let data = Buffer.allocUnsafe(4 + this.data.length); + const data = Buffer.allocUnsafe(4 + this.data.length); data.writeUInt32BE(this.n, 0, true); this.data.copy(data, 4); return data; }; GCSFilter.prototype.toPBytes = function toPBytes() { - let data = Buffer.allocUnsafe(1 + this.data.length); + const data = Buffer.allocUnsafe(1 + this.data.length); data.writeUInt8(this.p, 0, true); this.data.copy(data, 1); return data; }; GCSFilter.prototype.toNPBytes = function toNPBytes() { - let data = Buffer.allocUnsafe(5 + this.data.length); + const data = Buffer.allocUnsafe(5 + this.data.length); data.writeUInt32BE(this.n, 0, true); data.writeUInt8(this.p, 4, true); this.data.copy(data, 5); @@ -162,10 +154,6 @@ GCSFilter.prototype.toRaw = function toRaw() { }; GCSFilter.prototype.fromItems = function fromItems(P, key, items) { - let bw = new BitWriter(); - let last = new Int64(0); - let values = []; - assert(typeof P === 'number' && isFinite(P)); assert(P >= 0 && P <= 32); @@ -178,19 +166,24 @@ GCSFilter.prototype.fromItems = function fromItems(P, key, items) { this.n = items.length; this.p = P; - this.m = Int64(this.n).ishln(this.p); + this.m = U64(this.n).ishln(this.p); - for (let item of items) { + const values = []; + + for (const item of items) { assert(Buffer.isBuffer(item)); - let hash = siphash(item, key).imod(this.m); + const hash = siphash24(item, key).imod(this.m); values.push(hash); } values.sort(compare); - for (let hash of values) { - let rem = hash.sub(last).imaskn(this.p); - let value = hash.sub(last).isub(rem).ishrn(this.p); + const bw = new BitWriter(); + let last = new U64(0); + + for (const hash of values) { + const rem = hash.sub(last).imaskn(this.p); + const value = hash.sub(last).isub(rem).ishrn(this.p); last = hash; @@ -217,44 +210,38 @@ GCSFilter.prototype.fromBytes = function fromBytes(N, P, data) { this.n = N; this.p = P; - this.m = Int64(this.n).ishln(this.p); + this.m = U64(this.n).ishln(this.p); this.data = data; return this; }; GCSFilter.prototype.fromNBytes = function fromNBytes(P, data) { - let N; - assert(typeof P === 'number' && isFinite(P)); assert(Buffer.isBuffer(data)); assert(data.length >= 4); - N = data.readUInt32BE(0, true); + const N = data.readUInt32BE(0, true); return this.fromBytes(N, P, data.slice(4)); }; GCSFilter.prototype.fromPBytes = function fromPBytes(N, data) { - let P; - assert(typeof N === 'number' && isFinite(N)); assert(Buffer.isBuffer(data)); assert(data.length >= 1); - P = data.readUInt8(0, true); + const P = data.readUInt8(0, true); return this.fromBytes(N, P, data.slice(1)); }; GCSFilter.prototype.fromNPBytes = function fromNPBytes(data) { - let N, P; - assert(Buffer.isBuffer(data)); assert(data.length >= 5); - N = data.readUInt32BE(0, true); - P = data.readUInt8(4, true); + const N = data.readUInt32BE(0, true); + const P = data.readUInt8(4, true); return this.fromBytes(N, P, data.slice(5)); }; @@ -264,19 +251,19 @@ GCSFilter.prototype.fromRaw = function fromRaw(data) { }; GCSFilter.prototype.fromBlock = function fromBlock(block) { - let hash = block.hash(); - let key = hash.slice(0, 16); - let items = []; + const hash = block.hash(); + const key = hash.slice(0, 16); + const items = []; for (let i = 0; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; if (i > 0) { - for (let input of tx.inputs) + for (const input of tx.inputs) items.push(input.prevout.toRaw()); } - for (let output of tx.outputs) + for (const output of tx.outputs) getPushes(items, output.script); } @@ -284,17 +271,17 @@ GCSFilter.prototype.fromBlock = function fromBlock(block) { }; GCSFilter.prototype.fromExtended = function fromExtended(block) { - let hash = block.hash(); - let key = hash.slice(0, 16); - let items = []; + const hash = block.hash(); + const key = hash.slice(0, 16); + const items = []; for (let i = 0; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; items.push(tx.hash()); if (i > 0) { - for (let input of tx.inputs) { + for (const input of tx.inputs) { getWitness(items, input.witness); getPushes(items, input.script); } @@ -348,15 +335,13 @@ function BitWriter() { } BitWriter.prototype.writeBit = function writeBit(bit) { - let index; - if (this.remain === 0) { this.stream.push(0); this.remain = 8; } if (bit) { - index = this.stream.length - 1; + const index = this.stream.length - 1; this.stream[index] |= 1 << (this.remain - 1); } @@ -364,14 +349,12 @@ BitWriter.prototype.writeBit = function writeBit(bit) { }; BitWriter.prototype.writeByte = function writeByte(ch) { - let index; - if (this.remain === 0) { this.stream.push(0); this.remain = 8; } - index = this.stream.length - 1; + const index = this.stream.length - 1; this.stream[index] |= (ch >> (8 - this.remain)) & 0xff; this.stream.push(0); @@ -385,14 +368,14 @@ BitWriter.prototype.writeBits = function writeBits(num, count) { num <<= 32 - count; while (count >= 8) { - let ch = num >>> 24; + const ch = num >>> 24; this.writeByte(ch); num <<= 8; count -= 8; } while (count > 0) { - let bit = num >>> 31; + const bit = num >>> 31; this.writeBit(bit); num <<= 1; count -= 1; @@ -412,7 +395,7 @@ BitWriter.prototype.writeBits64 = function writeBits64(num, count) { }; BitWriter.prototype.render = function render() { - let data = Buffer.allocUnsafe(this.stream.length); + const data = Buffer.allocUnsafe(this.stream.length); for (let i = 0; i < this.stream.length; i++) data[i] = this.stream[i]; @@ -451,8 +434,6 @@ BitReader.prototype.readBit = function readBit() { }; BitReader.prototype.readByte = function readByte() { - let ch; - if (this.pos >= this.stream.length) throw new Error('EOF'); @@ -466,12 +447,12 @@ BitReader.prototype.readByte = function readByte() { } if (this.remain === 8) { - ch = this.stream[this.pos]; + const ch = this.stream[this.pos]; this.pos += 1; return ch; } - ch = this.stream[this.pos] & ((1 << this.remain) - 1); + let ch = this.stream[this.pos] & ((1 << this.remain) - 1); ch <<= 8 - this.remain; this.pos += 1; @@ -485,11 +466,11 @@ BitReader.prototype.readByte = function readByte() { }; BitReader.prototype.readBits = function readBits(count) { - let num = 0; - assert(count >= 0); assert(count <= 32); + let num = 0; + while (count >= 8) { num <<= 8; num |= this.readByte(); @@ -505,12 +486,12 @@ BitReader.prototype.readBits = function readBits(count) { return num; }; -BitReader.prototype.readBits64 = function readBits(count) { - let num = new Int64(); - +BitReader.prototype.readBits64 = function readBits64(count) { assert(count >= 0); assert(count <= 64); + const num = new U64(); + if (count > 32) { num.hi = this.readBits(count - 32); num.lo = this.readBits(32); @@ -529,13 +510,13 @@ function compare(a, b) { return a.cmp(b) < 0 ? -1 : 1; } -function siphash(data, key) { - let [hi, lo] = siphash24(data, key); - return new Int64().join(hi, lo); +function siphash24(data, key) { + const [hi, lo] = siphash(data, key); + return U64.fromBits(hi, lo); } function getPushes(items, script) { - for (let op of script.code) { + for (const op of script.code) { if (!op.data || op.data.length === 0) continue; @@ -544,7 +525,7 @@ function getPushes(items, script) { } function getWitness(items, witness) { - for (let item of witness.items) { + for (const item of witness.items) { if (item.length === 0) continue; diff --git a/lib/utils/heap.js b/lib/utils/heap.js index 5a6ef996c..17eef4cd3 100644 --- a/lib/utils/heap.js +++ b/lib/utils/heap.js @@ -31,13 +31,12 @@ function Heap(compare) { */ Heap.prototype.init = function init() { - let n = this.items.length; - let i; + const n = this.items.length; if (n <= 1) return; - for (i = (n / 2 | 0) - 1; i >= 0; i--) + for (let i = (n / 2 | 0) - 1; i >= 0; i--) this.down(i, n); }; @@ -80,12 +79,10 @@ Heap.prototype.insert = function insert(item) { */ Heap.prototype.shift = function shift() { - let n; - if (this.items.length === 0) - return; + return null; - n = this.items.length - 1; + const n = this.items.length - 1; this.swap(0, n); this.down(0, n); @@ -100,15 +97,13 @@ Heap.prototype.shift = function shift() { */ Heap.prototype.remove = function remove(i) { - let n; - if (this.items.length === 0) - return; + return null; - n = this.items.length - 1; + const n = this.items.length - 1; if (i < 0 || i > n) - return; + return null; if (n !== i) { this.swap(i, n); @@ -127,8 +122,8 @@ Heap.prototype.remove = function remove(i) { */ Heap.prototype.swap = function swap(a, b) { - let x = this.items[a]; - let y = this.items[b]; + const x = this.items[a]; + const y = this.items[b]; this.items[a] = y; this.items[b] = x; }; @@ -153,18 +148,16 @@ Heap.prototype.less = function less(i, j) { */ Heap.prototype.down = function down(i, n) { - let j, l, r; - for (;;) { - l = 2 * i + 1; + const l = 2 * i + 1; assert(l >= 0); if (l < 0 || l >= n) break; - j = l; - r = l + 1; + let j = l; + const r = l + 1; if (r < n && !this.less(l, r)) j = r; @@ -184,10 +177,8 @@ Heap.prototype.down = function down(i, n) { */ Heap.prototype.up = function up(i) { - let j; - for (;;) { - j = (i - 1) / 2 | 0; + const j = (i - 1) / 2 | 0; assert(j >= 0); @@ -208,8 +199,8 @@ Heap.prototype.up = function up(i) { */ Heap.prototype.toArray = function toArray() { - let heap = new Heap(); - let result = []; + const heap = new Heap(); + const result = []; heap.compare = this.compare; heap.items = this.items.slice(); @@ -228,7 +219,7 @@ Heap.prototype.toArray = function toArray() { */ Heap.fromArray = function fromArray(compare, items) { - let heap = new Heap(); + const heap = new Heap(); heap.set(compare); heap.items = items; heap.init(); diff --git a/lib/utils/index.js b/lib/utils/index.js index e36f5a181..bac0d298c 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -19,6 +19,7 @@ exports.bech32 = require('./bech32'); exports.Bloom = require('./bloom'); exports.co = require('./co'); exports.encoding = require('./encoding'); +exports.enforce = require('./enforce'); exports.fs = require('./fs'); exports.GCSFilter = require('./gcs'); exports.Heap = require('./heap'); diff --git a/lib/utils/ip.js b/lib/utils/ip.js index 1969f5e19..dc84b9154 100644 --- a/lib/utils/ip.js +++ b/lib/utils/ip.js @@ -9,6 +9,8 @@ * Copyright (c) 2012, Fedor Indutny (MIT License). */ +/* eslint no-unreachable: "off" */ + 'use strict'; const assert = require('assert'); @@ -65,12 +67,10 @@ IP.types = { */ IP.fromHostname = function fromHostname(addr, fallback) { - let parts, host, port, type, hostname, raw; - assert(typeof addr === 'string'); - assert(addr.length > 0, 'Bad address.'); + let host, port; if (addr[0] === '[') { if (addr[addr.length - 1] === ']') { // Case: @@ -81,13 +81,13 @@ IP.fromHostname = function fromHostname(addr, fallback) { // Case: // [::1]:80 addr = addr.slice(1); - parts = addr.split(']:'); + const parts = addr.split(']:'); assert(parts.length === 2, 'Bad IPv6 address.'); host = parts[0]; port = parts[1]; } } else { - parts = addr.split(':'); + const parts = addr.split(':'); switch (parts.length) { case 2: // Cases: @@ -124,13 +124,15 @@ IP.fromHostname = function fromHostname(addr, fallback) { port = fallback || 0; } - type = IP.getStringType(host); + const type = IP.getStringType(host); + let raw; if (type !== IP.types.DNS) { raw = IP.toBuffer(host); host = IP.toString(raw); } + let hostname; if (type === IP.types.IPV6) hostname = `[${host}]:${port}`; else @@ -147,8 +149,6 @@ IP.fromHostname = function fromHostname(addr, fallback) { */ IP.toHostname = function toHostname(host, port) { - let type; - assert(typeof host === 'string'); assert(host.length > 0); assert(typeof port === 'number'); @@ -156,7 +156,7 @@ IP.toHostname = function toHostname(host, port) { assert(!/[\[\]]/.test(host), 'Bad host.'); - type = IP.getStringType(host); + const type = IP.getStringType(host); if (host.indexOf(':') !== -1) assert(type === IP.types.IPV6, 'Bad host.'); @@ -271,10 +271,10 @@ IP.isMapped = function isMapped(raw) { */ IP.toBuffer = function toBuffer(str) { - let raw = Buffer.allocUnsafe(16); - assert(typeof str === 'string'); + const raw = Buffer.allocUnsafe(16); + if (IP.isV4String(str)) { raw.fill(0); raw[10] = 0xff; @@ -283,9 +283,9 @@ IP.toBuffer = function toBuffer(str) { } if (IP.isOnionString(str)) { - let data = TOR_ONION; - data.copy(raw, 0); - data = base32.decode(str.slice(0, -6)); + const prefix = TOR_ONION; + prefix.copy(raw, 0); + const data = base32.decode(str.slice(0, -6)); assert(data.length === 10, 'Invalid onion address.'); data.copy(raw, 6); return raw; @@ -304,7 +304,7 @@ IP.toBuffer = function toBuffer(str) { */ IP.parseV4 = function parseV4(str, raw, offset) { - let parts = str.split('.'); + const parts = str.split('.'); assert(parts.length === 4); @@ -329,18 +329,19 @@ IP.parseV4 = function parseV4(str, raw, offset) { */ IP.parseV6 = function parseV6(str, raw, offset) { - let parts = str.split(':'); + const parts = str.split(':'); let missing = 8 - parts.length; - let start = offset; - let colon = false; assert(parts.length >= 2, 'Not an IPv6 address.'); - for (let word of parts) { + for (const word of parts) { if (IP.isV4String(word)) missing--; } + const start = offset; + let colon = false; + for (let i = 0; i < parts.length; i++) { let word = parts[i]; @@ -386,7 +387,7 @@ IP.parseV6 = function parseV6(str, raw, offset) { } assert(missing === 0, 'IPv6 address has missing sections.'); - assert.equal(offset, start + 16); + assert.strictEqual(offset, start + 16); return raw; }; @@ -410,9 +411,8 @@ IP.toString = function toString(raw) { } if (raw.length === 16) { - let host = ''; - if (IP.isMapped(raw)) { + let host = ''; host += raw[12]; host += '.' + raw[13]; host += '.' + raw[14]; @@ -421,10 +421,12 @@ IP.toString = function toString(raw) { } if (IP.isOnion(raw)) { - host = base32.encode(raw.slice(6)); + const host = base32.encode(raw.slice(6)); return `${host}.onion`; } + let host = ''; + host += raw.readUInt16BE(0, true).toString(16); for (let i = 2; i < 16; i += 2) { @@ -485,7 +487,7 @@ IP.getType = function getType(raw) { if (IP.isOnion(raw)) return IP.types.ONION; - assert(false, 'Unknown type.'); + throw new Error('Unknown type.'); }; /** @@ -857,13 +859,13 @@ IP.getReachability = function getReachability(src, dest) { const IPV6_STRONG = 5; const PRIVATE = 6; - let srcNet = IP.getNetwork(src); - let destNet = IP.getNetwork(dest); - let types = IP.types; - if (!IP.isRoutable(src)) return UNREACHABLE; + const srcNet = IP.getNetwork(src); + const destNet = IP.getNetwork(dest); + const types = IP.types; + switch (destNet) { case types.IPV4: switch (srcNet) { @@ -960,16 +962,7 @@ IP.hasPrefix = function hasPrefix(raw, prefix) { IP.isEqual = function isEqual(a, b) { assert(a.length === 16); assert(b.length === 16); - - if (a.compare) - return a.compare(b) === 0; - - for (let i = 0; i < a.length; i++) { - if (a[i] !== b[i]) - return false; - } - - return true; + return a.equals(b); }; /** @@ -979,17 +972,15 @@ IP.isEqual = function isEqual(a, b) { * @returns {String} */ -IP.getInterfaces = function _getInterfaces(name, family) { - let interfaces = os.networkInterfaces(); - let keys = Object.keys(interfaces); - let result = []; +IP.getInterfaces = function getInterfaces(name, family) { + const interfaces = os.networkInterfaces(); + const result = []; - for (let key of keys) { - let items = interfaces[key]; + for (const key of Object.keys(interfaces)) { + const items = interfaces[key]; - for (let details of items) { - let type = details.family.toLowerCase(); - let raw; + for (const details of items) { + const type = details.family.toLowerCase(); if (family && type !== family) continue; @@ -997,6 +988,7 @@ IP.getInterfaces = function _getInterfaces(name, family) { if (details.internal) continue; + let raw; try { raw = IP.toBuffer(details.address); } catch (e) { diff --git a/lib/utils/list.js b/lib/utils/list.js index b66abf38a..75844e170 100644 --- a/lib/utils/list.js +++ b/lib/utils/list.js @@ -52,10 +52,10 @@ List.prototype.reset = function reset() { */ List.prototype.shift = function shift() { - let item = this.head; + const item = this.head; if (!item) - return; + return null; this.remove(item); @@ -88,10 +88,10 @@ List.prototype.push = function push(item) { */ List.prototype.pop = function pop() { - let item = this.tail; + const item = this.tail; if (!item) - return; + return null; this.remove(item); @@ -209,7 +209,7 @@ List.prototype.replace = function replace(ref, item) { */ List.prototype.slice = function slice(total) { - let items = []; + const items = []; let item, next; if (total == null) @@ -245,7 +245,7 @@ List.prototype.slice = function slice(total) { */ List.prototype.toArray = function toArray() { - let items = []; + const items = []; for (let item = this.head; item; item = item.next) items.push(item); diff --git a/lib/utils/lock.js b/lib/utils/lock.js index 4ecd72f03..8b0e7fa74 100644 --- a/lib/utils/lock.js +++ b/lib/utils/lock.js @@ -27,7 +27,7 @@ function Lock(named) { this.busy = false; this.destroyed = false; - this.map = Object.create(null); + this.map = new Map(); this.current = null; this.unlocker = this.unlock.bind(this); @@ -40,7 +40,7 @@ function Lock(named) { */ Lock.create = function create(named) { - let lock = new Lock(named); + const lock = new Lock(named); return function _lock(arg1, arg2) { return lock.lock(arg1, arg2); }; @@ -59,7 +59,12 @@ Lock.prototype.has = function has(name) { if (this.current === name) return true; - return this.map[name] > 0; + const count = this.map.get(name); + + if (count == null) + return false; + + return count > 0; }; /** @@ -71,7 +76,13 @@ Lock.prototype.has = function has(name) { Lock.prototype.hasPending = function hasPending(name) { assert(this.named, 'Must use named jobs.'); - return this.map[name] > 0; + + const count = this.map.get(name); + + if (count == null) + return false; + + return count > 0; }; /** @@ -105,9 +116,10 @@ Lock.prototype.lock = function lock(arg1, arg2) { if (this.busy) { if (name) { - if (!this.map[name]) - this.map[name] = 0; - this.map[name]++; + let count = this.map.get(name); + if (!count) + count = 0; + this.map.set(name, count + 1); } return new Promise((resolve, reject) => { this.jobs.push(new Job(resolve, reject, name)); @@ -126,8 +138,6 @@ Lock.prototype.lock = function lock(arg1, arg2) { */ Lock.prototype.unlock = function unlock() { - let job; - assert(this.destroyed || this.busy); this.busy = false; @@ -138,12 +148,15 @@ Lock.prototype.unlock = function unlock() { assert(!this.destroyed); - job = this.jobs.shift(); + const job = this.jobs.shift(); if (job.name) { - assert(this.map[job.name] > 0); - if (--this.map[job.name] === 0) - delete this.map[job.name]; + let count = this.map.get(job.name); + assert(count > 0); + if (--count === 0) + this.map.delete(job.name); + else + this.map.set(job.name, count); } this.busy = true; @@ -157,20 +170,18 @@ Lock.prototype.unlock = function unlock() { */ Lock.prototype.destroy = function destroy() { - let jobs; - assert(!this.destroyed, 'Lock is already destroyed.'); this.destroyed = true; - jobs = this.jobs.slice(); + const jobs = this.jobs; this.busy = false; - this.jobs.length = 0; - this.map = Object.create(null); + this.jobs = []; + this.map.clear(); this.current = null; - for (let job of jobs) + for (const job of jobs) job.reject(new Error('Lock was destroyed.')); }; diff --git a/lib/utils/lru.js b/lib/utils/lru.js index 49ef33e19..3f4ec104b 100644 --- a/lib/utils/lru.js +++ b/lib/utils/lru.js @@ -44,10 +44,8 @@ function LRU(capacity, getSize) { */ LRU.prototype._getSize = function _getSize(item) { - let keySize; - if (this.getSize) { - keySize = Math.floor(item.key.length * 1.375); + const keySize = Math.floor(item.key.length * 1.375); return 120 + keySize + this.getSize(item.value); } @@ -60,11 +58,10 @@ LRU.prototype._getSize = function _getSize(item) { */ LRU.prototype._compact = function _compact() { - let item, next; - if (this.size <= this.capacity) return; + let item, next; for (item = this.head; item; item = next) { if (this.size <= this.capacity) break; @@ -115,14 +112,12 @@ LRU.prototype.reset = function reset() { */ LRU.prototype.set = function set(key, value) { - let item; - if (this.capacity === 0) return; - key = key + ''; + key = String(key); - item = this.map.get(key); + let item = this.map.get(key); if (item) { this.size -= this._getSize(item); @@ -153,17 +148,15 @@ LRU.prototype.set = function set(key, value) { */ LRU.prototype.get = function get(key) { - let item; - if (this.capacity === 0) - return; + return null; - key = key + ''; + key = String(key); - item = this.map.get(key); + const item = this.map.get(key); if (!item) - return; + return null; this._removeList(item); this._appendList(item); @@ -177,10 +170,10 @@ LRU.prototype.get = function get(key) { * @returns {Boolean} */ -LRU.prototype.has = function get(key) { +LRU.prototype.has = function has(key) { if (this.capacity === 0) return false; - return this.map.has(key + ''); + return this.map.has(String(key)); }; /** @@ -190,14 +183,12 @@ LRU.prototype.has = function get(key) { */ LRU.prototype.remove = function remove(key) { - let item; - if (this.capacity === 0) - return; + return false; - key = key + ''; + key = String(key); - item = this.map.get(key); + const item = this.map.get(key); if (!item) return false; @@ -218,7 +209,7 @@ LRU.prototype.remove = function remove(key) { * @param {LRUItem} */ -LRU.prototype._prependList = function prependList(item) { +LRU.prototype._prependList = function _prependList(item) { this._insertList(null, item); }; @@ -228,7 +219,7 @@ LRU.prototype._prependList = function prependList(item) { * @param {LRUItem} */ -LRU.prototype._appendList = function appendList(item) { +LRU.prototype._appendList = function _appendList(item) { this._insertList(this.tail, item); }; @@ -239,7 +230,7 @@ LRU.prototype._appendList = function appendList(item) { * @param {LRUItem} item */ -LRU.prototype._insertList = function insertList(ref, item) { +LRU.prototype._insertList = function _insertList(ref, item) { assert(!item.next); assert(!item.prev); @@ -269,7 +260,7 @@ LRU.prototype._insertList = function insertList(ref, item) { * @param {LRUItem} */ -LRU.prototype._removeList = function removeList(item) { +LRU.prototype._removeList = function _removeList(item) { if (item.prev) item.prev.next = item.next; @@ -297,8 +288,8 @@ LRU.prototype._removeList = function removeList(item) { * @returns {String[]} */ -LRU.prototype.keys = function _keys() { - let keys = []; +LRU.prototype.keys = function keys() { + const items = []; for (let item = this.head; item; item = item.next) { if (item === this.head) @@ -307,10 +298,10 @@ LRU.prototype.keys = function _keys() { assert(item === this.head); if (!item.next) assert(item === this.tail); - keys.push(item.key); + items.push(item.key); } - return keys; + return items; }; /** @@ -318,13 +309,13 @@ LRU.prototype.keys = function _keys() { * @returns {String[]} */ -LRU.prototype.values = function _values() { - let values = []; +LRU.prototype.values = function values() { + const items = []; for (let item = this.head; item; item = item.next) - values.push(item.value); + items.push(item.value); - return values; + return items; }; /** @@ -333,7 +324,7 @@ LRU.prototype.values = function _values() { */ LRU.prototype.toArray = function toArray() { - let items = []; + const items = []; for (let item = this.head; item; item = item.next) items.push(item); @@ -477,7 +468,7 @@ LRUBatch.prototype.clear = function clear() { */ LRUBatch.prototype.commit = function commit() { - for (let op of this.ops) { + for (const op of this.ops) { if (op.remove) { this.lru.remove(op.key); continue; diff --git a/lib/utils/mappedlock.js b/lib/utils/mappedlock.js index 05081d14c..a9d7fe975 100644 --- a/lib/utils/mappedlock.js +++ b/lib/utils/mappedlock.js @@ -31,7 +31,7 @@ function MappedLock() { */ MappedLock.create = function create() { - let lock = new MappedLock(); + const lock = new MappedLock(); return function _lock(key, force) { return lock.lock(key, force); }; @@ -103,10 +103,9 @@ MappedLock.prototype.lock = function lock(key, force) { */ MappedLock.prototype.unlock = function unlock(key) { - let self = this; + const self = this; return function unlocker() { - let jobs = self.jobs.get(key); - let job; + const jobs = self.jobs.get(key); assert(self.destroyed || self.busy.has(key)); self.busy.delete(key); @@ -116,7 +115,7 @@ MappedLock.prototype.unlock = function unlock(key) { assert(!self.destroyed); - job = jobs.shift(); + const job = jobs.shift(); assert(job); if (jobs.length === 0) @@ -133,17 +132,17 @@ MappedLock.prototype.unlock = function unlock(key) { */ MappedLock.prototype.destroy = function destroy() { - let map = this.jobs; - assert(!this.destroyed, 'Lock is already destroyed.'); + const map = this.jobs; + this.destroyed = true; this.jobs = new Map(); this.busy = new Map(); - for (let jobs of map.values()) { - for (let job of jobs) + for (const jobs of map.values()) { + for (const job of jobs) job.reject(new Error('Lock was destroyed.')); } }; diff --git a/lib/utils/murmur3.js b/lib/utils/murmur3.js index f9bed6b55..57bda5db9 100644 --- a/lib/utils/murmur3.js +++ b/lib/utils/murmur3.js @@ -18,9 +18,9 @@ const native = require('../native').binding; */ function murmur3(data, seed) { - let tail = data.length - (data.length % 4); - let c1 = 0xcc9e2d51; - let c2 = 0x1b873593; + const tail = data.length - (data.length % 4); + const c1 = 0xcc9e2d51; + const c2 = 0x1b873593; let h1 = seed; let k1; @@ -68,18 +68,18 @@ if (native) murmur3 = native.murmur3; function mul32(a, b) { - let alo = a & 0xffff; - let blo = b & 0xffff; - let ahi = a >>> 16; - let bhi = b >>> 16; - let r, lo, hi; + const alo = a & 0xffff; + const blo = b & 0xffff; + const ahi = a >>> 16; + const bhi = b >>> 16; - lo = alo * blo; - hi = (ahi * blo + bhi * alo) & 0xffff; + let lo = alo * blo; + let hi = (ahi * blo + bhi * alo) & 0xffff; hi += lo >>> 16; lo &= 0xffff; - r = (hi << 16) | lo; + + let r = (hi << 16) | lo; if (r < 0) r += 0x100000000; diff --git a/lib/utils/pem.js b/lib/utils/pem.js index 0878e7e6c..2d68372e2 100644 --- a/lib/utils/pem.js +++ b/lib/utils/pem.js @@ -22,41 +22,60 @@ const PEM = exports; */ PEM.parse = function parse(pem) { - let buf = ''; - let chunks = []; - let s, tag, type; + const chunks = []; + let chunk = ''; + let tag; while (pem.length) { - if (s = /^-----BEGIN ([^\-]+)-----/.exec(pem)) { - pem = pem.substring(s[0].length); - tag = s[1]; + let m; + + m = /^-----BEGIN ([^\-]+)-----/.exec(pem); + if (m) { + pem = pem.substring(m[0].length); + tag = m[1]; continue; } - if (s = /^-----END ([^\-]+)-----/.exec(pem)) { - pem = pem.substring(s[0].length); - assert(tag === s[1], 'Tag mismatch.'); - buf = Buffer.from(buf, 'base64'); - type = tag.split(' ')[0].toLowerCase(); - chunks.push({ tag: tag, type: type, data: buf }); - buf = ''; + + m = /^-----END ([^\-]+)-----/.exec(pem); + if (m) { + pem = pem.substring(m[0].length); + + assert(tag === m[1], 'Tag mismatch.'); + + const type = tag.split(' ')[0].toLowerCase(); + const data = Buffer.from(chunk, 'base64'); + + chunks.push({ + tag: tag, + type: type, + data: data + }); + + chunk = ''; tag = null; + continue; } - if (s = /^[a-zA-Z0-9\+=\/]+/.exec(pem)) { - pem = pem.substring(s[0].length); - buf += s[0]; + + m = /^[a-zA-Z0-9\+=\/]+/.exec(pem); + if (m) { + pem = pem.substring(m[0].length); + chunk += m[0]; continue; } - if (s = /^\s+/.exec(pem)) { - pem = pem.substring(s[0].length); + + m = /^\s+/.exec(pem); + if (m) { + pem = pem.substring(m[0].length); continue; } + throw new Error('PEM parse error.'); } assert(chunks.length !== 0, 'PEM parse error.'); assert(!tag, 'Un-ended tag.'); - assert(buf.length === 0, 'Trailing data.'); + assert(chunk.length === 0, 'Trailing data.'); return chunks; }; @@ -69,16 +88,19 @@ PEM.parse = function parse(pem) { */ PEM.decode = function decode(pem) { - let chunks = PEM.parse(pem); - let body = chunks[0]; - let extra = chunks[1]; - let params, alg; + const chunks = PEM.parse(pem); + const body = chunks[0]; + const extra = chunks[1]; + + let params = null; if (extra) { if (extra.tag.indexOf('PARAMETERS') !== -1) params = extra.data; } + let alg = null; + switch (body.type) { case 'dsa': alg = 'dsa'; @@ -121,6 +143,6 @@ PEM.encode = function encode(der, type, suffix) { return '' + `-----BEGIN ${type}-----\n` - + `${pem}` + + pem + `-----END ${type}-----\n`; }; diff --git a/lib/utils/protoreader.js b/lib/utils/protoreader.js index a037c6e36..7a6452ec6 100644 --- a/lib/utils/protoreader.js +++ b/lib/utils/protoreader.js @@ -7,7 +7,6 @@ 'use strict'; const assert = require('assert'); -const util = require('../utils/util'); const BufferReader = require('../utils/reader'); /* @@ -36,61 +35,74 @@ function ProtoReader(data, zeroCopy) { BufferReader.call(this, data, zeroCopy); } -util.inherits(ProtoReader, BufferReader); +Object.setPrototypeOf(ProtoReader.prototype, BufferReader.prototype); -ProtoReader.prototype.readVarint = function _readVarint() { - let {size, value} = readVarint(this.data, this.offset); +ProtoReader.prototype.readVarint = function readVarint() { + const {size, value} = _readVarint(this.data, this.offset); this.offset += size; return value; }; ProtoReader.prototype.readFieldValue = function readFieldValue(tag, opt) { - let field = this.readField(tag, opt); + const field = this.readField(tag, opt); + if (!field) return -1; + assert(field.value != null); + return field.value; }; ProtoReader.prototype.readFieldU64 = function readFieldU64(tag, opt) { - let field = this.readField(tag, opt); + const field = this.readField(tag, opt); + if (!field) return -1; + assert(field.type === wireType.VARINT || field.type === wireType.FIXED64); + return field.value; }; ProtoReader.prototype.readFieldU32 = function readFieldU32(tag, opt) { - let field = this.readField(tag, opt); + const field = this.readField(tag, opt); + if (!field) return -1; + assert(field.type === wireType.VARINT || field.type === wireType.FIXED32); + return field.value; }; ProtoReader.prototype.readFieldBytes = function readFieldBytes(tag, opt) { - let field = this.readField(tag, opt); + const field = this.readField(tag, opt); + if (!field) return null; + assert(field.data); + return field.data; }; ProtoReader.prototype.readFieldString = function readFieldString(tag, opt, enc) { - let field = this.readField(tag, opt); + const field = this.readField(tag, opt); + if (!field) return null; + assert(field.data); + return field.data.toString(enc || 'utf8'); }; ProtoReader.prototype.nextTag = function nextTag() { - let field; - if (this.left() === 0) return -1; - field = this.readField(); + const field = this.readField(); this.seek(-field.size); @@ -98,10 +110,9 @@ ProtoReader.prototype.nextTag = function nextTag() { }; ProtoReader.prototype.readField = function readField(tag, opt) { - let offset = this.offset; - let header = this.readVarint(); - let field = new Field(header); - let inner; + const offset = this.offset; + const header = this.readVarint(); + const field = new Field(header); if (tag != null && field.tag !== tag) { assert(opt, 'Non-optional field not present.'); @@ -122,7 +133,7 @@ ProtoReader.prototype.readField = function readField(tag, opt) { case wireType.START_GROUP: field.group = []; for (;;) { - inner = this.readField(); + const inner = this.readField(); if (inner.type === wireType.END_GROUP) break; field.group.push(inner); @@ -148,7 +159,7 @@ ProtoReader.prototype.readField = function readField(tag, opt) { * Encoding */ -function readVarint(data, off) { +function _readVarint(data, off) { let num = 0; let ch = 0x80; let size = 0; diff --git a/lib/utils/protowriter.js b/lib/utils/protowriter.js index 58de3ec84..5f1a7abdb 100644 --- a/lib/utils/protowriter.js +++ b/lib/utils/protowriter.js @@ -11,7 +11,6 @@ */ const assert = require('assert'); -const util = require('../utils/util'); const BufferWriter = require('../utils/writer'); /* @@ -40,59 +39,65 @@ function ProtoWriter() { BufferWriter.call(this); } -util.inherits(ProtoWriter, BufferWriter); +Object.setPrototypeOf(ProtoWriter.prototype, BufferWriter.prototype); -ProtoWriter.prototype.writeVarint = function _writeVarint(num) { - let size = sizeVarint(num); - let value; +ProtoWriter.prototype.writeVarint = function writeVarint(num) { + const size = sizeVarint(num); // Avoid an extra allocation until // we make bufferwriter more hackable. // More insanity here... switch (size) { - case 6: - value = slipVarint(num); + case 6: { + const value = slipVarint(num); this.writeU32BE(value / 0x10000 | 0); this.writeU16BE(value & 0xffff); break; - case 5: - value = slipVarint(num); + } + case 5: { + const value = slipVarint(num); this.writeU32BE(value / 0x100 | 0); this.writeU8(value & 0xff); break; - case 4: - value = slipVarint(num); + } + case 4: { + const value = slipVarint(num); this.writeU32BE(value); break; - case 3: - value = slipVarint(num); + } + case 3: { + const value = slipVarint(num); this.writeU16BE(value >> 8); this.writeU8(value & 0xff); break; - case 2: - value = slipVarint(num); + } + case 2: { + const value = slipVarint(num); this.writeU16BE(value); break; - case 1: - value = slipVarint(num); + } + case 1: { + const value = slipVarint(num); this.writeU8(value); break; - default: - value = Buffer.allocUnsafe(size); - writeVarint(value, num, 0); + } + default: { + const value = Buffer.allocUnsafe(size); + _writeVarint(value, num, 0); this.writeBytes(value); break; + } } }; ProtoWriter.prototype.writeFieldVarint = function writeFieldVarint(tag, value) { - let header = (tag << 3) | wireType.VARINT; + const header = (tag << 3) | wireType.VARINT; this.writeVarint(header); this.writeVarint(value); }; ProtoWriter.prototype.writeFieldU64 = function writeFieldU64(tag, value) { - assert(util.isSafeInteger(value)); + assert(Number.isSafeInteger(value)); this.writeFieldVarint(tag, value); }; @@ -102,7 +107,7 @@ ProtoWriter.prototype.writeFieldU32 = function writeFieldU32(tag, value) { }; ProtoWriter.prototype.writeFieldBytes = function writeFieldBytes(tag, data) { - let header = (tag << 3) | wireType.DELIMITED; + const header = (tag << 3) | wireType.DELIMITED; this.writeVarint(header); this.writeVarint(data.length); this.writeBytes(data); @@ -118,14 +123,12 @@ ProtoWriter.prototype.writeFieldString = function writeFieldString(tag, data, en * Encoding */ -function writeVarint(data, num, off) { - let ch; - - assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.'); +function _writeVarint(data, num, off) { + assert(Number.isSafeInteger(num), 'Number exceeds 2^53-1.'); do { assert(off < data.length); - ch = num & 0x7f; + let ch = num & 0x7f; num -= num % 0x80; num /= 0x80; if (num !== 0) @@ -138,15 +141,14 @@ function writeVarint(data, num, off) { }; function slipVarint(num) { + assert(Number.isSafeInteger(num), 'Number exceeds 2^53-1.'); + let data = 0; let size = 0; - let ch; - - assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.'); do { assert(size < 7); - ch = num & 0x7f; + let ch = num & 0x7f; num -= num % 0x80; num /= 0x80; if (num !== 0) @@ -160,9 +162,9 @@ function slipVarint(num) { } function sizeVarint(num) { - let size = 0; + assert(Number.isSafeInteger(num), 'Number exceeds 2^53-1.'); - assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.'); + let size = 0; do { num -= num % 0x80; diff --git a/lib/utils/rbt.js b/lib/utils/rbt.js index 9b8c7de66..17454395f 100644 --- a/lib/utils/rbt.js +++ b/lib/utils/rbt.js @@ -48,7 +48,7 @@ RBT.prototype.search = function search(key) { let current = this.root; while (!current.isNull()) { - let cmp = this.compare(key, current.key); + const cmp = this.compare(key, current.key); if (cmp === 0) return current; @@ -58,6 +58,8 @@ RBT.prototype.search = function search(key) { else current = current.right; } + + return null; }; /** @@ -69,10 +71,10 @@ RBT.prototype.search = function search(key) { RBT.prototype.insert = function insert(key, value) { let current = this.root; let left = false; - let parent, node; + let parent; while (!current.isNull()) { - let cmp = this.compare(key, current.key); + const cmp = this.compare(key, current.key); if (this.unique && cmp === 0) { current.key = key; @@ -91,7 +93,7 @@ RBT.prototype.insert = function insert(key, value) { } } - node = new RBTNode(key, value); + const node = new RBTNode(key, value); if (!parent) { this.root = node; @@ -118,13 +120,11 @@ RBT.prototype.insert = function insert(key, value) { */ RBT.prototype.insertFixup = function insertFixup(x) { - let y; - x.color = RED; while (x !== this.root && x.parent.color === RED) { if (x.parent === x.parent.parent.left) { - y = x.parent.parent.right; + const y = x.parent.parent.right; if (!y.isNull() && y.color === RED) { x.parent.color = BLACK; y.color = BLACK; @@ -140,7 +140,7 @@ RBT.prototype.insertFixup = function insertFixup(x) { this.rotr(x.parent.parent); } } else { - y = x.parent.parent.left; + const y = x.parent.parent.left; if (!y.isNull() && y.color === RED) { x.parent.color = BLACK; y.color = BLACK; @@ -171,7 +171,7 @@ RBT.prototype.remove = function remove(key) { let current = this.root; while (!current.isNull()) { - let cmp = this.compare(key, current.key); + const cmp = this.compare(key, current.key); if (cmp === 0) { this.removeNode(current); @@ -183,6 +183,8 @@ RBT.prototype.remove = function remove(key) { else current = current.right; } + + return null; }; /** @@ -193,12 +195,11 @@ RBT.prototype.remove = function remove(key) { RBT.prototype.removeNode = function removeNode(z) { let y = z; - let x; if (!z.left.isNull() && !z.right.isNull()) y = this.successor(z); - x = y.left.isNull() ? y.right : y.left; + const x = y.left.isNull() ? y.right : y.left; x.parent = y.parent; if (y.parent.isNull()) { @@ -226,11 +227,9 @@ RBT.prototype.removeNode = function removeNode(z) { */ RBT.prototype.removeFixup = function removeFixup(x) { - let w; - while (x !== this.root && x.color === BLACK) { if (x === x.parent.left) { - w = x.parent.right; + let w = x.parent.right; if (w.color === RED) { w.color = BLACK; @@ -256,7 +255,7 @@ RBT.prototype.removeFixup = function removeFixup(x) { x = this.root; } } else { - w = x.parent.left; + let w = x.parent.left; if (w.color === RED) { w.color = BLACK; @@ -294,7 +293,8 @@ RBT.prototype.removeFixup = function removeFixup(x) { */ RBT.prototype.rotl = function rotl(x) { - let y = x.right; + const y = x.right; + x.right = y.left; if (!y.left.isNull()) @@ -322,7 +322,8 @@ RBT.prototype.rotl = function rotl(x) { */ RBT.prototype.rotr = function rotr(x) { - let y = x.left; + const y = x.left; + x.left = y.right; if (!y.right.isNull()) @@ -353,8 +354,10 @@ RBT.prototype.rotr = function rotr(x) { RBT.prototype.min = function min(z) { if (z.isNull()) return z; + while (!z.left.isNull()) z = z.left; + return z; }; @@ -368,8 +371,10 @@ RBT.prototype.min = function min(z) { RBT.prototype.max = function max(z) { if (z.isNull()) return z; + while (!z.right.isNull()) z = z.right; + return z; }; @@ -381,18 +386,21 @@ RBT.prototype.max = function max(z) { */ RBT.prototype.successor = function successor(x) { - let y; if (!x.right.isNull()) { x = x.right; + while (!x.left.isNull()) x = x.left; + return x; } - y = x.parent; + + let y = x.parent; while (!y.isNull() && x === y.right) { x = y; y = y.parent; } + return y; }; @@ -404,18 +412,21 @@ RBT.prototype.successor = function successor(x) { */ RBT.prototype.predecessor = function predecessor(x) { - let y; if (!x.left.isNull()) { x = x.left; + while (!x.right.isNull()) x = x.right; + return x; } - y = x.parent; + + let y = x.parent; while (!y.isNull() && x === y.left) { x = y; y = y.parent; } + return y; }; @@ -426,14 +437,18 @@ RBT.prototype.predecessor = function predecessor(x) { */ RBT.prototype.clone = function clone() { + if (this.root.isNull()) + return SENTINEL; + + const stack = []; + let current = this.root; - let stack = []; let left = true; - let parent, copy, snapshot; + let parent, snapshot; for (;;) { if (!current.isNull()) { - copy = current.clone(); + const copy = current.clone(); if (parent) copy.parent = parent; @@ -466,6 +481,8 @@ RBT.prototype.clone = function clone() { current = current.right; } + assert(snapshot); + return snapshot; }; @@ -476,12 +493,10 @@ RBT.prototype.clone = function clone() { */ RBT.prototype.snapshot = function snapshot() { - let node = SENTINEL; - if (this.root.isNull()) - return node; + return SENTINEL; - node = this.root.clone(); + const node = this.root.clone(); copyLeft(node, node.left); copyRight(node, node.right); @@ -507,8 +522,8 @@ RBT.prototype.iterator = function iterator(snapshot) { */ RBT.prototype.range = function range(min, max) { - let iter = this.iterator(); - let items = []; + const iter = this.iterator(); + const items = []; if (min) iter.seekMin(min); @@ -608,13 +623,13 @@ Iterator.prototype.seek = function seek(key) { */ Iterator.prototype.seekMin = function seekMin(key) { + assert(key != null, 'No key passed to seek.'); + let root = this.current; let current = SENTINEL; - assert(key != null, 'No key passed to seek.'); - while (!root.isNull()) { - let cmp = this.tree.compare(root.key, key); + const cmp = this.tree.compare(root.key, key); if (cmp === 0) { current = root; @@ -640,13 +655,13 @@ Iterator.prototype.seekMin = function seekMin(key) { */ Iterator.prototype.seekMax = function seekMax(key) { + assert(key != null, 'No key passed to seek.'); + let root = this.current; let current = SENTINEL; - assert(key != null, 'No key passed to seek.'); - while (!root.isNull()) { - let cmp = this.tree.compare(root.key, key); + const cmp = this.tree.compare(root.key, key); if (cmp === 0) { current = root; @@ -744,7 +759,7 @@ function RBTNode(key, value) { */ RBTNode.prototype.clone = function clone() { - let node = new RBTNode(this.key, this.value); + const node = new RBTNode(this.key, this.value); node.color = this.color; node.parent = this.parent; node.left = this.left; diff --git a/lib/utils/reader.js b/lib/utils/reader.js index 513ff13b7..4323c17b7 100644 --- a/lib/utils/reader.js +++ b/lib/utils/reader.js @@ -10,6 +10,7 @@ const assert = require('assert'); const encoding = require('./encoding'); const digest = require('../crypto/digest'); +const EMPTY_BUFFER = Buffer.alloc(0); /** * An object that allows reading of buffers in a sane manner. @@ -101,15 +102,12 @@ BufferReader.prototype.start = function start() { * @throws on empty stack. */ -BufferReader.prototype.end = function _end() { - let start, end; - +BufferReader.prototype.end = function end() { assert(this.stack.length > 0); - start = this.stack.pop(); - end = this.offset; + const start = this.stack.pop(); - return end - start; + return this.offset - start; }; /** @@ -123,14 +121,12 @@ BufferReader.prototype.end = function _end() { */ BufferReader.prototype.endData = function endData(zeroCopy) { - let ret, start, end, size, data; - assert(this.stack.length > 0); - start = this.stack.pop(); - end = this.offset; - size = end - start; - data = this.data; + const start = this.stack.pop(); + const end = this.offset; + const size = end - start; + const data = this.data; if (size === data.length) return data; @@ -138,7 +134,7 @@ BufferReader.prototype.endData = function endData(zeroCopy) { if (this.zeroCopy || zeroCopy) return data.slice(start, end); - ret = Buffer.allocUnsafe(size); + const ret = Buffer.allocUnsafe(size); data.copy(ret, 0, start, end); return ret; @@ -149,9 +145,9 @@ BufferReader.prototype.endData = function endData(zeroCopy) { */ BufferReader.prototype.destroy = function destroy() { - this.offset = null; - this.stack = null; - this.data = null; + this.data = EMPTY_BUFFER; + this.offset = 0; + this.stack.length = 0; }; /** @@ -160,9 +156,8 @@ BufferReader.prototype.destroy = function destroy() { */ BufferReader.prototype.readU8 = function readU8() { - let ret; this.assert(this.offset + 1 <= this.data.length); - ret = this.data[this.offset]; + const ret = this.data[this.offset]; this.offset += 1; return ret; }; @@ -173,9 +168,8 @@ BufferReader.prototype.readU8 = function readU8() { */ BufferReader.prototype.readU16 = function readU16() { - let ret; this.assert(this.offset + 2 <= this.data.length); - ret = this.data.readUInt16LE(this.offset, true); + const ret = this.data.readUInt16LE(this.offset, true); this.offset += 2; return ret; }; @@ -186,9 +180,8 @@ BufferReader.prototype.readU16 = function readU16() { */ BufferReader.prototype.readU16BE = function readU16BE() { - let ret; this.assert(this.offset + 2 <= this.data.length); - ret = this.data.readUInt16BE(this.offset, true); + const ret = this.data.readUInt16BE(this.offset, true); this.offset += 2; return ret; }; @@ -199,9 +192,8 @@ BufferReader.prototype.readU16BE = function readU16BE() { */ BufferReader.prototype.readU32 = function readU32() { - let ret; this.assert(this.offset + 4 <= this.data.length); - ret = this.data.readUInt32LE(this.offset, true); + const ret = this.data.readUInt32LE(this.offset, true); this.offset += 4; return ret; }; @@ -212,9 +204,8 @@ BufferReader.prototype.readU32 = function readU32() { */ BufferReader.prototype.readU32BE = function readU32BE() { - let ret; this.assert(this.offset + 4 <= this.data.length); - ret = this.data.readUInt32BE(this.offset, true); + const ret = this.data.readUInt32BE(this.offset, true); this.offset += 4; return ret; }; @@ -226,9 +217,8 @@ BufferReader.prototype.readU32BE = function readU32BE() { */ BufferReader.prototype.readU64 = function readU64() { - let ret; this.assert(this.offset + 8 <= this.data.length); - ret = encoding.readU64(this.data, this.offset); + const ret = encoding.readU64(this.data, this.offset); this.offset += 8; return ret; }; @@ -240,9 +230,8 @@ BufferReader.prototype.readU64 = function readU64() { */ BufferReader.prototype.readU64BE = function readU64BE() { - let ret; this.assert(this.offset + 8 <= this.data.length); - ret = encoding.readU64BE(this.data, this.offset); + const ret = encoding.readU64BE(this.data, this.offset); this.offset += 8; return ret; }; @@ -254,9 +243,8 @@ BufferReader.prototype.readU64BE = function readU64BE() { */ BufferReader.prototype.readU53 = function readU53() { - let ret; this.assert(this.offset + 8 <= this.data.length); - ret = encoding.readU53(this.data, this.offset); + const ret = encoding.readU53(this.data, this.offset); this.offset += 8; return ret; }; @@ -268,9 +256,8 @@ BufferReader.prototype.readU53 = function readU53() { */ BufferReader.prototype.readU53BE = function readU53BE() { - let ret; this.assert(this.offset + 8 <= this.data.length); - ret = encoding.readU53BE(this.data, this.offset); + const ret = encoding.readU53BE(this.data, this.offset); this.offset += 8; return ret; }; @@ -280,10 +267,9 @@ BufferReader.prototype.readU53BE = function readU53BE() { * @returns {Number} */ -BufferReader.prototype.read8 = function read8() { - let ret; +BufferReader.prototype.readI8 = function readI8() { this.assert(this.offset + 1 <= this.data.length); - ret = this.data.readInt8(this.offset, true); + const ret = this.data.readInt8(this.offset, true); this.offset += 1; return ret; }; @@ -293,10 +279,9 @@ BufferReader.prototype.read8 = function read8() { * @returns {Number} */ -BufferReader.prototype.read16 = function read16() { - let ret; +BufferReader.prototype.readI16 = function readI16() { this.assert(this.offset + 2 <= this.data.length); - ret = this.data.readInt16LE(this.offset, true); + const ret = this.data.readInt16LE(this.offset, true); this.offset += 2; return ret; }; @@ -306,10 +291,9 @@ BufferReader.prototype.read16 = function read16() { * @returns {Number} */ -BufferReader.prototype.read16BE = function read16BE() { - let ret; +BufferReader.prototype.readI16BE = function readI16BE() { this.assert(this.offset + 2 <= this.data.length); - ret = this.data.readInt16BE(this.offset, true); + const ret = this.data.readInt16BE(this.offset, true); this.offset += 2; return ret; }; @@ -319,10 +303,9 @@ BufferReader.prototype.read16BE = function read16BE() { * @returns {Number} */ -BufferReader.prototype.read32 = function read32() { - let ret; +BufferReader.prototype.readI32 = function readI32() { this.assert(this.offset + 4 <= this.data.length); - ret = this.data.readInt32LE(this.offset, true); + const ret = this.data.readInt32LE(this.offset, true); this.offset += 4; return ret; }; @@ -332,10 +315,9 @@ BufferReader.prototype.read32 = function read32() { * @returns {Number} */ -BufferReader.prototype.read32BE = function read32BE() { - let ret; +BufferReader.prototype.readI32BE = function readI32BE() { this.assert(this.offset + 4 <= this.data.length); - ret = this.data.readInt32BE(this.offset, true); + const ret = this.data.readInt32BE(this.offset, true); this.offset += 4; return ret; }; @@ -346,10 +328,9 @@ BufferReader.prototype.read32BE = function read32BE() { * @throws on num > MAX_SAFE_INTEGER */ -BufferReader.prototype.read64 = function read64() { - let ret; +BufferReader.prototype.readI64 = function readI64() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.read64(this.data, this.offset); + const ret = encoding.readI64(this.data, this.offset); this.offset += 8; return ret; }; @@ -360,10 +341,9 @@ BufferReader.prototype.read64 = function read64() { * @throws on num > MAX_SAFE_INTEGER */ -BufferReader.prototype.read64BE = function read64BE() { - let ret; +BufferReader.prototype.readI64BE = function readI64BE() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.read64BE(this.data, this.offset); + const ret = encoding.readI64BE(this.data, this.offset); this.offset += 8; return ret; }; @@ -374,10 +354,9 @@ BufferReader.prototype.read64BE = function read64BE() { * @returns {Number} */ -BufferReader.prototype.read53 = function read53() { - let ret; +BufferReader.prototype.readI53 = function readI53() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.read53(this.data, this.offset); + const ret = encoding.readI53(this.data, this.offset); this.offset += 8; return ret; }; @@ -388,62 +367,57 @@ BufferReader.prototype.read53 = function read53() { * @returns {Number} */ -BufferReader.prototype.read53BE = function read53BE() { - let ret; +BufferReader.prototype.readI53BE = function readI53BE() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.read53BE(this.data, this.offset); + const ret = encoding.readI53BE(this.data, this.offset); this.offset += 8; return ret; }; /** * Read uint64le. - * @returns {BN} + * @returns {U64} */ -BufferReader.prototype.readU64BN = function readU64BN() { - let ret; +BufferReader.prototype.readU64N = function readU64N() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.readU64BN(this.data, this.offset); + const ret = encoding.readU64N(this.data, this.offset); this.offset += 8; return ret; }; /** * Read uint64be. - * @returns {BN} + * @returns {U64} */ -BufferReader.prototype.readU64BEBN = function readU64BEBN() { - let ret; +BufferReader.prototype.readU64BEN = function readU64BEN() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.readU64BEBN(this.data, this.offset); + const ret = encoding.readU64BEN(this.data, this.offset); this.offset += 8; return ret; }; /** * Read int64le. - * @returns {BN} + * @returns {I64} */ -BufferReader.prototype.read64BN = function read64BN() { - let ret; +BufferReader.prototype.readI64N = function readI64N() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.read64BN(this.data, this.offset); + const ret = encoding.readI64N(this.data, this.offset); this.offset += 8; return ret; }; /** * Read int64be. - * @returns {BN} + * @returns {I64} */ -BufferReader.prototype.read64BEBN = function read64BEBN() { - let ret; +BufferReader.prototype.readI64BEN = function readI64BEN() { this.assert(this.offset + 8 <= this.data.length); - ret = encoding.read64BEBN(this.data, this.offset); + const ret = encoding.readI64BEN(this.data, this.offset); this.offset += 8; return ret; }; @@ -454,9 +428,8 @@ BufferReader.prototype.read64BEBN = function read64BEBN() { */ BufferReader.prototype.readFloat = function readFloat() { - let ret; this.assert(this.offset + 4 <= this.data.length); - ret = this.data.readFloatLE(this.offset, true); + const ret = this.data.readFloatLE(this.offset, true); this.offset += 4; return ret; }; @@ -467,9 +440,8 @@ BufferReader.prototype.readFloat = function readFloat() { */ BufferReader.prototype.readFloatBE = function readFloatBE() { - let ret; this.assert(this.offset + 4 <= this.data.length); - ret = this.data.readFloatBE(this.offset, true); + const ret = this.data.readFloatBE(this.offset, true); this.offset += 4; return ret; }; @@ -480,9 +452,8 @@ BufferReader.prototype.readFloatBE = function readFloatBE() { */ BufferReader.prototype.readDouble = function readDouble() { - let ret; this.assert(this.offset + 8 <= this.data.length); - ret = this.data.readDoubleLE(this.offset, true); + const ret = this.data.readDoubleLE(this.offset, true); this.offset += 8; return ret; }; @@ -493,9 +464,8 @@ BufferReader.prototype.readDouble = function readDouble() { */ BufferReader.prototype.readDoubleBE = function readDoubleBE() { - let ret; this.assert(this.offset + 8 <= this.data.length); - ret = this.data.readDoubleBE(this.offset, true); + const ret = this.data.readDoubleBE(this.offset, true); this.offset += 8; return ret; }; @@ -506,7 +476,7 @@ BufferReader.prototype.readDoubleBE = function readDoubleBE() { */ BufferReader.prototype.readVarint = function readVarint() { - let {size, value} = encoding.readVarint(this.data, this.offset); + const {size, value} = encoding.readVarint(this.data, this.offset); this.offset += size; return value; }; @@ -517,18 +487,19 @@ BufferReader.prototype.readVarint = function readVarint() { */ BufferReader.prototype.skipVarint = function skipVarint() { - let size = encoding.skipVarint(this.data, this.offset); + const size = encoding.skipVarint(this.data, this.offset); this.assert(this.offset + size <= this.data.length); this.offset += size; + return size; }; /** * Read a varint. - * @returns {BN} + * @returns {U64} */ -BufferReader.prototype.readVarintBN = function readVarintBN() { - let {size, value} = encoding.readVarintBN(this.data, this.offset); +BufferReader.prototype.readVarintN = function readVarintN() { + const {size, value} = encoding.readVarintN(this.data, this.offset); this.offset += size; return value; }; @@ -539,7 +510,7 @@ BufferReader.prototype.readVarintBN = function readVarintBN() { */ BufferReader.prototype.readVarint2 = function readVarint2() { - let {size, value} = encoding.readVarint2(this.data, this.offset); + const {size, value} = encoding.readVarint2(this.data, this.offset); this.offset += size; return value; }; @@ -550,18 +521,18 @@ BufferReader.prototype.readVarint2 = function readVarint2() { */ BufferReader.prototype.skipVarint2 = function skipVarint2() { - let size = encoding.skipVarint2(this.data, this.offset); + const size = encoding.skipVarint2(this.data, this.offset); this.assert(this.offset + size <= this.data.length); this.offset += size; }; /** * Read a varint (type 2). - * @returns {BN} + * @returns {U64} */ -BufferReader.prototype.readVarint2BN = function readVarint2BN() { - let {size, value} = encoding.readVarint2BN(this.data, this.offset); +BufferReader.prototype.readVarint2N = function readVarint2N() { + const {size, value} = encoding.readVarint2N(this.data, this.offset); this.offset += size; return value; }; @@ -576,11 +547,10 @@ BufferReader.prototype.readVarint2BN = function readVarint2BN() { */ BufferReader.prototype.readBytes = function readBytes(size, zeroCopy) { - let ret; - assert(size >= 0); this.assert(this.offset + size <= this.data.length); + let ret; if (this.zeroCopy || zeroCopy) { ret = this.data.slice(this.offset, this.offset + size); } else { @@ -613,10 +583,9 @@ BufferReader.prototype.readVarBytes = function readVarBytes(zeroCopy) { */ BufferReader.prototype.readString = function readString(enc, size) { - let ret; assert(size >= 0); this.assert(this.offset + size <= this.data.length); - ret = this.data.toString(enc, this.offset, this.offset + size); + const ret = this.data.toString(enc, this.offset, this.offset + size); this.offset += size; return ret; }; @@ -641,7 +610,7 @@ BufferReader.prototype.readHash = function readHash(enc) { */ BufferReader.prototype.readVarString = function readVarString(enc, limit) { - let size = this.readVarint(); + const size = this.readVarint(); this.enforce(!limit || size <= limit, 'String exceeds limit.'); return this.readString(enc, size); }; @@ -653,15 +622,20 @@ BufferReader.prototype.readVarString = function readVarString(enc, limit) { */ BufferReader.prototype.readNullString = function readNullString(enc) { - let i, ret; this.assert(this.offset + 1 <= this.data.length); - for (i = this.offset; i < this.data.length; i++) { + + let i = this.offset; + for (; i < this.data.length; i++) { if (this.data[i] === 0) break; } + this.assert(i !== this.data.length); - ret = this.readString(enc, i - this.offset); + + const ret = this.readString(enc, i - this.offset); + this.offset = i + 1; + return ret; }; @@ -672,12 +646,11 @@ BufferReader.prototype.readNullString = function readNullString(enc) { BufferReader.prototype.createChecksum = function createChecksum() { let start = 0; - let data; if (this.stack.length > 0) start = this.stack[this.stack.length - 1]; - data = this.data.slice(start, this.offset); + const data = this.data.slice(start, this.offset); return digest.hash256(data).readUInt32LE(0, true); }; @@ -689,8 +662,8 @@ BufferReader.prototype.createChecksum = function createChecksum() { */ BufferReader.prototype.verifyChecksum = function verifyChecksum() { - let chk = this.createChecksum(); - let checksum = this.readU32(); + const chk = this.createChecksum(); + const checksum = this.readU32(); this.enforce(chk === checksum, 'Checksum mismatch.'); return checksum; }; diff --git a/lib/utils/rollingfilter.js b/lib/utils/rollingfilter.js index 77a03376c..df6d8e250 100644 --- a/lib/utils/rollingfilter.js +++ b/lib/utils/rollingfilter.js @@ -48,30 +48,29 @@ function RollingFilter(items, rate) { */ RollingFilter.prototype.fromRate = function fromRate(items, rate) { - let logRate, max, n, limit, size, tweak, filter; - assert(typeof items === 'number', '`items` must be a number.'); assert(items > 0, '`items` must be greater than zero.'); - assert(items % 1 === 0, '`items` must be an integer.'); + assert(Number.isSafeInteger(items), '`items` must be an integer.'); assert(typeof rate === 'number', '`rate` must be a number.'); assert(rate >= 0 && rate <= 1, '`rate` must be between 0.0 and 1.0.'); - logRate = Math.log(rate); + const logRate = Math.log(rate); + + const n = Math.max(1, Math.min(Math.round(logRate / Math.log(0.5)), 50)); + const limit = (items + 1) / 2 | 0; - n = Math.max(1, Math.min(Math.round(logRate / Math.log(0.5)), 50)); - limit = (items + 1) / 2 | 0; + const max = limit * 3; - max = limit * 3; - size = -1 * n * max / Math.log(1.0 - Math.exp(logRate / n)); + let size = -1 * n * max / Math.log(1.0 - Math.exp(logRate / n)); size = Math.ceil(size); items = ((size + 63) / 64 | 0) << 1; items >>>= 0; items = Math.max(1, items); - tweak = (Math.random() * 0x100000000) >>> 0; + const tweak = (Math.random() * 0x100000000) >>> 0; - filter = Buffer.allocUnsafe(items * 8); + const filter = Buffer.allocUnsafe(items * 8); filter.fill(0); this.n = n; @@ -130,24 +129,22 @@ RollingFilter.prototype.add = function add(val, enc) { val = Buffer.from(val, enc); if (this.entries === this.limit) { - let m1, m2; - this.entries = 0; this.generation += 1; if (this.generation === 4) this.generation = 1; - m1 = (this.generation & 1) * 0xffffffff; - m2 = (this.generation >>> 1) * 0xffffffff; + const m1 = (this.generation & 1) * 0xffffffff; + const m2 = (this.generation >>> 1) * 0xffffffff; for (let i = 0; i < this.items; i += 2) { - let pos1 = i * 8; - let pos2 = (i + 1) * 8; - let v1 = read(this.filter, pos1); - let v2 = read(this.filter, pos2); - let mhi = (v1.hi ^ m1) | (v2.hi ^ m2); - let mlo = (v1.lo ^ m1) | (v2.lo ^ m2); + const pos1 = i * 8; + const pos2 = (i + 1) * 8; + const v1 = read(this.filter, pos1); + const v2 = read(this.filter, pos2); + const mhi = (v1.hi ^ m1) | (v2.hi ^ m2); + const mlo = (v1.lo ^ m1) | (v2.lo ^ m2); v1.hi &= mhi; v1.lo &= mlo; @@ -162,22 +159,19 @@ RollingFilter.prototype.add = function add(val, enc) { this.entries += 1; for (let i = 0; i < this.n; i++) { - let hash = this.hash(val, i); - let bits = hash & 0x3f; - let pos = (hash >>> 6) % this.items; - let pos1 = (pos & ~1) * 8; - let pos2 = (pos | 1) * 8; - let bit = bits % 8; - let oct = (bits - bit) / 8; - - pos1 += oct; - pos2 += oct; - - this.filter[pos1] &= ~(1 << bit); - this.filter[pos1] |= (this.generation & 1) << bit; - - this.filter[pos2] &= ~(1 << bit); - this.filter[pos2] |= (this.generation >>> 1) << bit; + const hash = this.hash(val, i); + const bits = hash & 0x3f; + const pos = (hash >>> 6) % this.items; + const pos1 = (pos & ~1) * 8; + const pos2 = (pos | 1) * 8; + const bit = bits % 8; + const oct = (bits - bit) / 8; + + this.filter[pos1 + oct] &= ~(1 << bit); + this.filter[pos1 + oct] |= (this.generation & 1) << bit; + + this.filter[pos2 + oct] &= ~(1 << bit); + this.filter[pos2 + oct] |= (this.generation >>> 1) << bit; } }; @@ -196,21 +190,18 @@ RollingFilter.prototype.test = function test(val, enc) { val = Buffer.from(val, enc); for (let i = 0; i < this.n; i++) { - let hash = this.hash(val, i); - let bits = hash & 0x3f; - let pos = (hash >>> 6) % this.items; - let pos1 = (pos & ~1) * 8; - let pos2 = (pos | 1) * 8; - let bit = bits % 8; - let oct = (bits - bit) / 8; - - pos1 += oct; - pos2 += oct; - - bits = (this.filter[pos1] >>> bit) & 1; - bits |= (this.filter[pos2] >>> bit) & 1; - - if (bits === 0) + const hash = this.hash(val, i); + const bits = hash & 0x3f; + const pos = (hash >>> 6) % this.items; + const pos1 = (pos & ~1) * 8; + const pos2 = (pos | 1) * 8; + const bit = bits % 8; + const oct = (bits - bit) / 8; + + const bit1 = (this.filter[pos1 + oct] >>> bit) & 1; + const bit2 = (this.filter[pos2 + oct] >>> bit) & 1; + + if ((bit1 | bit2) === 0) return false; } @@ -247,8 +238,8 @@ function U64(hi, lo) { } function read(data, off) { - let hi = data.readUInt32LE(off + 4, true); - let lo = data.readUInt32LE(off, true); + const hi = data.readUInt32LE(off + 4, true); + const lo = data.readUInt32LE(off, true); return new U64(hi, lo); } diff --git a/lib/utils/staticwriter.js b/lib/utils/staticwriter.js index 83b414d73..c90ad799d 100644 --- a/lib/utils/staticwriter.js +++ b/lib/utils/staticwriter.js @@ -9,6 +9,7 @@ const assert = require('assert'); const encoding = require('./encoding'); const digest = require('../crypto/digest'); +const EMPTY_BUFFER = Buffer.alloc(0); /** * Statically allocated buffer writer. @@ -22,7 +23,7 @@ function StaticWriter(size) { return new StaticWriter(size); this.data = Buffer.allocUnsafe(size); - this.written = 0; + this.offset = 0; } /** @@ -32,9 +33,9 @@ function StaticWriter(size) { */ StaticWriter.prototype.render = function render(keep) { - let data = this.data; + const data = this.data; - assert(this.written === data.length); + assert(this.offset === data.length); if (!keep) this.destroy(); @@ -48,7 +49,7 @@ StaticWriter.prototype.render = function render(keep) { */ StaticWriter.prototype.getSize = function getSize() { - return this.written; + return this.offset; }; /** @@ -57,7 +58,7 @@ StaticWriter.prototype.getSize = function getSize() { */ StaticWriter.prototype.seek = function seek(offset) { - this.written += offset; + this.offset += offset; }; /** @@ -65,8 +66,8 @@ StaticWriter.prototype.seek = function seek(offset) { */ StaticWriter.prototype.destroy = function destroy() { - this.data = null; - this.written = null; + this.data = EMPTY_BUFFER; + this.offset = 0; }; /** @@ -75,7 +76,7 @@ StaticWriter.prototype.destroy = function destroy() { */ StaticWriter.prototype.writeU8 = function writeU8(value) { - this.written = this.data.writeUInt8(value, this.written, true); + this.offset = this.data.writeUInt8(value, this.offset, true); }; /** @@ -84,7 +85,7 @@ StaticWriter.prototype.writeU8 = function writeU8(value) { */ StaticWriter.prototype.writeU16 = function writeU16(value) { - this.written = this.data.writeUInt16LE(value, this.written, true); + this.offset = this.data.writeUInt16LE(value, this.offset, true); }; /** @@ -93,7 +94,7 @@ StaticWriter.prototype.writeU16 = function writeU16(value) { */ StaticWriter.prototype.writeU16BE = function writeU16BE(value) { - this.written = this.data.writeUInt16BE(value, this.written, true); + this.offset = this.data.writeUInt16BE(value, this.offset, true); }; /** @@ -102,7 +103,7 @@ StaticWriter.prototype.writeU16BE = function writeU16BE(value) { */ StaticWriter.prototype.writeU32 = function writeU32(value) { - this.written = this.data.writeUInt32LE(value, this.written, true); + this.offset = this.data.writeUInt32LE(value, this.offset, true); }; /** @@ -111,7 +112,7 @@ StaticWriter.prototype.writeU32 = function writeU32(value) { */ StaticWriter.prototype.writeU32BE = function writeU32BE(value) { - this.written = this.data.writeUInt32BE(value, this.written, true); + this.offset = this.data.writeUInt32BE(value, this.offset, true); }; /** @@ -120,7 +121,7 @@ StaticWriter.prototype.writeU32BE = function writeU32BE(value) { */ StaticWriter.prototype.writeU64 = function writeU64(value) { - this.written = encoding.writeU64(this.data, value, this.written); + this.offset = encoding.writeU64(this.data, value, this.offset); }; /** @@ -129,25 +130,25 @@ StaticWriter.prototype.writeU64 = function writeU64(value) { */ StaticWriter.prototype.writeU64BE = function writeU64BE(value) { - this.written = encoding.writeU64BE(this.data, value, this.written); + this.offset = encoding.writeU64BE(this.data, value, this.offset); }; /** * Write uint64le. - * @param {BN} value + * @param {U64} value */ -StaticWriter.prototype.writeU64BN = function writeU64BN(value) { - assert(false, 'Not implemented.'); +StaticWriter.prototype.writeU64N = function writeU64N(value) { + this.offset = encoding.writeU64N(this.data, value, this.offset); }; /** * Write uint64be. - * @param {BN} value + * @param {U64} value */ -StaticWriter.prototype.writeU64BEBN = function writeU64BEBN(value) { - assert(false, 'Not implemented.'); +StaticWriter.prototype.writeU64BEN = function writeU64BEN(value) { + this.offset = encoding.writeU64BEN(this.data, value, this.offset); }; /** @@ -155,8 +156,8 @@ StaticWriter.prototype.writeU64BEBN = function writeU64BEBN(value) { * @param {Number} value */ -StaticWriter.prototype.write8 = function write8(value) { - this.written = this.data.writeInt8(value, this.written, true); +StaticWriter.prototype.writeI8 = function writeI8(value) { + this.offset = this.data.writeInt8(value, this.offset, true); }; /** @@ -164,8 +165,8 @@ StaticWriter.prototype.write8 = function write8(value) { * @param {Number} value */ -StaticWriter.prototype.write16 = function write16(value) { - this.written = this.data.writeInt16LE(value, this.written, true); +StaticWriter.prototype.writeI16 = function writeI16(value) { + this.offset = this.data.writeInt16LE(value, this.offset, true); }; /** @@ -173,8 +174,8 @@ StaticWriter.prototype.write16 = function write16(value) { * @param {Number} value */ -StaticWriter.prototype.write16BE = function write16BE(value) { - this.written = this.data.writeInt16BE(value, this.written, true); +StaticWriter.prototype.writeI16BE = function writeI16BE(value) { + this.offset = this.data.writeInt16BE(value, this.offset, true); }; /** @@ -182,8 +183,8 @@ StaticWriter.prototype.write16BE = function write16BE(value) { * @param {Number} value */ -StaticWriter.prototype.write32 = function write32(value) { - this.written = this.data.writeInt32LE(value, this.written, true); +StaticWriter.prototype.writeI32 = function writeI32(value) { + this.offset = this.data.writeInt32LE(value, this.offset, true); }; /** @@ -191,8 +192,8 @@ StaticWriter.prototype.write32 = function write32(value) { * @param {Number} value */ -StaticWriter.prototype.write32BE = function write32BE(value) { - this.written = this.data.writeInt32BE(value, this.written, true); +StaticWriter.prototype.writeI32BE = function writeI32BE(value) { + this.offset = this.data.writeInt32BE(value, this.offset, true); }; /** @@ -200,8 +201,8 @@ StaticWriter.prototype.write32BE = function write32BE(value) { * @param {Number} value */ -StaticWriter.prototype.write64 = function write64(value) { - this.written = encoding.write64(this.data, value, this.written); +StaticWriter.prototype.writeI64 = function writeI64(value) { + this.offset = encoding.writeI64(this.data, value, this.offset); }; /** @@ -209,26 +210,26 @@ StaticWriter.prototype.write64 = function write64(value) { * @param {Number} value */ -StaticWriter.prototype.write64BE = function write64BE(value) { - this.written = encoding.write64BE(this.data, value, this.written); +StaticWriter.prototype.writeI64BE = function writeI64BE(value) { + this.offset = encoding.writeI64BE(this.data, value, this.offset); }; /** * Write int64le. - * @param {BN} value + * @param {I64} value */ -StaticWriter.prototype.write64BN = function write64BN(value) { - assert(false, 'Not implemented.'); +StaticWriter.prototype.writeI64N = function writeI64N(value) { + this.offset = encoding.writeI64N(this.data, value, this.offset); }; /** * Write int64be. - * @param {BN} value + * @param {I64} value */ -StaticWriter.prototype.write64BEBN = function write64BEBN(value) { - assert(false, 'Not implemented.'); +StaticWriter.prototype.writeI64BEN = function writeI64BEN(value) { + this.offset = encoding.writeI64BEN(this.data, value, this.offset); }; /** @@ -237,7 +238,7 @@ StaticWriter.prototype.write64BEBN = function write64BEBN(value) { */ StaticWriter.prototype.writeFloat = function writeFloat(value) { - this.written = this.data.writeFloatLE(value, this.written, true); + this.offset = this.data.writeFloatLE(value, this.offset, true); }; /** @@ -246,7 +247,7 @@ StaticWriter.prototype.writeFloat = function writeFloat(value) { */ StaticWriter.prototype.writeFloatBE = function writeFloatBE(value) { - this.written = this.data.writeFloatBE(value, this.written, true); + this.offset = this.data.writeFloatBE(value, this.offset, true); }; /** @@ -255,7 +256,7 @@ StaticWriter.prototype.writeFloatBE = function writeFloatBE(value) { */ StaticWriter.prototype.writeDouble = function writeDouble(value) { - this.written = this.data.writeDoubleLE(value, this.written, true); + this.offset = this.data.writeDoubleLE(value, this.offset, true); }; /** @@ -264,7 +265,7 @@ StaticWriter.prototype.writeDouble = function writeDouble(value) { */ StaticWriter.prototype.writeDoubleBE = function writeDoubleBE(value) { - this.written = this.data.writeDoubleBE(value, this.written, true); + this.offset = this.data.writeDoubleBE(value, this.offset, true); }; /** @@ -273,16 +274,16 @@ StaticWriter.prototype.writeDoubleBE = function writeDoubleBE(value) { */ StaticWriter.prototype.writeVarint = function writeVarint(value) { - this.written = encoding.writeVarint(this.data, value, this.written); + this.offset = encoding.writeVarint(this.data, value, this.offset); }; /** * Write a varint. - * @param {BN} value + * @param {U64} value */ -StaticWriter.prototype.writeVarintBN = function writeVarintBN(value) { - assert(false, 'Not implemented.'); +StaticWriter.prototype.writeVarintN = function writeVarintN(value) { + this.offset = encoding.writeVarintN(this.data, value, this.offset); }; /** @@ -291,16 +292,16 @@ StaticWriter.prototype.writeVarintBN = function writeVarintBN(value) { */ StaticWriter.prototype.writeVarint2 = function writeVarint2(value) { - this.written = encoding.writeVarint2(this.data, value, this.written); + this.offset = encoding.writeVarint2(this.data, value, this.offset); }; /** * Write a varint (type 2). - * @param {BN} value + * @param {U64} value */ -StaticWriter.prototype.writeVarint2BN = function writeVarint2BN(value) { - assert(false, 'Not implemented.'); +StaticWriter.prototype.writeVarint2N = function writeVarint2N(value) { + this.offset = encoding.writeVarint2N(this.data, value, this.offset); }; /** @@ -312,9 +313,9 @@ StaticWriter.prototype.writeBytes = function writeBytes(value) { if (value.length === 0) return; - value.copy(this.data, this.written); + value.copy(this.data, this.offset); - this.written += value.length; + this.offset += value.length; }; /** @@ -335,13 +336,13 @@ StaticWriter.prototype.writeVarBytes = function writeVarBytes(value) { */ StaticWriter.prototype.copy = function copy(value, start, end) { - let len = end - start; + const len = end - start; if (len === 0) return; - value.copy(this.data, this.written, start, end); - this.written += len; + value.copy(this.data, this.offset, start, end); + this.offset += len; }; /** @@ -351,16 +352,14 @@ StaticWriter.prototype.copy = function copy(value, start, end) { */ StaticWriter.prototype.writeString = function writeString(value, enc) { - let size; - if (value.length === 0) return; - size = Buffer.byteLength(value, enc); + const size = Buffer.byteLength(value, enc); - this.data.write(value, this.written, enc); + this.data.write(value, this.offset, enc); - this.written += size; + this.offset += size; }; /** @@ -371,11 +370,12 @@ StaticWriter.prototype.writeString = function writeString(value, enc) { StaticWriter.prototype.writeHash = function writeHash(value) { if (typeof value !== 'string') { assert(value.length === 32); - return this.writeBytes(value); + this.writeBytes(value); + return; } assert(value.length === 64); - this.data.write(value, this.written, 'hex'); - this.written += 32; + this.data.write(value, this.offset, 'hex'); + this.offset += 32; }; /** @@ -385,19 +385,17 @@ StaticWriter.prototype.writeHash = function writeHash(value) { */ StaticWriter.prototype.writeVarString = function writeVarString(value, enc) { - let size; - if (value.length === 0) { this.writeVarint(0); return; } - size = Buffer.byteLength(value, enc); + const size = Buffer.byteLength(value, enc); this.writeVarint(size); - this.data.write(value, this.written, enc); + this.data.write(value, this.offset, enc); - this.written += size; + this.offset += size; }; /** @@ -416,10 +414,10 @@ StaticWriter.prototype.writeNullString = function writeNullString(value, enc) { */ StaticWriter.prototype.writeChecksum = function writeChecksum() { - let data = this.data.slice(0, this.written); - let hash = digest.hash256(data); - hash.copy(this.data, this.written, 0, 4); - this.written += 4; + const data = this.data.slice(0, this.offset); + const hash = digest.hash256(data); + hash.copy(this.data, this.offset, 0, 4); + this.offset += 4; }; /** @@ -434,8 +432,8 @@ StaticWriter.prototype.fill = function fill(value, size) { if (size === 0) return; - this.data.fill(value, this.written, this.written + size); - this.written += size; + this.data.fill(value, this.offset, this.offset + size); + this.offset += size; }; /* diff --git a/lib/utils/util.js b/lib/utils/util.js index 447c2194e..ffe898ef1 100644 --- a/lib/utils/util.js +++ b/lib/utils/util.js @@ -16,170 +16,112 @@ const nodeUtil = require('util'); const util = exports; -/** - * Return hrtime (shim for browser). - * @param {Array} time - * @returns {Array} +/* + * Constants */ -util.hrtime = function hrtime(time) { - if (!process.hrtime) { - let now = util.ms(); - let ms, sec; - - if (time) { - time = time[0] * 1000 + time[1] / 1e6; - now -= time; - return now; - } - - ms = now % 1000; - sec = (now - ms) / 1000; - return [sec, ms * 1e6]; - } - - if (time) { - let elapsed = process.hrtime(time); - return elapsed[0] * 1000 + elapsed[1] / 1e6; - } - - return process.hrtime(); +const inspectOptions = { + showHidden: false, + depth: 20, + colors: false, + customInspect: true, + showProxy: false, + maxArrayLength: Infinity, + breakLength: 60 }; /** - * Test whether a string is base58 (note that you - * may get a false positive on a hex string). - * @param {String?} obj + * Test whether a number is Number, + * finite, and below MAX_SAFE_INTEGER. + * @param {Number?} value * @returns {Boolean} */ -util.isBase58 = function isBase58(obj) { - return typeof obj === 'string' && /^[1-9a-zA-Z]+$/.test(obj); +util.isNumber = function isNumber(value) { + return typeof value === 'number' + && isFinite(value) + && value >= -Number.MAX_SAFE_INTEGER + && value <= Number.MAX_SAFE_INTEGER; }; /** - * Test whether a string is hex (length must be even). - * Note that this _could_ await a false positive on - * base58 strings. - * @param {String?} obj + * Test whether an object is an int. + * @param {Number?} value * @returns {Boolean} */ -util.isHex = function isHex(obj) { - return typeof obj === 'string' - && /^[0-9a-f]+$/i.test(obj) - && obj.length % 2 === 0; +util.isInt = function isInt(value) { + return Number.isSafeInteger(value); }; /** - * Reverse a hex-string (used because of - * bitcoind's affinity for uint256le). - * @param {String} data - Hex string. - * @returns {String} Reversed hex string. + * Test whether an object is a uint. + * @param {Number?} value + * @returns {Boolean} */ -util.revHex = function revHex(data) { - let out = ''; - - assert(typeof data === 'string'); - assert(data.length > 0); - assert(data.length % 2 === 0); - - for (let i = 0; i < data.length; i += 2) - out = data.slice(i, i + 2) + out; - - return out; +util.isUint = function isUint(value) { + return util.isInt(value) && value >= 0; }; /** - * Test whether a number is below MAX_SAFE_INTEGER. - * @param {Number} value + * Test whether a number is a float. + * @param {Number?} value * @returns {Boolean} */ -util.isSafeInteger = function isSafeInteger(value) { - return Number.isSafeInteger(value); +util.isFloat = function isFloat(value) { + return typeof value === 'number' && isFinite(value); }; /** - * Test whether the result of a positive - * addition would be below MAX_SAFE_INTEGER. - * @param {Number} value + * Test whether a number is a positive float. + * @param {Number?} value * @returns {Boolean} */ -util.isSafeAddition = function isSafeAddition(a, b) { - let hi, lo, ahi, alo, bhi, blo; - let as, bs, s, c; - - // We only work on positive numbers. - assert(a >= 0); - assert(b >= 0); - - // Fast case. - if (a <= 0xfffffffffffff && b <= 0xfffffffffffff) - return true; - - // Do a 64 bit addition and check the top 11 bits. - ahi = (a * (1 / 0x100000000)) | 0; - alo = a | 0; - - bhi = (b * (1 / 0x100000000)) | 0; - blo = b | 0; - - // Credit to @indutny for this method. - lo = (alo + blo) | 0; - - s = lo >> 31; - as = alo >> 31; - bs = blo >> 31; - - c = ((as & bs) | (~s & (as ^ bs))) & 1; - - hi = (((ahi + bhi) | 0) + c) | 0; - - hi >>>= 0; - ahi >>>= 0; - bhi >>>= 0; +util.isUfloat = function isUfloat(value) { + return util.isFloat(value) && value >= 0; +}; - // Overflow? - if (hi < ahi || hi < bhi) - return false; +/** + * Test whether an object is an int8. + * @param {Number?} value + * @returns {Boolean} + */ - return (hi & 0xffe00000) === 0; +util.isI8 = function isI8(value) { + return (value | 0) === value && value >= -0x80 && value <= 0x7f; }; /** - * Test whether a number is Number, - * finite, and below MAX_SAFE_INTEGER. + * Test whether an object is an int16. * @param {Number?} value * @returns {Boolean} */ -util.isNumber = function isNumber(value) { - return typeof value === 'number' - && isFinite(value) - && util.isSafeInteger(value); +util.isI16 = function isI16(value) { + return (value | 0) === value && value >= -0x8000 && value <= 0x7fff; }; /** - * Test whether an object is an int. + * Test whether an object is an int32. * @param {Number?} value * @returns {Boolean} */ -util.isInt = function isInt(value) { - return util.isNumber(value) && value % 1 === 0; +util.isI32 = function isI32(value) { + return (value | 0) === value; }; /** - * Test whether an object is an int8. + * Test whether an object is a int53. * @param {Number?} value * @returns {Boolean} */ -util.isInt8 = function isInt8(value) { - return (value | 0) === value && value >= -0x80 && value <= 0x7f; +util.isI64 = function isI64(value) { + return util.isInt(value); }; /** @@ -188,18 +130,18 @@ util.isInt8 = function isInt8(value) { * @returns {Boolean} */ -util.isUInt8 = function isUInt8(value) { - return (value >>> 0) === value && value >= 0 && value <= 0xff; +util.isU8 = function isU8(value) { + return (value & 0xff) === value; }; /** - * Test whether an object is an int32. + * Test whether an object is a uint16. * @param {Number?} value * @returns {Boolean} */ -util.isInt32 = function isInt32(value) { - return (value | 0) === value; +util.isU16 = function isU16(value) { + return (value & 0xffff) === value; }; /** @@ -208,66 +150,123 @@ util.isInt32 = function isInt32(value) { * @returns {Boolean} */ -util.isUInt32 = function isUInt32(value) { +util.isU32 = function isU32(value) { return (value >>> 0) === value; }; /** - * Test whether an object is a int53. + * Test whether an object is a uint53. * @param {Number?} value * @returns {Boolean} */ -util.isInt53 = function isInt53(value) { - return util.isInt(value); +util.isU64 = function isU64(value) { + return util.isUint(value); }; /** - * Test whether an object is a uint53. - * @param {Number?} value + * Test whether a string is a plain + * ascii string (no control characters). + * @param {String} str * @returns {Boolean} */ -util.isUInt53 = function isUInt53(value) { - return util.isInt(value) && value >= 0; +util.isAscii = function isAscii(str) { + return typeof str === 'string' && /^[\t\n\r -~]*$/.test(str); +}; + +/** + * Test whether a string is base58 (note that you + * may get a false positive on a hex string). + * @param {String?} str + * @returns {Boolean} + */ + +util.isBase58 = function isBase58(str) { + return typeof str === 'string' && /^[1-9A-Za-z]+$/.test(str); +}; + +/** + * Test whether a string is hex (length must be even). + * Note that this _could_ await a false positive on + * base58 strings. + * @param {String?} str + * @returns {Boolean} + */ + +util.isHex = function isHex(str) { + if (typeof str !== 'string') + return false; + return str.length % 2 === 0 && /^[0-9A-Fa-f]+$/.test(str); }; /** * Test whether an object is a 160 bit hash (hex string). - * @param {String?} value + * @param {String?} hash * @returns {Boolean} */ util.isHex160 = function isHex160(hash) { - return util.isHex(hash) && hash.length === 40; + if (typeof hash !== 'string') + return false; + return hash.length === 40 && util.isHex(hash); }; /** * Test whether an object is a 256 bit hash (hex string). - * @param {String?} value + * @param {String?} hash * @returns {Boolean} */ util.isHex256 = function isHex256(hash) { - return util.isHex(hash) && hash.length === 64; + if (typeof hash !== 'string') + return false; + return hash.length === 64 && util.isHex(hash); }; /** - * Test whether a string qualifies as a float. - * - * This is stricter than checking if the result of parseFloat() is NaN - * as, e.g. parseFloat successfully parses the string '1.2.3' as 1.2, and - * we also check that the value is a string. - * - * @param {String?} value + * Test whether the result of a positive + * addition would be below MAX_SAFE_INTEGER. + * @param {Number} value * @returns {Boolean} */ -util.isFloat = function isFloat(value) { - return typeof value === 'string' - && /^-?(\d+)?(?:\.\d*)?$/.test(value) - && value.length !== 0 - && value !== '-'; +util.isSafeAddition = function isSafeAddition(a, b) { + // We only work on positive numbers. + assert(a >= 0); + assert(b >= 0); + + // Fast case. + if (a <= 0xfffffffffffff && b <= 0xfffffffffffff) + return true; + + // Do a 64 bit addition and check the top 11 bits. + let ahi = (a * (1 / 0x100000000)) | 0; + const alo = a | 0; + + let bhi = (b * (1 / 0x100000000)) | 0; + const blo = b | 0; + + // Credit to @indutny for this method. + const lo = (alo + blo) | 0; + + const s = lo >> 31; + const as = alo >> 31; + const bs = blo >> 31; + + const c = ((as & bs) | (~s & (as ^ bs))) & 1; + + let hi = (((ahi + bhi) | 0) + c) | 0; + + hi >>>= 0; + ahi >>>= 0; + bhi >>>= 0; + + // Overflow? + if (hi < ahi || hi < bhi) + return false; + + return (hi & 0xffe00000) === 0; }; /** @@ -278,9 +277,12 @@ util.isFloat = function isFloat(value) { */ util.inspectify = function inspectify(obj, color) { - return typeof obj !== 'string' - ? nodeUtil.inspect(obj, null, 20, color !== false) - : obj; + if (typeof obj === 'string') + return obj; + + inspectOptions.colors = color !== false; + + return nodeUtil.inspect(obj, inspectOptions); }; /** @@ -300,12 +302,12 @@ util.fmt = nodeUtil.format; */ util.format = function format(args, color) { - if (color == null) - color = process.stdout ? process.stdout.isTTY : false; - - return typeof args[0] === 'object' - ? util.inspectify(args[0], color) - : util.fmt.apply(util, args); + if (args.length > 0 && args[0] && typeof args[0] === 'object') { + if (color == null) + color = Boolean(process.stdout && process.stdout.isTTY); + return util.inspectify(args[0], color); + } + return util.fmt(...args); }; /** @@ -315,17 +317,19 @@ util.format = function format(args, color) { */ util.log = function log(...args) { - let msg; - if (!process.stdout) { - msg = typeof args[0] !== 'object' - ? util.format(args, false) - : args[0]; + let msg; + if (args.length > 0) { + msg = typeof args[0] !== 'object' + ? util.fmt(...args) + : args[0]; + } console.log(msg); return; } - msg = util.format(args); + const msg = util.format(args); + process.stdout.write(msg + '\n'); }; @@ -336,20 +340,57 @@ util.log = function log(...args) { */ util.error = function error(...args) { - let msg; - if (!process.stderr) { - msg = typeof args[0] !== 'object' - ? util.format(args, false) - : args[0]; + let msg; + if (args.length > 0) { + msg = typeof args[0] !== 'object' + ? util.fmt(...args) + : args[0]; + } console.error(msg); return; } - msg = util.format(args); + const msg = util.format(args); + process.stderr.write(msg + '\n'); }; +/** + * Return hrtime (shim for browser). + * @param {Array} time + * @returns {Array} [seconds, nanoseconds] + */ + +util.hrtime = function hrtime(time) { + if (!process.hrtime) { + const now = util.ms(); + + if (time) { + const [hi, lo] = time; + const start = hi * 1000 + lo / 1e6; + return now - start; + } + + const ms = now % 1000; + + // Seconds + const hi = (now - ms) / 1000; + + // Nanoseconds + const lo = ms * 1e6; + + return [hi, lo]; + } + + if (time) { + const [hi, lo] = process.hrtime(time); + return hi * 1000 + lo / 1e6; + } + + return process.hrtime(); +}; + /** * Get current time in unix time (seconds). * @returns {Number} @@ -365,27 +406,25 @@ util.now = function now() { */ util.ms = function ms() { - if (Date.now) - return Date.now(); - return +new Date(); + return Date.now(); }; /** * Create a Date ISO string from time in unix time (seconds). - * @param {Number?} ts - Seconds in unix time. + * @param {Number?} time - Seconds in unix time. * @returns {String} */ -util.date = function date(ts) { - if (ts == null) - ts = util.now(); +util.date = function date(time) { + if (time == null) + time = util.now(); - return new Date(ts * 1000).toISOString().slice(0, -5) + 'Z'; + return new Date(time * 1000).toISOString().slice(0, -5) + 'Z'; }; /** * Get unix seconds from a Date string. - * @param {String} date - Date ISO String. + * @param {String?} date - Date ISO String. * @returns {Number} */ @@ -413,31 +452,31 @@ util.random = function random(min, max) { * @returns {Buffer} */ -util.nonce = function _nonce(size) { - let n, nonce; +util.nonce = function nonce(size) { + let n, data; if (!size) size = 8; switch (size) { case 8: - nonce = Buffer.allocUnsafe(8); + data = Buffer.allocUnsafe(8); n = util.random(0, 0x100000000); - nonce.writeUInt32LE(n, 0, true); + data.writeUInt32LE(n, 0, true); n = util.random(0, 0x100000000); - nonce.writeUInt32LE(n, 4, true); + data.writeUInt32LE(n, 4, true); break; case 4: - nonce = Buffer.allocUnsafe(4); + data = Buffer.allocUnsafe(4); n = util.random(0, 0x100000000); - nonce.writeUInt32LE(n, 0, true); + data.writeUInt32LE(n, 0, true); break; default: assert(false, 'Bad nonce size.'); break; } - return nonce; + return data; }; /** @@ -448,7 +487,7 @@ util.nonce = function _nonce(size) { */ util.strcmp = function strcmp(a, b) { - let len = Math.min(a.length, b.length); + const len = Math.min(a.length, b.length); for (let i = 0; i < len; i++) { if (a[i] < b[i]) @@ -476,21 +515,6 @@ util.mb = function mb(size) { return Math.floor(size / 1024 / 1024); }; -/** - * Inheritance. - * @param {Function} child - Constructor to inherit. - * @param {Function} parent - Parent constructor. - */ - -util.inherits = function inherits(child, parent) { - child.super_ = parent; - Object.setPrototypeOf(child.prototype, parent.prototype); - Object.defineProperty(child.prototype, 'constructor', { - value: child, - enumerable: false - }); -}; - /** * Find index of a buffer in an array of buffers. * @param {Buffer[]} items @@ -503,8 +527,10 @@ util.indexOf = function indexOf(items, data) { assert(Buffer.isBuffer(data)); for (let i = 0; i < items.length; i++) { - let item = items[i]; + const item = items[i]; + assert(Buffer.isBuffer(item)); + if (item.equals(data)) return i; } @@ -520,8 +546,11 @@ util.indexOf = function indexOf(items, data) { */ util.pad8 = function pad8(num) { + assert(typeof num === 'number'); assert(num >= 0); - num = num + ''; + + num = num.toString(10); + switch (num.length) { case 1: return '00' + num; @@ -530,7 +559,8 @@ util.pad8 = function pad8(num) { case 3: return num; } - assert(false); + + throw new Error('Number too big.'); }; /** @@ -541,8 +571,11 @@ util.pad8 = function pad8(num) { */ util.pad32 = function pad32(num) { + assert(typeof num === 'number'); assert(num >= 0); - num = num + ''; + + num = num.toString(10); + switch (num.length) { case 1: return '000000000' + num; @@ -564,9 +597,9 @@ util.pad32 = function pad32(num) { return '0' + num; case 10: return num; - default: - assert(false); } + + throw new Error('Number too big.'); }; /** @@ -577,16 +610,19 @@ util.pad32 = function pad32(num) { */ util.hex8 = function hex8(num) { + assert(typeof num === 'number'); assert(num >= 0); + num = num.toString(16); + switch (num.length) { case 1: return '0' + num; case 2: return num; - default: - assert(false); } + + throw new Error('Number too big.'); }; /** @@ -597,8 +633,11 @@ util.hex8 = function hex8(num) { */ util.hex32 = function hex32(num) { + assert(typeof num === 'number'); assert(num >= 0); + num = num.toString(16); + switch (num.length) { case 1: return '0000000' + num; @@ -616,56 +655,44 @@ util.hex32 = function hex32(num) { return '0' + num; case 8: return num; - default: - assert(false); } -}; - -/** - * Convert an array to a map. - * @param {String[]} items - * @returns {Object} Map. - */ - -util.toMap = function toMap(items) { - let map = {}; - for (let value of items) - map[value] = true; - - return map; + throw new Error('Number too big.'); }; /** - * Reverse a map. - * @param {Object} map - * @returns {Object} Reversed map. + * Reverse a hex-string (used because of + * bitcoind's affinity for uint256le). + * @param {String} data - Hex string. + * @returns {String} Reversed hex string. */ -util.revMap = function revMap(map) { - let reversed = {}; - let keys = Object.keys(map); +util.revHex = function revHex(data) { + assert(typeof data === 'string'); + assert(data.length > 0); + assert(data.length % 2 === 0); + + let out = ''; - for (let key of keys) - reversed[map[key]] = key; + for (let i = 0; i < data.length; i += 2) + out = data.slice(i, i + 2) + out; - return reversed; + return out; }; /** - * Get object values. - * @param {Object} map - * @returns {Array} Values. + * Reverse an object's keys and values. + * @param {Object} obj + * @returns {Object} Reversed object. */ -util.values = function values(map) { - let keys = Object.keys(map); - let out = []; +util.reverse = function reverse(obj) { + const reversed = {}; - for (let key of keys) - out.push(map[key]); + for (const key of Object.keys(obj)) + reversed[obj[key]] = key; - return out; + return reversed; }; /** @@ -682,8 +709,8 @@ util.binarySearch = function binarySearch(items, key, compare, insert) { let end = items.length - 1; while (start <= end) { - let pos = (start + end) >>> 1; - let cmp = compare(items[pos], key); + const pos = (start + end) >>> 1; + const cmp = compare(items[pos], key); if (cmp === 0) return pos; @@ -709,7 +736,7 @@ util.binarySearch = function binarySearch(items, key, compare, insert) { */ util.binaryInsert = function binaryInsert(items, item, compare, uniq) { - let i = util.binarySearch(items, item, compare, true); + const i = util.binarySearch(items, item, compare, true); if (uniq && i < items.length) { if (compare(items[i], item) === 0) @@ -735,7 +762,7 @@ util.binaryInsert = function binaryInsert(items, item, compare, uniq) { */ util.binaryRemove = function binaryRemove(items, item, compare) { - let i = util.binarySearch(items, item, compare, false); + const i = util.binarySearch(items, item, compare, false); if (i === -1) return false; @@ -752,8 +779,11 @@ util.binaryRemove = function binaryRemove(items, item, compare) { */ util.isUpperCase = function isUpperCase(str) { + assert(typeof str === 'string'); + if (str.length === 0) return false; + return (str.charCodeAt(0) & 32) === 0; }; @@ -764,15 +794,14 @@ util.isUpperCase = function isUpperCase(str) { * @returns {Boolean} */ -util.startsWith = function startsWiths(str, prefix) { - return str.startsWith(prefix); -}; +util.startsWith = function startsWith(str, prefix) { + assert(typeof str === 'string'); -if (!''.startsWith) { - util.startsWith = function startsWith(str, prefix) { + if (!str.startsWith) return str.indexOf(prefix) === 0; - }; -} + + return str.startsWith(prefix); +}; /** * Get memory usage info. @@ -780,8 +809,6 @@ if (!''.startsWith) { */ util.memoryUsage = function memoryUsage() { - let mem; - if (!process.memoryUsage) { return { total: 0, @@ -792,7 +819,7 @@ util.memoryUsage = function memoryUsage() { }; } - mem = process.memoryUsage(); + const mem = process.memoryUsage(); return { total: util.mb(mem.rss), @@ -802,3 +829,209 @@ util.memoryUsage = function memoryUsage() { external: util.mb(mem.external) }; }; + +/** + * Convert int to fixed number string and reduce by a + * power of ten (uses no floating point arithmetic). + * @param {Number} num + * @param {Number} exp - Number of decimal places. + * @returns {String} Fixed number string. + */ + +util.toFixed = function toFixed(num, exp) { + assert(typeof num === 'number'); + assert(Number.isSafeInteger(num), 'Invalid integer value.'); + + let sign = ''; + + if (num < 0) { + num = -num; + sign = '-'; + } + + const mult = pow10(exp); + let lo = num % mult; + const hi = (num - lo) / mult; + + lo = lo.toString(10); + + while (lo.length < exp) + lo = '0' + lo; + + lo = lo.replace(/0+$/, ''); + + assert(lo.length <= exp, 'Invalid integer value.'); + + if (lo.length === 0) + lo = '0'; + + if (exp === 0) + return `${sign}${hi}`; + + return `${sign}${hi}.${lo}`; +}; + +/** + * Parse a fixed number string and multiply by a + * power of ten (uses no floating point arithmetic). + * @param {String} str + * @param {Number} exp - Number of decimal places. + * @returns {Number} Integer. + */ + +util.fromFixed = function fromFixed(str, exp) { + assert(typeof str === 'string'); + assert(str.length <= 32, 'Fixed number string too large.'); + + let sign = 1; + + if (str.length > 0 && str[0] === '-') { + str = str.substring(1); + sign = -1; + } + + let hi = str; + let lo = '0'; + + const index = str.indexOf('.'); + + if (index !== -1) { + hi = str.substring(0, index); + lo = str.substring(index + 1); + } + + hi = hi.replace(/^0+/, ''); + lo = lo.replace(/0+$/, ''); + + assert(hi.length <= 16 - exp, + 'Fixed number string exceeds 2^53-1.'); + + assert(lo.length <= exp, + 'Too many decimal places in fixed number string.'); + + if (hi.length === 0) + hi = '0'; + + while (lo.length < exp) + lo += '0'; + + if (lo.length === 0) + lo = '0'; + + assert(/^\d+$/.test(hi) && /^\d+$/.test(lo), + 'Non-numeric characters in fixed number string.'); + + hi = parseInt(hi, 10); + lo = parseInt(lo, 10); + + const mult = pow10(exp); + const maxLo = modSafe(mult); + const maxHi = divSafe(mult); + + assert(hi < maxHi || (hi === maxHi && lo <= maxLo), + 'Fixed number string exceeds 2^53-1.'); + + return sign * (hi * mult + lo); +}; + +/** + * Convert int to float and reduce by a power + * of ten (uses no floating point arithmetic). + * @param {Number} num + * @param {Number} exp - Number of decimal places. + * @returns {Number} Double float. + */ + +util.toFloat = function toFloat(num, exp) { + return Number(util.toFixed(num, exp)); +}; + +/** + * Parse a double float number and multiply by a + * power of ten (uses no floating point arithmetic). + * @param {Number} num + * @param {Number} exp - Number of decimal places. + * @returns {Number} Integer. + */ + +util.fromFloat = function fromFloat(num, exp) { + assert(typeof num === 'number' && isFinite(num)); + assert(Number.isSafeInteger(exp)); + return util.fromFixed(num.toFixed(exp), exp); +}; + +/* + * Helpers + */ + +function pow10(exp) { + switch (exp) { + case 0: + return 1; + case 1: + return 10; + case 2: + return 100; + case 3: + return 1000; + case 4: + return 10000; + case 5: + return 100000; + case 6: + return 1000000; + case 7: + return 10000000; + case 8: + return 100000000; + } + throw new Error('Exponent is too large.'); +} + +function modSafe(mod) { + switch (mod) { + case 1: + return 0; + case 10: + return 1; + case 100: + return 91; + case 1000: + return 991; + case 10000: + return 991; + case 100000: + return 40991; + case 1000000: + return 740991; + case 10000000: + return 4740991; + case 100000000: + return 54740991; + } + throw new Error('Exponent is too large.'); +} + +function divSafe(div) { + switch (div) { + case 1: + return 9007199254740991; + case 10: + return 900719925474099; + case 100: + return 90071992547409; + case 1000: + return 9007199254740; + case 10000: + return 900719925474; + case 100000: + return 90071992547; + case 1000000: + return 9007199254; + case 10000000: + return 900719925; + case 100000000: + return 90071992; + } + throw new Error('Exponent is too large.'); +} diff --git a/lib/utils/validator.js b/lib/utils/validator.js index 922284362..159851433 100644 --- a/lib/utils/validator.js +++ b/lib/utils/validator.js @@ -7,6 +7,7 @@ 'use strict'; const assert = require('assert'); +const util = require('../utils/util'); /** * Validator @@ -48,10 +49,10 @@ Validator.prototype.init = function init(data) { Validator.prototype.has = function has(key) { assert(typeof key === 'string' || typeof key === 'number', - 'Key must be a string.'); + 'Key must be a string or number.'); - for (let map of this.data) { - let value = map[key]; + for (const map of this.data) { + const value = map[key]; if (value != null) return true; } @@ -71,9 +72,9 @@ Validator.prototype.get = function get(key, fallback) { fallback = null; if (Array.isArray(key)) { - let keys = key; - for (let key of keys) { - let value = this.get(key); + const keys = key; + for (const key of keys) { + const value = this.get(key); if (value !== null) return value; } @@ -81,15 +82,13 @@ Validator.prototype.get = function get(key, fallback) { } assert(typeof key === 'string' || typeof key === 'number', - 'Key must be a string.'); - - for (let map of this.data) { - let value; + 'Key must be a string or number.'); + for (const map of this.data) { if (!map || typeof map !== 'object') throw new ValidationError('data', 'object'); - value = map[key]; + const value = map[key]; if (value != null) return value; @@ -98,6 +97,21 @@ Validator.prototype.get = function get(key, fallback) { return fallback; }; +/** + * Get a value's type. + * @param {String} key + * @returns {String} + */ + +Validator.prototype.typeOf = function typeOf(key) { + const value = this.get(key); + + if (value == null) + return 'null'; + + return typeof value; +}; + /** * Get a value (as a string). * @param {String} key @@ -106,7 +120,7 @@ Validator.prototype.get = function get(key, fallback) { */ Validator.prototype.str = function str(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -121,13 +135,13 @@ Validator.prototype.str = function str(key, fallback) { }; /** - * Get a value (as a number). + * Get a value (as an integer). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.num = function num(key, fallback) { +Validator.prototype.int = function int(key, fallback) { let value = this.get(key); if (fallback === undefined) @@ -138,29 +152,55 @@ Validator.prototype.num = function num(key, fallback) { if (typeof value !== 'string') { if (typeof value !== 'number') - throw new ValidationError(key, 'number'); + throw new ValidationError(key, 'int'); + + if (!Number.isSafeInteger(value)) + throw new ValidationError(key, 'int'); + return value; } - if (!/^\d+$/.test(value)) - throw new ValidationError(key, 'number'); + if (!/^\-?\d+$/.test(value)) + throw new ValidationError(key, 'int'); value = parseInt(value, 10); - if (!isFinite(value)) - throw new ValidationError(key, 'number'); + if (!Number.isSafeInteger(value)) + throw new ValidationError(key, 'int'); + + return value; +}; + +/** + * Get a value (as a signed integer). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.uint = function uint(key, fallback) { + const value = this.int(key); + + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; + + if (value < 0) + throw new ValidationError(key, 'uint'); return value; }; /** - * Get a value (as a number). + * Get a value (as a float). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.flt = function flt(key, fallback) { +Validator.prototype.float = function float(key, fallback) { let value = this.get(key); if (fallback === undefined) @@ -172,10 +212,17 @@ Validator.prototype.flt = function flt(key, fallback) { if (typeof value !== 'string') { if (typeof value !== 'number') throw new ValidationError(key, 'float'); + + if (!isFinite(value)) + throw new ValidationError(key, 'float'); + return value; } - if (!/^\d*(?:\.\d*)?$/.test(value)) + if (!/^\-?\d*(?:\.\d*)?$/.test(value)) + throw new ValidationError(key, 'float'); + + if (!/\d/.test(value)) throw new ValidationError(key, 'float'); value = parseFloat(value); @@ -187,14 +234,14 @@ Validator.prototype.flt = function flt(key, fallback) { }; /** - * Get a value (as a uint32). + * Get a value (as a positive float). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.u32 = function u32(key, fallback) { - let value = this.num(key); +Validator.prototype.ufloat = function ufloat(key, fallback) { + const value = this.float(key); if (fallback === undefined) fallback = null; @@ -202,21 +249,46 @@ Validator.prototype.u32 = function u32(key, fallback) { if (value === null) return fallback; - if ((value >>> 0) !== value) - throw new ValidationError(key, 'uint32'); + if (value < 0) + throw new ValidationError(key, 'positive float'); return value; }; /** - * Get a value (as a uint64). + * Get a value (as a fixed number). * @param {String} key + * @param {Number?} exp * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.u64 = function u64(key, fallback) { - let value = this.num(key); +Validator.prototype.fixed = function fixed(key, exp, fallback) { + const value = this.float(key); + + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; + + try { + return util.fromFloat(value, exp || 0); + } catch (e) { + throw new ValidationError(key, 'fixed number'); + } +}; + +/** + * Get a value (as a positive fixed number). + * @param {String} key + * @param {Number?} exp + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.ufixed = function ufixed(key, exp, fallback) { + const value = this.fixed(key, exp); if (fallback === undefined) fallback = null; @@ -224,8 +296,8 @@ Validator.prototype.u64 = function u64(key, fallback) { if (value === null) return fallback; - if (value % 1 !== 0 || value < 0 || value > 0x1fffffffffffff) - throw new ValidationError(key, 'uint64'); + if (value < 0) + throw new ValidationError(key, 'positive fixed number'); return value; }; @@ -237,8 +309,8 @@ Validator.prototype.u64 = function u64(key, fallback) { * @returns {Number|null} */ -Validator.prototype.i32 = function i32(key, fallback) { - let value = this.num(key); +Validator.prototype.i8 = function i8(key, fallback) { + const value = this.int(key); if (fallback === undefined) fallback = null; @@ -246,21 +318,21 @@ Validator.prototype.i32 = function i32(key, fallback) { if (value === null) return fallback; - if ((value | 0) !== value) - throw new ValidationError(key, 'int32'); + if (value < -0x80 || value > 0x7f) + throw new ValidationError(key, 'i8'); return value; }; /** - * Get a value (as an int64). + * Get a value (as an int32). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.i64 = function i64(key, fallback) { - let value = this.num(key); +Validator.prototype.i16 = function i16(key, fallback) { + const value = this.int(key); if (fallback === undefined) fallback = null; @@ -268,21 +340,21 @@ Validator.prototype.i64 = function i64(key, fallback) { if (value === null) return fallback; - if (value % 1 !== 0 || Math.abs(value) > 0x1fffffffffffff) - throw new ValidationError(key, 'int64'); + if (value < -0x8000 || value > 0x7fff) + throw new ValidationError(key, 'i16'); return value; }; /** - * Get a value (as a satoshi number or btc string). + * Get a value (as an int32). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.amt = function amt(key, fallback) { - let value = this.get(key); +Validator.prototype.i32 = function i32(key, fallback) { + const value = this.int(key); if (fallback === undefined) fallback = null; @@ -290,37 +362,54 @@ Validator.prototype.amt = function amt(key, fallback) { if (value === null) return fallback; - if (typeof value !== 'string') { - if (typeof value !== 'number') - throw new ValidationError(key, 'amount'); - return value; - } + if ((value | 0) !== value) + throw new ValidationError(key, 'int32'); - if (!/^\d+(\.\d{0,8})?$/.test(value)) - throw new ValidationError(key, 'amount'); + return value; +}; - value = parseFloat(value); +/** + * Get a value (as an int64). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ - if (!isFinite(value)) - throw new ValidationError(key, 'amount'); +Validator.prototype.i64 = function i64(key, fallback) { + return this.int(key, fallback); +}; + +/** + * Get a value (as a uint32). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.u8 = function u8(key, fallback) { + const value = this.uint(key); - value *= 1e8; + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; - if (value % 1 !== 0 || value < 0 || value > 0x1fffffffffffff) - throw new ValidationError(key, 'amount (uint64)'); + if ((value & 0xff) !== value) + throw new ValidationError(key, 'uint8'); return value; }; /** - * Get a value (as a btc float). + * Get a value (as a uint16). * @param {String} key * @param {Object?} fallback * @returns {Number|null} */ -Validator.prototype.btc = function btc(key, fallback) { - let value = this.num(key); +Validator.prototype.u16 = function u16(key, fallback) { + const value = this.uint(key); if (fallback === undefined) fallback = null; @@ -328,14 +417,45 @@ Validator.prototype.btc = function btc(key, fallback) { if (value === null) return fallback; - value *= 1e8; + if ((value & 0xffff) !== value) + throw new ValidationError(key, 'uint16'); + + return value; +}; + +/** + * Get a value (as a uint32). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.u32 = function u32(key, fallback) { + const value = this.uint(key); + + if (fallback === undefined) + fallback = null; - if (value % 1 !== 0 || value < 0 || value > 0x1fffffffffffff) - throw new ValidationError(key, 'btc float (uint64)'); + if (value === null) + return fallback; + + if ((value >>> 0) !== value) + throw new ValidationError(key, 'uint32'); return value; }; +/** + * Get a value (as a uint64). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.u64 = function u64(key, fallback) { + return this.uint(key, fallback); +}; + /** * Get a value (as a reverse hash). * @param {String} key @@ -344,8 +464,7 @@ Validator.prototype.btc = function btc(key, fallback) { */ Validator.prototype.hash = function hash(key, fallback) { - let value = this.get(key); - let out = ''; + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -369,6 +488,8 @@ Validator.prototype.hash = function hash(key, fallback) { if (!/^[0-9a-f]+$/i.test(value)) throw new ValidationError(key, 'hex string'); + let out = ''; + for (let i = 0; i < value.length; i += 2) out = value.slice(i, i + 2) + out; @@ -383,46 +504,9 @@ Validator.prototype.hash = function hash(key, fallback) { */ Validator.prototype.numhash = function numhash(key, fallback) { - let value = this.get(key); - - if (value === null) - return fallback; - - if (typeof value === 'string') - return this.hash(key); - - return this.num(key); -}; - -/** - * Get a value (as a number or string). - * @param {String} key - * @param {Object?} fallback - * @returns {Number|String|null} - */ - -Validator.prototype.numstr = function numstr(key, fallback) { - let value = this.get(key); - let num; - - if (fallback === undefined) - fallback = null; - - if (value === null) - return fallback; - - if (typeof value !== 'string') { - if (typeof value !== 'number') - throw new ValidationError(key, 'number or string'); - return value; - } - - num = parseInt(value, 10); - - if (!isFinite(num)) - return value; - - return num; + if (this.typeOf(key) === 'string') + return this.hash(key, fallback); + return this.uint(key, fallback); }; /** @@ -433,7 +517,7 @@ Validator.prototype.numstr = function numstr(key, fallback) { */ Validator.prototype.bool = function bool(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -441,13 +525,14 @@ Validator.prototype.bool = function bool(key, fallback) { if (value === null) return fallback; - // bitcoin core mixes semantics of truthiness amoung rpc methods - // most "verbose" parameters are bools, but getrawtransaction is 1/0 - if (value === 1) - return true; + // Bitcoin Core compat. + if (typeof value === 'number') { + if (value === 1) + return true; - if (value === 0) - return false; + if (value === 0) + return false; + } if (typeof value !== 'string') { if (typeof value !== 'boolean') @@ -473,8 +558,7 @@ Validator.prototype.bool = function bool(key, fallback) { */ Validator.prototype.buf = function buf(key, fallback, enc) { - let value = this.get(key); - let data; + const value = this.get(key); if (!enc) enc = 'hex'; @@ -491,7 +575,7 @@ Validator.prototype.buf = function buf(key, fallback, enc) { return value; } - data = Buffer.from(value, enc); + const data = Buffer.from(value, enc); if (data.length !== Buffer.byteLength(value, enc)) throw new ValidationError(key, `${enc} string`); @@ -507,8 +591,7 @@ Validator.prototype.buf = function buf(key, fallback, enc) { */ Validator.prototype.array = function array(key, fallback) { - let value = this.get(key); - let result, parts; + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -522,10 +605,10 @@ Validator.prototype.array = function array(key, fallback) { return value; } - parts = value.trim().split(/\s*,\s*/); - result = []; + const parts = value.trim().split(/\s*,\s*/); + const result = []; - for (let part of parts) { + for (const part of parts) { if (part.length === 0) continue; @@ -543,7 +626,7 @@ Validator.prototype.array = function array(key, fallback) { */ Validator.prototype.obj = function obj(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -551,7 +634,7 @@ Validator.prototype.obj = function obj(key, fallback) { if (value === null) return fallback; - if (!value || typeof value !== 'object') + if (typeof value !== 'object') throw new ValidationError(key, 'object'); return value; @@ -565,7 +648,7 @@ Validator.prototype.obj = function obj(key, fallback) { */ Validator.prototype.func = function func(key, fallback) { - let value = this.get(key); + const value = this.get(key); if (fallback === undefined) fallback = null; @@ -584,18 +667,13 @@ Validator.prototype.func = function func(key, fallback) { */ function fmt(key) { + if (Array.isArray(key)) + key = key[0]; + if (typeof key === 'number') return `Param #${key}`; - return key; -} -function inherits(child, parent) { - child.super_ = parent; - Object.setPrototypeOf(child.prototype, parent.prototype); - Object.defineProperty(child.prototype, 'constructor', { - value: child, - enumerable: false - }); + return key; } function ValidationError(key, type) { @@ -611,14 +689,10 @@ function ValidationError(key, type) { Error.captureStackTrace(this, ValidationError); } -inherits(ValidationError, Error); +Object.setPrototypeOf(ValidationError.prototype, Error.prototype); /* * Expose */ -exports = Validator; -exports.Validator = Validator; -exports.Error = ValidationError; - -module.exports = exports; +module.exports = Validator; diff --git a/lib/utils/writer.js b/lib/utils/writer.js index 6bb7cf1a8..96da456eb 100644 --- a/lib/utils/writer.js +++ b/lib/utils/writer.js @@ -23,23 +23,29 @@ const UI32 = 4; const UI32BE = 5; const UI64 = 6; const UI64BE = 7; -const I8 = 8; -const I16 = 9; -const I16BE = 10; -const I32 = 11; -const I32BE = 12; -const I64 = 13; -const I64BE = 14; -const FL = 15; -const FLBE = 16; -const DBL = 17; -const DBLBE = 18; -const VARINT = 19; -const VARINT2 = 20; -const BYTES = 21; -const STR = 22; -const CHECKSUM = 23; -const FILL = 24; +const UI64N = 8; +const UI64BEN = 9; +const I8 = 10; +const I16 = 11; +const I16BE = 12; +const I32 = 13; +const I32BE = 14; +const I64 = 15; +const I64BE = 16; +const I64N = 17; +const I64BEN = 18; +const FL = 19; +const FLBE = 20; +const DBL = 21; +const DBLBE = 22; +const VARINT = 23; +const VARINTN = 24; +const VARINT2 = 25; +const VARINT2N = 26; +const BYTES = 27; +const STR = 28; +const CHECKSUM = 29; +const FILL = 30; /** * An object that allows writing of buffers in a @@ -60,7 +66,7 @@ function BufferWriter() { return new BufferWriter(); this.ops = []; - this.written = 0; + this.offset = 0; } /** @@ -70,34 +76,98 @@ function BufferWriter() { */ BufferWriter.prototype.render = function render(keep) { - let data = Buffer.allocUnsafe(this.written); + const data = Buffer.allocUnsafe(this.offset); let off = 0; - for (let op of this.ops) { + for (const op of this.ops) { switch (op.type) { - case SEEK: off += op.value; break; - case UI8: off = data.writeUInt8(op.value, off, true); break; - case UI16: off = data.writeUInt16LE(op.value, off, true); break; - case UI16BE: off = data.writeUInt16BE(op.value, off, true); break; - case UI32: off = data.writeUInt32LE(op.value, off, true); break; - case UI32BE: off = data.writeUInt32BE(op.value, off, true); break; - case UI64: off = encoding.writeU64(data, op.value, off); break; - case UI64BE: off = encoding.writeU64BE(data, op.value, off); break; - case I8: off = data.writeInt8(op.value, off, true); break; - case I16: off = data.writeInt16LE(op.value, off, true); break; - case I16BE: off = data.writeInt16BE(op.value, off, true); break; - case I32: off = data.writeInt32LE(op.value, off, true); break; - case I32BE: off = data.writeInt32BE(op.value, off, true); break; - case I64: off = encoding.write64(data, op.value, off); break; - case I64BE: off = encoding.write64BE(data, op.value, off); break; - case FL: off = data.writeFloatLE(op.value, off, true); break; - case FLBE: off = data.writeFloatBE(op.value, off, true); break; - case DBL: off = data.writeDoubleLE(op.value, off, true); break; - case DBLBE: off = data.writeDoubleBE(op.value, off, true); break; - case VARINT: off = encoding.writeVarint(data, op.value, off); break; - case VARINT2: off = encoding.writeVarint2(data, op.value, off); break; - case BYTES: off += op.value.copy(data, off); break; - case STR: off += data.write(op.value, off, op.enc); break; + case SEEK: + off += op.value; + break; + case UI8: + off = data.writeUInt8(op.value, off, true); + break; + case UI16: + off = data.writeUInt16LE(op.value, off, true); + break; + case UI16BE: + off = data.writeUInt16BE(op.value, off, true); + break; + case UI32: + off = data.writeUInt32LE(op.value, off, true); + break; + case UI32BE: + off = data.writeUInt32BE(op.value, off, true); + break; + case UI64: + off = encoding.writeU64(data, op.value, off); + break; + case UI64BE: + off = encoding.writeU64BE(data, op.value, off); + break; + case UI64N: + off = encoding.writeU64N(data, op.value, off); + break; + case UI64BEN: + off = encoding.writeU64BEN(data, op.value, off); + break; + case I8: + off = data.writeInt8(op.value, off, true); + break; + case I16: + off = data.writeInt16LE(op.value, off, true); + break; + case I16BE: + off = data.writeInt16BE(op.value, off, true); + break; + case I32: + off = data.writeInt32LE(op.value, off, true); + break; + case I32BE: + off = data.writeInt32BE(op.value, off, true); + break; + case I64: + off = encoding.writeI64(data, op.value, off); + break; + case I64BE: + off = encoding.writeI64BE(data, op.value, off); + break; + case I64N: + off = encoding.writeI64N(data, op.value, off); + break; + case I64BEN: + off = encoding.writeI64BEN(data, op.value, off); + break; + case FL: + off = data.writeFloatLE(op.value, off, true); + break; + case FLBE: + off = data.writeFloatBE(op.value, off, true); + break; + case DBL: + off = data.writeDoubleLE(op.value, off, true); + break; + case DBLBE: + off = data.writeDoubleBE(op.value, off, true); + break; + case VARINT: + off = encoding.writeVarint(data, op.value, off); + break; + case VARINTN: + off = encoding.writeVarintN(data, op.value, off); + break; + case VARINT2: + off = encoding.writeVarint2(data, op.value, off); + break; + case VARINT2N: + off = encoding.writeVarint2N(data, op.value, off); + break; + case BYTES: + off += op.value.copy(data, off); + break; + case STR: + off += data.write(op.value, off, op.enc); + break; case CHECKSUM: off += digest.hash256(data.slice(0, off)).copy(data, off, 0, 4); break; @@ -125,7 +195,7 @@ BufferWriter.prototype.render = function render(keep) { */ BufferWriter.prototype.getSize = function getSize() { - return this.written; + return this.offset; }; /** @@ -134,7 +204,7 @@ BufferWriter.prototype.getSize = function getSize() { */ BufferWriter.prototype.seek = function seek(offset) { - this.written += offset; + this.offset += offset; this.ops.push(new WriteOp(SEEK, offset)); }; @@ -144,8 +214,7 @@ BufferWriter.prototype.seek = function seek(offset) { BufferWriter.prototype.destroy = function destroy() { this.ops.length = 0; - this.ops = null; - this.written = null; + this.offset = 0; }; /** @@ -154,7 +223,7 @@ BufferWriter.prototype.destroy = function destroy() { */ BufferWriter.prototype.writeU8 = function writeU8(value) { - this.written += 1; + this.offset += 1; this.ops.push(new WriteOp(UI8, value)); }; @@ -164,7 +233,7 @@ BufferWriter.prototype.writeU8 = function writeU8(value) { */ BufferWriter.prototype.writeU16 = function writeU16(value) { - this.written += 2; + this.offset += 2; this.ops.push(new WriteOp(UI16, value)); }; @@ -174,7 +243,7 @@ BufferWriter.prototype.writeU16 = function writeU16(value) { */ BufferWriter.prototype.writeU16BE = function writeU16BE(value) { - this.written += 2; + this.offset += 2; this.ops.push(new WriteOp(UI16BE, value)); }; @@ -184,7 +253,7 @@ BufferWriter.prototype.writeU16BE = function writeU16BE(value) { */ BufferWriter.prototype.writeU32 = function writeU32(value) { - this.written += 4; + this.offset += 4; this.ops.push(new WriteOp(UI32, value)); }; @@ -194,7 +263,7 @@ BufferWriter.prototype.writeU32 = function writeU32(value) { */ BufferWriter.prototype.writeU32BE = function writeU32BE(value) { - this.written += 4; + this.offset += 4; this.ops.push(new WriteOp(UI32BE, value)); }; @@ -204,7 +273,7 @@ BufferWriter.prototype.writeU32BE = function writeU32BE(value) { */ BufferWriter.prototype.writeU64 = function writeU64(value) { - this.written += 8; + this.offset += 8; this.ops.push(new WriteOp(UI64, value)); }; @@ -214,26 +283,28 @@ BufferWriter.prototype.writeU64 = function writeU64(value) { */ BufferWriter.prototype.writeU64BE = function writeU64BE(value) { - this.written += 8; + this.offset += 8; this.ops.push(new WriteOp(UI64BE, value)); }; /** * Write uint64le. - * @param {BN} value + * @param {U64} value */ -BufferWriter.prototype.writeU64BN = function writeU64BN(value) { - assert(false, 'Not implemented.'); +BufferWriter.prototype.writeU64N = function writeU64N(value) { + this.offset += 8; + this.ops.push(new WriteOp(UI64N, value)); }; /** * Write uint64be. - * @param {BN} value + * @param {U64} value */ -BufferWriter.prototype.writeU64BEBN = function writeU64BEBN(value) { - assert(false, 'Not implemented.'); +BufferWriter.prototype.writeU64BEN = function writeU64BEN(value) { + this.offset += 8; + this.ops.push(new WriteOp(UI64BEN, value)); }; /** @@ -241,8 +312,8 @@ BufferWriter.prototype.writeU64BEBN = function writeU64BEBN(value) { * @param {Number} value */ -BufferWriter.prototype.write8 = function write8(value) { - this.written += 1; +BufferWriter.prototype.writeI8 = function writeI8(value) { + this.offset += 1; this.ops.push(new WriteOp(I8, value)); }; @@ -251,8 +322,8 @@ BufferWriter.prototype.write8 = function write8(value) { * @param {Number} value */ -BufferWriter.prototype.write16 = function write16(value) { - this.written += 2; +BufferWriter.prototype.writeI16 = function writeI16(value) { + this.offset += 2; this.ops.push(new WriteOp(I16, value)); }; @@ -261,8 +332,8 @@ BufferWriter.prototype.write16 = function write16(value) { * @param {Number} value */ -BufferWriter.prototype.write16BE = function write16BE(value) { - this.written += 2; +BufferWriter.prototype.writeI16BE = function writeI16BE(value) { + this.offset += 2; this.ops.push(new WriteOp(I16BE, value)); }; @@ -271,8 +342,8 @@ BufferWriter.prototype.write16BE = function write16BE(value) { * @param {Number} value */ -BufferWriter.prototype.write32 = function write32(value) { - this.written += 4; +BufferWriter.prototype.writeI32 = function writeI32(value) { + this.offset += 4; this.ops.push(new WriteOp(I32, value)); }; @@ -281,8 +352,8 @@ BufferWriter.prototype.write32 = function write32(value) { * @param {Number} value */ -BufferWriter.prototype.write32BE = function write32BE(value) { - this.written += 4; +BufferWriter.prototype.writeI32BE = function writeI32BE(value) { + this.offset += 4; this.ops.push(new WriteOp(I32BE, value)); }; @@ -291,8 +362,8 @@ BufferWriter.prototype.write32BE = function write32BE(value) { * @param {Number} value */ -BufferWriter.prototype.write64 = function write64(value) { - this.written += 8; +BufferWriter.prototype.writeI64 = function writeI64(value) { + this.offset += 8; this.ops.push(new WriteOp(I64, value)); }; @@ -301,27 +372,29 @@ BufferWriter.prototype.write64 = function write64(value) { * @param {Number} value */ -BufferWriter.prototype.write64BE = function write64BE(value) { - this.written += 8; +BufferWriter.prototype.writeI64BE = function writeI64BE(value) { + this.offset += 8; this.ops.push(new WriteOp(I64BE, value)); }; /** * Write int64le. - * @param {BN} value + * @param {I64} value */ -BufferWriter.prototype.write64BN = function write64BN(value) { - assert(false, 'Not implemented.'); +BufferWriter.prototype.writeI64N = function writeI64N(value) { + this.offset += 8; + this.ops.push(new WriteOp(I64N, value)); }; /** * Write int64be. - * @param {BN} value + * @param {I64} value */ -BufferWriter.prototype.write64BEBN = function write64BEBN(value) { - assert(false, 'Not implemented.'); +BufferWriter.prototype.writeI64BEN = function writeI64BEN(value) { + this.offset += 8; + this.ops.push(new WriteOp(I64BEN, value)); }; /** @@ -330,7 +403,7 @@ BufferWriter.prototype.write64BEBN = function write64BEBN(value) { */ BufferWriter.prototype.writeFloat = function writeFloat(value) { - this.written += 4; + this.offset += 4; this.ops.push(new WriteOp(FL, value)); }; @@ -340,7 +413,7 @@ BufferWriter.prototype.writeFloat = function writeFloat(value) { */ BufferWriter.prototype.writeFloatBE = function writeFloatBE(value) { - this.written += 4; + this.offset += 4; this.ops.push(new WriteOp(FLBE, value)); }; @@ -350,7 +423,7 @@ BufferWriter.prototype.writeFloatBE = function writeFloatBE(value) { */ BufferWriter.prototype.writeDouble = function writeDouble(value) { - this.written += 8; + this.offset += 8; this.ops.push(new WriteOp(DBL, value)); }; @@ -360,7 +433,7 @@ BufferWriter.prototype.writeDouble = function writeDouble(value) { */ BufferWriter.prototype.writeDoubleBE = function writeDoubleBE(value) { - this.written += 8; + this.offset += 8; this.ops.push(new WriteOp(DBLBE, value)); }; @@ -370,17 +443,18 @@ BufferWriter.prototype.writeDoubleBE = function writeDoubleBE(value) { */ BufferWriter.prototype.writeVarint = function writeVarint(value) { - this.written += encoding.sizeVarint(value); + this.offset += encoding.sizeVarint(value); this.ops.push(new WriteOp(VARINT, value)); }; /** * Write a varint. - * @param {BN} value + * @param {U64} value */ -BufferWriter.prototype.writeVarintBN = function writeVarintBN(value) { - assert(false, 'Not implemented.'); +BufferWriter.prototype.writeVarintN = function writeVarintN(value) { + this.offset += encoding.sizeVarintN(value); + this.ops.push(new WriteOp(VARINTN, value)); }; /** @@ -389,17 +463,18 @@ BufferWriter.prototype.writeVarintBN = function writeVarintBN(value) { */ BufferWriter.prototype.writeVarint2 = function writeVarint2(value) { - this.written += encoding.sizeVarint2(value); + this.offset += encoding.sizeVarint2(value); this.ops.push(new WriteOp(VARINT2, value)); }; /** * Write a varint (type 2). - * @param {BN} value + * @param {U64} value */ -BufferWriter.prototype.writeVarint2BN = function writeVarint2BN(value) { - assert(false, 'Not implemented.'); +BufferWriter.prototype.writeVarint2N = function writeVarint2N(value) { + this.offset += encoding.sizeVarint2N(value); + this.ops.push(new WriteOp(VARINT2N, value)); }; /** @@ -411,7 +486,7 @@ BufferWriter.prototype.writeBytes = function writeBytes(value) { if (value.length === 0) return; - this.written += value.length; + this.offset += value.length; this.ops.push(new WriteOp(BYTES, value)); }; @@ -421,13 +496,13 @@ BufferWriter.prototype.writeBytes = function writeBytes(value) { */ BufferWriter.prototype.writeVarBytes = function writeVarBytes(value) { - this.written += encoding.sizeVarint(value.length); + this.offset += encoding.sizeVarint(value.length); this.ops.push(new WriteOp(VARINT, value.length)); if (value.length === 0) return; - this.written += value.length; + this.offset += value.length; this.ops.push(new WriteOp(BYTES, value)); }; @@ -454,7 +529,7 @@ BufferWriter.prototype.writeString = function writeString(value, enc) { if (value.length === 0) return; - this.written += Buffer.byteLength(value, enc); + this.offset += Buffer.byteLength(value, enc); this.ops.push(new WriteOp(STR, value, enc)); }; @@ -466,7 +541,8 @@ BufferWriter.prototype.writeString = function writeString(value, enc) { BufferWriter.prototype.writeHash = function writeHash(value) { if (typeof value !== 'string') { assert(value.length === 32); - return this.writeBytes(value); + this.writeBytes(value); + return; } assert(value.length === 64); this.writeString(value, 'hex'); @@ -479,17 +555,15 @@ BufferWriter.prototype.writeHash = function writeHash(value) { */ BufferWriter.prototype.writeVarString = function writeVarString(value, enc) { - let size; - if (value.length === 0) { this.ops.push(new WriteOp(VARINT, 0)); return; } - size = Buffer.byteLength(value, enc); + const size = Buffer.byteLength(value, enc); - this.written += encoding.sizeVarint(size); - this.written += size; + this.offset += encoding.sizeVarint(size); + this.offset += size; this.ops.push(new WriteOp(VARINT, size)); @@ -512,7 +586,7 @@ BufferWriter.prototype.writeNullString = function writeNullString(value, enc) { */ BufferWriter.prototype.writeChecksum = function writeChecksum() { - this.written += 4; + this.offset += 4; this.ops.push(new WriteOp(CHECKSUM)); }; @@ -528,7 +602,7 @@ BufferWriter.prototype.fill = function fill(value, size) { if (size === 0) return; - this.written += size; + this.offset += size; this.ops.push(new WriteOp(FILL, value, null, size)); }; diff --git a/lib/wallet/account.js b/lib/wallet/account.js index 013aad348..024d14f93 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -105,10 +105,10 @@ Account.typesByVal = { Account.prototype.fromOptions = function fromOptions(options) { assert(options, 'Options are required.'); - assert(util.isNumber(options.wid)); + assert(util.isU32(options.wid)); assert(common.isName(options.id), 'Bad Wallet ID.'); assert(HD.isHD(options.accountKey), 'Account key is required.'); - assert(util.isNumber(options.accountIndex), 'Account index is required.'); + assert(util.isU32(options.accountIndex), 'Account index is required.'); this.wid = options.wid; this.id = options.id; @@ -145,37 +145,37 @@ Account.prototype.fromOptions = function fromOptions(options) { } if (options.m != null) { - assert(util.isNumber(options.m)); + assert(util.isU8(options.m)); this.m = options.m; } if (options.n != null) { - assert(util.isNumber(options.n)); + assert(util.isU8(options.n)); this.n = options.n; } if (options.accountIndex != null) { - assert(util.isNumber(options.accountIndex)); + assert(util.isU32(options.accountIndex)); this.accountIndex = options.accountIndex; } if (options.receiveDepth != null) { - assert(util.isNumber(options.receiveDepth)); + assert(util.isU32(options.receiveDepth)); this.receiveDepth = options.receiveDepth; } if (options.changeDepth != null) { - assert(util.isNumber(options.changeDepth)); + assert(util.isU32(options.changeDepth)); this.changeDepth = options.changeDepth; } if (options.nestedDepth != null) { - assert(util.isNumber(options.nestedDepth)); + assert(util.isU32(options.nestedDepth)); this.nestedDepth = options.nestedDepth; } if (options.lookahead != null) { - assert(util.isNumber(options.lookahead)); + assert(util.isU32(options.lookahead)); assert(options.lookahead >= 0); assert(options.lookahead <= Account.MAX_LOOKAHEAD); this.lookahead = options.lookahead; @@ -187,14 +187,14 @@ Account.prototype.fromOptions = function fromOptions(options) { this.type = Account.types.MULTISIG; if (!this.name) - this.name = this.accountIndex + ''; + this.name = this.accountIndex.toString(10); if (this.m < 1 || this.m > this.n) throw new Error('m ranges between 1 and n'); if (options.keys) { assert(Array.isArray(options.keys)); - for (let key of options.keys) + for (const key of options.keys) this.pushKey(key); } @@ -274,8 +274,6 @@ Account.prototype.open = function open() { */ Account.prototype.pushKey = function pushKey(key) { - let index; - if (typeof key === 'string') key = HD.PublicKey.fromBase58(key, this.network); @@ -285,16 +283,16 @@ Account.prototype.pushKey = function pushKey(key) { if (!HD.isPublic(key)) throw new Error('Must add HD keys to wallet.'); - if (!key.isBIP44()) + if (!key.isAccount()) throw new Error('Must add HD account keys to BIP44 wallet.'); if (this.type !== Account.types.MULTISIG) throw new Error('Cannot add keys to non-multisig wallet.'); - if (key.equal(this.accountKey)) + if (key.equals(this.accountKey)) throw new Error('Cannot add own key.'); - index = util.binaryInsert(this.keys, key, cmp, true); + const index = util.binaryInsert(this.keys, key, cmp, true); if (index === -1) return false; @@ -325,7 +323,7 @@ Account.prototype.spliceKey = function spliceKey(key) { if (!HD.isPublic(key)) throw new Error('Must add HD keys to wallet.'); - if (!key.isBIP44()) + if (!key.isAccount()) throw new Error('Must add HD account keys to BIP44 wallet.'); if (this.type !== Account.types.MULTISIG) @@ -345,10 +343,9 @@ Account.prototype.spliceKey = function spliceKey(key) { */ Account.prototype.addSharedKey = async function addSharedKey(key) { - let result = this.pushKey(key); - let exists = await this._hasDuplicate(); + const result = this.pushKey(key); - if (exists) { + if (await this.hasDuplicate()) { this.spliceKey(key); throw new Error('Cannot add a key from another account.'); } @@ -365,14 +362,12 @@ Account.prototype.addSharedKey = async function addSharedKey(key) { * @returns {Promise} */ -Account.prototype._hasDuplicate = function _hasDuplicate() { - let ring, hash; - +Account.prototype.hasDuplicate = function hasDuplicate() { if (this.keys.length !== this.n - 1) return false; - ring = this.deriveReceive(0); - hash = ring.getScriptHash('hex'); + const ring = this.deriveReceive(0); + const hash = ring.getScriptHash('hex'); return this.wallet.hasAddress(hash); }; @@ -385,7 +380,7 @@ Account.prototype._hasDuplicate = function _hasDuplicate() { */ Account.prototype.removeSharedKey = function removeSharedKey(key) { - let result = this.spliceKey(key); + const result = this.spliceKey(key); if (!result) return false; @@ -503,28 +498,29 @@ Account.prototype.deriveNested = function deriveNested(index, master) { */ Account.prototype.derivePath = function derivePath(path, master) { - let data = path.data; - let ring; - switch (path.keyType) { - case Path.types.HD: + case Path.types.HD: { return this.deriveKey(path.branch, path.index, master); - case Path.types.KEY: + } + case Path.types.KEY: { assert(this.type === Account.types.PUBKEYHASH); + let data = path.data; + if (path.encrypted) { data = master.decipher(data, path.hash); if (!data) - return; + return null; } - ring = WalletKey.fromImport(this, data); - - return ring; - case Path.types.ADDRESS: - return; - default: - assert(false, 'Bad key type.'); + return WalletKey.fromImport(this, data); + } + case Path.types.ADDRESS: { + return null; + } + default: { + throw new Error('Bad key type.'); + } } }; @@ -536,19 +532,19 @@ Account.prototype.derivePath = function derivePath(path, master) { */ Account.prototype.deriveKey = function deriveKey(branch, index, master) { - let keys = []; - let key, shared, ring; - assert(typeof branch === 'number'); + const keys = []; + + let key; if (master && master.key && !this.watchOnly) { - key = master.key.deriveBIP44(this.accountIndex); + key = master.key.deriveAccount(44, this.accountIndex); key = key.derive(branch).derive(index); } else { key = this.accountKey.derive(branch).derive(index); } - ring = WalletKey.fromHD(this, key, branch, index); + const ring = WalletKey.fromHD(this, key, branch, index); switch (this.type) { case Account.types.PUBKEYHASH: @@ -556,9 +552,9 @@ Account.prototype.deriveKey = function deriveKey(branch, index, master) { case Account.types.MULTISIG: keys.push(key.publicKey); - for (shared of this.keys) { - shared = shared.derive(branch).derive(index); - keys.push(shared.publicKey); + for (const shared of this.keys) { + const key = shared.derive(branch).derive(index); + keys.push(key.publicKey); } ring.script = Script.fromMultisig(this.m, this.n, keys); @@ -613,7 +609,7 @@ Account.prototype.initDepth = async function initDepth() { // Lookahead for (let i = 0; i < this.lookahead; i++) { - let key = this.deriveReceive(i + 1); + const key = this.deriveReceive(i + 1); await this.saveKey(key); } @@ -625,7 +621,7 @@ Account.prototype.initDepth = async function initDepth() { // Lookahead for (let i = 0; i < this.lookahead; i++) { - let key = this.deriveChange(i + 1); + const key = this.deriveChange(i + 1); await this.saveKey(key); } @@ -638,7 +634,7 @@ Account.prototype.initDepth = async function initDepth() { // Lookahead for (let i = 0; i < this.lookahead; i++) { - let key = this.deriveNested(i + 1); + const key = this.deriveNested(i + 1); await this.saveKey(key); } } @@ -659,12 +655,12 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested) let result = null; if (receive > this.receiveDepth) { - let depth = this.receiveDepth + this.lookahead; + const depth = this.receiveDepth + this.lookahead; assert(receive <= depth + 1); for (let i = depth; i < receive + this.lookahead; i++) { - let key = this.deriveReceive(i); + const key = this.deriveReceive(i); await this.saveKey(key); } @@ -676,12 +672,12 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested) } if (change > this.changeDepth) { - let depth = this.changeDepth + this.lookahead; + const depth = this.changeDepth + this.lookahead; assert(change <= depth + 1); for (let i = depth; i < change + this.lookahead; i++) { - let key = this.deriveChange(i); + const key = this.deriveChange(i); await this.saveKey(key); } @@ -692,12 +688,12 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested) } if (this.witness && nested > this.nestedDepth) { - let depth = this.nestedDepth + this.lookahead; + const depth = this.nestedDepth + this.lookahead; assert(nested <= depth + 1); for (let i = depth; i < nested + this.lookahead; i++) { - let key = this.deriveNested(i); + const key = this.deriveNested(i); await this.saveKey(key); } @@ -721,8 +717,6 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested) */ Account.prototype.setLookahead = async function setLookahead(lookahead) { - let depth, target; - if (lookahead === this.lookahead) { this.db.logger.warning( 'Lookahead is not changing for: %s/%s.', @@ -731,7 +725,7 @@ Account.prototype.setLookahead = async function setLookahead(lookahead) { } if (lookahead < this.lookahead) { - let diff = this.lookahead - lookahead; + const diff = this.lookahead - lookahead; this.receiveDepth += diff; this.receive = this.deriveReceive(this.receiveDepth - 1); @@ -751,28 +745,32 @@ Account.prototype.setLookahead = async function setLookahead(lookahead) { return; } - depth = this.receiveDepth + this.lookahead; - target = this.receiveDepth + lookahead; + { + const depth = this.receiveDepth + this.lookahead; + const target = this.receiveDepth + lookahead; - for (let i = depth; i < target; i++) { - let key = this.deriveReceive(i); - await this.saveKey(key); + for (let i = depth; i < target; i++) { + const key = this.deriveReceive(i); + await this.saveKey(key); + } } - depth = this.changeDepth + this.lookahead; - target = this.changeDepth + lookahead; + { + const depth = this.changeDepth + this.lookahead; + const target = this.changeDepth + lookahead; - for (let i = depth; i < target; i++) { - let key = this.deriveChange(i); - await this.saveKey(key); + for (let i = depth; i < target; i++) { + const key = this.deriveChange(i); + await this.saveKey(key); + } } if (this.witness) { - let depth = this.nestedDepth + this.lookahead; - let target = this.nestedDepth + lookahead; + const depth = this.nestedDepth + this.lookahead; + const target = this.nestedDepth + lookahead; for (let i = depth; i < target; i++) { - let key = this.deriveNested(i); + const key = this.deriveNested(i); await this.saveKey(key); } } @@ -799,7 +797,7 @@ Account.prototype.getAddress = function getAddress(enc) { Account.prototype.getReceive = function getReceive(enc) { if (!this.receive) - return; + return null; return this.receive.getAddress(enc); }; @@ -811,7 +809,8 @@ Account.prototype.getReceive = function getReceive(enc) { Account.prototype.getChange = function getChange(enc) { if (!this.change) - return; + return null; + return this.change.getAddress(enc); }; @@ -823,7 +822,8 @@ Account.prototype.getChange = function getChange(enc) { Account.prototype.getNested = function getNested(enc) { if (!this.nested) - return; + return null; + return this.nested.getAddress(enc); }; @@ -918,8 +918,8 @@ Account.prototype.getSize = function getSize() { */ Account.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeVarString(this.name, 'ascii'); bw.writeU8(this.initialized ? 1 : 0); @@ -935,7 +935,7 @@ Account.prototype.toRaw = function toRaw() { bw.writeBytes(this.accountKey.toRaw()); bw.writeU8(this.keys.length); - for (let key of this.keys) + for (const key of this.keys) bw.writeBytes(key.toRaw()); return bw.render(); @@ -949,8 +949,7 @@ Account.prototype.toRaw = function toRaw() { */ Account.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let count; + const br = new BufferReader(data); this.name = br.readVarString('ascii'); this.initialized = br.readU8() === 1; @@ -967,10 +966,10 @@ Account.prototype.fromRaw = function fromRaw(data) { assert(Account.typesByVal[this.type]); - count = br.readU8(); + const count = br.readU8(); for (let i = 0; i < count; i++) { - let key = HD.PublicKey.fromRaw(br.readBytes(82)); + const key = HD.PublicKey.fromRaw(br.readBytes(82)); this.pushKey(key); } @@ -1004,8 +1003,8 @@ Account.isAccount = function isAccount(obj) { * Helpers */ -function cmp(key1, key2) { - return key1.compare(key2); +function cmp(a, b) { + return a.compare(b); } /* diff --git a/lib/wallet/client.js b/lib/wallet/client.js index f3f0ef543..e5281f923 100644 --- a/lib/wallet/client.js +++ b/lib/wallet/client.js @@ -44,7 +44,7 @@ function WalletClient(options) { this.socket = null; } -util.inherits(WalletClient, AsyncObject); +Object.setPrototypeOf(WalletClient.prototype, AsyncObject.prototype); /** * Open the client, wait for socket to connect. @@ -100,7 +100,8 @@ WalletClient.prototype._open = async function _open() { block = parseBlock(entry, txs); } catch (e) { this.emit('error', e); - return cb(); + cb(); + return; } this.fire('block rescan', block.entry, block.txs).then(cb, cb); @@ -141,7 +142,7 @@ WalletClient.prototype._open = async function _open() { * @returns {Promise} */ -WalletClient.prototype._close = function close() { +WalletClient.prototype._close = function _close() { if (!this.socket) return Promise.resolve(); @@ -309,27 +310,26 @@ WalletClient.prototype.rescan = function rescan(start) { */ function parseEntry(data, enc) { - let br, block, hash, height; - if (typeof data === 'string') data = Buffer.from(data, 'hex'); - block = Headers.fromAbbr(data); + const block = Headers.fromHead(data); - br = new BufferReader(data); + const br = new BufferReader(data); br.seek(80); - height = br.readU32(); - hash = block.hash('hex'); - return new BlockMeta(hash, height, block.ts); + const height = br.readU32(); + const hash = block.hash('hex'); + + return new BlockMeta(hash, height, block.time); } function parseBlock(entry, txs) { - let block = parseEntry(entry); - let out = []; + const block = parseEntry(entry); + const out = []; - for (let tx of txs) { - tx = parseTX(tx); + for (const raw of txs) { + const tx = parseTX(raw); out.push(tx); } diff --git a/lib/wallet/common.js b/lib/wallet/common.js index 71ee62dba..5f45ed659 100644 --- a/lib/wallet/common.js +++ b/lib/wallet/common.js @@ -56,7 +56,7 @@ common.isName = function isName(key) { common.sortTX = function sortTX(txs) { return txs.sort((a, b) => { - return a.ps - b.ps; + return a.mtime - b.mtime; }); }; @@ -81,36 +81,36 @@ common.sortCoins = function sortCoins(coins) { */ common.sortDeps = function sortDeps(txs) { - let depMap = {}; - let count = {}; - let result = []; - let top = []; - let map = {}; - - for (let tx of txs) { - let hash = tx.hash('hex'); - map[hash] = tx; + const map = new Map(); + + for (const tx of txs) { + const hash = tx.hash('hex'); + map.set(hash, tx); } - for (let tx of txs) { - let hash = tx.hash('hex'); - let hasDeps = false; + const depMap = new Map(); + const depCount = new Map(); + const top = []; + + for (const [hash, tx] of map) { + depCount.set(hash, 0); - count[hash] = 0; + let hasDeps = false; - for (let input of tx.inputs) { - let prev = input.prevout.hash; + for (const input of tx.inputs) { + const prev = input.prevout.hash; - if (!map[prev]) + if (!map.has(prev)) continue; - count[hash] += 1; + const count = depCount.get(hash); + depCount.set(hash, count + 1); hasDeps = true; - if (!depMap[prev]) - depMap[prev] = []; + if (!depMap.has(prev)) + depMap.set(prev, []); - depMap[prev].push(tx); + depMap.get(prev).push(tx); } if (hasDeps) @@ -119,20 +119,25 @@ common.sortDeps = function sortDeps(txs) { top.push(tx); } - for (let tx of top) { - let hash = tx.hash('hex'); - let deps = depMap[hash]; + const result = []; + + for (const tx of top) { + const hash = tx.hash('hex'); + const deps = depMap.get(hash); result.push(tx); if (!deps) continue; - for (let tx of deps) { - let hash = tx.hash('hex'); + for (const tx of deps) { + const hash = tx.hash('hex'); + let count = depCount.get(hash); - if (--count[hash] === 0) + if (--count === 0) top.push(tx); + + depCount.set(hash, count); } } diff --git a/lib/wallet/http.js b/lib/wallet/http.js index 271bd2098..1fc55bd2e 100644 --- a/lib/wallet/http.js +++ b/lib/wallet/http.js @@ -20,6 +20,8 @@ const random = require('../crypto/random'); const ccmp = require('../crypto/ccmp'); const Network = require('../protocol/network'); const Validator = require('../utils/validator'); +const Address = require('../primitives/address'); +const KeyRing = require('../primitives/keyring'); const common = require('./common'); /** @@ -50,7 +52,7 @@ function HTTPServer(options) { this.init(); } -util.inherits(HTTPServer, HTTPBase); +Object.setPrototypeOf(HTTPServer.prototype, HTTPBase.prototype); /** * Attach to server. @@ -107,8 +109,7 @@ HTTPServer.prototype.initRouter = function initRouter() { this.use(this.jsonRPC(this.rpc)); this.hook(async (req, res) => { - let valid = req.valid(); - let id, token, wallet; + const valid = req.valid(); if (req.path.length === 0) return; @@ -119,11 +120,11 @@ HTTPServer.prototype.initRouter = function initRouter() { if (req.method === 'PUT' && req.path.length === 1) return; - id = valid.str('id'); - token = valid.buf('token'); + const id = valid.str('id'); + const token = valid.buf('token'); if (!this.options.walletAuth) { - wallet = await this.walletdb.get(id); + const wallet = await this.walletdb.get(id); if (!wallet) { res.send(404); @@ -135,6 +136,7 @@ HTTPServer.prototype.initRouter = function initRouter() { return; } + let wallet; try { wallet = await this.walletdb.auth(id, token); } catch (err) { @@ -155,8 +157,8 @@ HTTPServer.prototype.initRouter = function initRouter() { // Rescan this.post('/_admin/rescan', async (req, res) => { - let valid = req.valid(); - let height = valid.u32('height'); + const valid = req.valid(); + const height = valid.u32('height'); res.send(200, { success: true }); @@ -171,8 +173,8 @@ HTTPServer.prototype.initRouter = function initRouter() { // Backup WalletDB this.post('/_admin/backup', async (req, res) => { - let valid = req.valid(); - let path = valid.str('path'); + const valid = req.valid(); + const path = valid.str('path'); enforce(path, 'Path is required.'); @@ -183,7 +185,7 @@ HTTPServer.prototype.initRouter = function initRouter() { // List wallets this.get('/_admin/wallets', async (req, res) => { - let wallets = await this.walletdb.getWallets(); + const wallets = await this.walletdb.getWallets(); res.send(200, wallets); }); @@ -199,10 +201,9 @@ HTTPServer.prototype.initRouter = function initRouter() { // Create wallet (compat) this.post('/', async (req, res) => { - let valid = req.valid(); - let wallet; + const valid = req.valid(); - wallet = await this.walletdb.create({ + const wallet = await this.walletdb.create({ id: valid.str('id'), type: valid.str('type'), m: valid.u32('m'), @@ -220,10 +221,9 @@ HTTPServer.prototype.initRouter = function initRouter() { // Create wallet this.put('/:id', async (req, res) => { - let valid = req.valid(); - let wallet; + const valid = req.valid(); - wallet = await this.walletdb.create({ + const wallet = await this.walletdb.create({ id: valid.str('id'), type: valid.str('type'), m: valid.u32('m'), @@ -241,15 +241,15 @@ HTTPServer.prototype.initRouter = function initRouter() { // List accounts this.get('/:id/account', async (req, res) => { - let accounts = await req.wallet.getAccounts(); + const accounts = await req.wallet.getAccounts(); res.send(200, accounts); }); // Get account this.get('/:id/account/:account', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let account = await req.wallet.getAccount(acct); + const valid = req.valid(); + const acct = valid.str('account'); + const account = await req.wallet.getAccount(acct); if (!account) { res.send(404); @@ -261,11 +261,10 @@ HTTPServer.prototype.initRouter = function initRouter() { // Create account (compat) this.post('/:id/account', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let options, account; + const valid = req.valid(); + const passphrase = valid.str('passphrase'); - options = { + const options = { name: valid.str(['account', 'name']), witness: valid.bool('witness'), watchOnly: valid.bool('watchOnly'), @@ -276,23 +275,17 @@ HTTPServer.prototype.initRouter = function initRouter() { lookahead: valid.u32('lookahead') }; - account = await req.wallet.createAccount(options, passphrase); - - if (!account) { - res.send(404); - return; - } + const account = await req.wallet.createAccount(options, passphrase); res.send(200, account.toJSON()); }); // Create account this.put('/:id/account/:account', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let options, account; + const valid = req.valid(); + const passphrase = valid.str('passphrase'); - options = { + const options = { name: valid.str('account'), witness: valid.bool('witness'), watchOnly: valid.bool('watchOnly'), @@ -303,33 +296,34 @@ HTTPServer.prototype.initRouter = function initRouter() { lookahead: valid.u32('lookahead') }; - account = await req.wallet.createAccount(options, passphrase); - - if (!account) { - res.send(404); - return; - } + const account = await req.wallet.createAccount(options, passphrase); res.send(200, account.toJSON()); }); // Change passphrase this.post('/:id/passphrase', async (req, res) => { - let valid = req.valid(); - let old = valid.str('old'); - let new_ = valid.str('new'); + const valid = req.valid(); + const old = valid.str('old'); + const new_ = valid.str('new'); + enforce(old || new_, 'Passphrase is required.'); + await req.wallet.setPassphrase(old, new_); + res.send(200, { success: true }); }); // Unlock wallet this.post('/:id/unlock', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let timeout = valid.u32('timeout'); + const valid = req.valid(); + const passphrase = valid.str('passphrase'); + const timeout = valid.u32('timeout'); + enforce(passphrase, 'Passphrase is required.'); + await req.wallet.unlock(passphrase, timeout); + res.send(200, { success: true }); }); @@ -341,26 +335,29 @@ HTTPServer.prototype.initRouter = function initRouter() { // Import key this.post('/:id/import', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let pub = valid.str('publicKey'); - let priv = valid.str('privateKey'); - let address = valid.str('address'); + const valid = req.valid(); + const acct = valid.str('account'); + const pub = valid.buf('publicKey'); + const priv = valid.str('privateKey'); + const b58 = valid.str('address'); if (pub) { - await req.wallet.importKey(acct, pub); + const key = KeyRing.fromPublic(pub, this.network); + await req.wallet.importKey(acct, key); res.send(200, { success: true }); return; } if (priv) { - await req.wallet.importKey(acct, priv); + const key = KeyRing.fromSecret(priv, this.network); + await req.wallet.importKey(acct, key); res.send(200, { success: true }); return; } - if (address) { - await req.wallet.importAddress(acct, address); + if (b58) { + const addr = Address.fromString(b58, this.network); + await req.wallet.importAddress(acct, addr); res.send(200, { success: true }); return; } @@ -370,38 +367,40 @@ HTTPServer.prototype.initRouter = function initRouter() { // Generate new token this.post('/:id/retoken', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let token = await req.wallet.retoken(passphrase); - res.send(200, { token: token.toString('hex') }); + const valid = req.valid(); + const passphrase = valid.str('passphrase'); + const token = await req.wallet.retoken(passphrase); + + res.send(200, { + token: token.toString('hex') + }); }); // Send TX this.post('/:id/send', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let outputs = valid.array('outputs'); - let options, tx, details; + const valid = req.valid(); + const passphrase = valid.str('passphrase'); + const outputs = valid.array('outputs'); - options = { + const options = { rate: valid.u64('rate'), blocks: valid.u32('blocks'), maxFee: valid.u64('maxFee'), selection: valid.str('selection'), smart: valid.bool('smart'), subtractFee: valid.bool('subtractFee'), + subtractIndex: valid.i32('subtractIndex'), depth: valid.u32(['confirmations', 'depth']), outputs: [] }; - for (let output of outputs) { - let valid = new Validator([output]); + for (const output of outputs) { + const valid = new Validator([output]); + const raw = valid.buf('script'); let script = null; - if (valid.has('script')) { - script = valid.buf('script'); - script = Script.fromRaw(script); - } + if (raw) + script = Script.fromRaw(raw); options.outputs.push({ script: script, @@ -410,38 +409,37 @@ HTTPServer.prototype.initRouter = function initRouter() { }); } - tx = await req.wallet.send(options, passphrase); + const tx = await req.wallet.send(options, passphrase); - details = await req.wallet.getDetails(tx.hash('hex')); + const details = await req.wallet.getDetails(tx.hash('hex')); res.send(200, details.toJSON()); }); // Create TX this.post('/:id/create', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let outputs = valid.array('outputs'); - let options, tx; + const valid = req.valid(); + const passphrase = valid.str('passphrase'); + const outputs = valid.array('outputs'); - options = { + const options = { rate: valid.u64('rate'), maxFee: valid.u64('maxFee'), selection: valid.str('selection'), smart: valid.bool('smart'), subtractFee: valid.bool('subtractFee'), + subtractIndex: valid.i32('subtractIndex'), depth: valid.u32(['confirmations', 'depth']), outputs: [] }; - for (let output of outputs) { - let valid = new Validator([output]); + for (const output of outputs) { + const valid = new Validator([output]); + const raw = valid.buf('script'); let script = null; - if (valid.has('script')) { - script = valid.buf('script'); - script = Script.fromRaw(script); - } + if (raw) + script = Script.fromRaw(raw); options.outputs.push({ script: script, @@ -450,21 +448,23 @@ HTTPServer.prototype.initRouter = function initRouter() { }); } - tx = await req.wallet.createTX(options); + const tx = await req.wallet.createTX(options); + await req.wallet.sign(tx, passphrase); + res.send(200, tx.getJSON(this.network)); }); // Sign TX this.post('/:id/sign', async (req, res) => { - let valid = req.valid(); - let passphrase = valid.str('passphrase'); - let raw = valid.buf('tx'); - let tx; + const valid = req.valid(); + const passphrase = valid.str('passphrase'); + const raw = valid.buf('tx'); enforce(raw, 'TX is required.'); - tx = MTX.fromRaw(raw); + const tx = MTX.fromRaw(raw); + tx.view = await req.wallet.getCoinView(tx); await req.wallet.sign(tx, passphrase); @@ -473,38 +473,43 @@ HTTPServer.prototype.initRouter = function initRouter() { // Zap Wallet TXs this.post('/:id/zap', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let age = valid.u32('age'); + const valid = req.valid(); + const acct = valid.str('account'); + const age = valid.u32('age'); + enforce(age, 'Age is required.'); + await req.wallet.zap(acct, age); + res.send(200, { success: true }); }); // Abandon Wallet TX this.del('/:id/tx/:hash', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); + const valid = req.valid(); + const hash = valid.hash('hash'); + enforce(hash, 'Hash is required.'); + await req.wallet.abandon(hash); + res.send(200, { success: true }); }); // List blocks this.get('/:id/block', async (req, res) => { - let heights = await req.wallet.getBlocks(); + const heights = await req.wallet.getBlocks(); res.send(200, heights); }); // Get Block Record this.get('/:id/block/:height', async (req, res) => { - let valid = req.valid(); - let height = valid.u32('height'); - let block; + const valid = req.valid(); + const height = valid.u32('height'); enforce(height != null, 'Height is required.'); - block = await req.wallet.getBlock(height); + const block = await req.wallet.getBlock(height); if (!block) { res.send(404); @@ -516,33 +521,38 @@ HTTPServer.prototype.initRouter = function initRouter() { // Add key this.put('/:id/shared-key', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let key = valid.str('accountKey'); + const valid = req.valid(); + const acct = valid.str('account'); + const key = valid.str('accountKey'); + enforce(key, 'Key is required.'); + await req.wallet.addSharedKey(acct, key); + res.send(200, { success: true }); }); // Remove key this.del('/:id/shared-key', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let key = valid.str('accountKey'); + const valid = req.valid(); + const acct = valid.str('account'); + const key = valid.str('accountKey'); + enforce(key, 'Key is required.'); + await req.wallet.removeSharedKey(acct, key); + res.send(200, { success: true }); }); // Get key by address this.get('/:id/key/:address', async (req, res) => { - let valid = req.valid(); - let address = valid.str('address'); - let key; + const valid = req.valid(); + const address = valid.str('address'); enforce(address, 'Address is required.'); - key = await req.wallet.getKey(address); + const key = await req.wallet.getKey(address); if (!key) { res.send(404); @@ -554,14 +564,13 @@ HTTPServer.prototype.initRouter = function initRouter() { // Get private key this.get('/:id/wif/:address', async (req, res) => { - let valid = req.valid(); - let address = valid.str('address'); - let passphrase = valid.str('passphrase'); - let key; + const valid = req.valid(); + const address = valid.str('address'); + const passphrase = valid.str('passphrase'); enforce(address, 'Address is required.'); - key = await req.wallet.getPrivateKey(address, passphrase); + const key = await req.wallet.getPrivateKey(address, passphrase); if (!key) { res.send(404); @@ -573,33 +582,36 @@ HTTPServer.prototype.initRouter = function initRouter() { // Create address this.post('/:id/address', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let address = await req.wallet.createReceive(acct); + const valid = req.valid(); + const acct = valid.str('account'); + const address = await req.wallet.createReceive(acct); + res.send(200, address.toJSON()); }); // Create change address this.post('/:id/change', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let address = await req.wallet.createChange(acct); + const valid = req.valid(); + const acct = valid.str('account'); + const address = await req.wallet.createChange(acct); + res.send(200, address.toJSON()); }); // Create nested address this.post('/:id/nested', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let address = await req.wallet.createNested(acct); + const valid = req.valid(); + const acct = valid.str('account'); + const address = await req.wallet.createNested(acct); + res.send(200, address.toJSON()); }); // Wallet Balance this.get('/:id/balance', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let balance = await req.wallet.getBalance(acct); + const valid = req.valid(); + const acct = valid.str('account'); + const balance = await req.wallet.getBalance(acct); if (!balance) { res.send(404); @@ -611,15 +623,14 @@ HTTPServer.prototype.initRouter = function initRouter() { // Wallet UTXOs this.get('/:id/coin', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let coins = await req.wallet.getCoins(acct); - let result = []; - let coin; + const valid = req.valid(); + const acct = valid.str('account'); + const coins = await req.wallet.getCoins(acct); + const result = []; common.sortCoins(coins); - for (coin of coins) + for (const coin of coins) result.push(coin.getJSON(this.network)); res.send(200, result); @@ -627,11 +638,10 @@ HTTPServer.prototype.initRouter = function initRouter() { // Locked coins this.get('/:id/locked', async (req, res) => { - let locked = this.wallet.getLocked(); - let result = []; - let outpoint; + const locked = this.wallet.getLocked(); + const result = []; - for (outpoint of locked) + for (const outpoint of locked) result.push(outpoint.toJSON()); res.send(200, result); @@ -639,45 +649,42 @@ HTTPServer.prototype.initRouter = function initRouter() { // Lock coin this.put('/:id/locked/:hash/:index', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); - let index = valid.u32('index'); - let outpoint; + const valid = req.valid(); + const hash = valid.hash('hash'); + const index = valid.u32('index'); enforce(hash, 'Hash is required.'); enforce(index != null, 'Index is required.'); - outpoint = new Outpoint(hash, index); + const outpoint = new Outpoint(hash, index); this.wallet.lockCoin(outpoint); }); // Unlock coin this.del('/:id/locked/:hash/:index', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); - let index = valid.u32('index'); - let outpoint; + const valid = req.valid(); + const hash = valid.hash('hash'); + const index = valid.u32('index'); enforce(hash, 'Hash is required.'); enforce(index != null, 'Index is required.'); - outpoint = new Outpoint(hash, index); + const outpoint = new Outpoint(hash, index); this.wallet.unlockCoin(outpoint); }); // Wallet Coin this.get('/:id/coin/:hash/:index', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); - let index = valid.u32('index'); - let coin; + const valid = req.valid(); + const hash = valid.hash('hash'); + const index = valid.u32('index'); enforce(hash, 'Hash is required.'); enforce(index != null, 'Index is required.'); - coin = await req.wallet.getCoin(hash, index); + const coin = await req.wallet.getCoin(hash, index); if (!coin) { res.send(404); @@ -689,17 +696,17 @@ HTTPServer.prototype.initRouter = function initRouter() { // Wallet TXs this.get('/:id/tx/history', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let txs = await req.wallet.getHistory(acct); - let result = []; - let details; + const valid = req.valid(); + const acct = valid.str('account'); + const txs = await req.wallet.getHistory(acct); common.sortTX(txs); - details = await req.wallet.toDetails(txs); + const details = await req.wallet.toDetails(txs); - for (let item of details) + const result = []; + + for (const item of details) result.push(item.toJSON()); res.send(200, result); @@ -707,17 +714,17 @@ HTTPServer.prototype.initRouter = function initRouter() { // Wallet Pending TXs this.get('/:id/tx/unconfirmed', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let txs = await req.wallet.getPending(acct); - let result = []; - let details; + const valid = req.valid(); + const acct = valid.str('account'); + const txs = await req.wallet.getPending(acct); common.sortTX(txs); - details = await req.wallet.toDetails(txs); + const details = await req.wallet.toDetails(txs); + + const result = []; - for (let item of details) + for (const item of details) result.push(item.toJSON()); res.send(200, result); @@ -725,23 +732,23 @@ HTTPServer.prototype.initRouter = function initRouter() { // Wallet TXs within time range this.get('/:id/tx/range', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let result = []; - let options, txs, details; + const valid = req.valid(); + const acct = valid.str('account'); - options = { + const options = { start: valid.u32('start'), end: valid.u32('end'), limit: valid.u32('limit'), reverse: valid.bool('reverse') }; - txs = await req.wallet.getRange(acct, options); + const txs = await req.wallet.getRange(acct, options); - details = await req.wallet.toDetails(txs); + const details = await req.wallet.toDetails(txs); - for (let item of details) + const result = []; + + for (const item of details) result.push(item.toJSON()); res.send(200, result); @@ -749,14 +756,14 @@ HTTPServer.prototype.initRouter = function initRouter() { // Last Wallet TXs this.get('/:id/tx/last', async (req, res) => { - let valid = req.valid(); - let acct = valid.str('account'); - let limit = valid.u32('limit'); - let txs = await req.wallet.getLast(acct, limit); - let details = await req.wallet.toDetails(txs); - let result = []; - - for (let item of details) + const valid = req.valid(); + const acct = valid.str('account'); + const limit = valid.u32('limit'); + const txs = await req.wallet.getLast(acct, limit); + const details = await req.wallet.toDetails(txs); + const result = []; + + for (const item of details) result.push(item.toJSON()); res.send(200, result); @@ -764,20 +771,19 @@ HTTPServer.prototype.initRouter = function initRouter() { // Wallet TX this.get('/:id/tx/:hash', async (req, res) => { - let valid = req.valid(); - let hash = valid.hash('hash'); - let tx, details; + const valid = req.valid(); + const hash = valid.hash('hash'); enforce(hash, 'Hash is required.'); - tx = await req.wallet.getTX(hash); + const tx = await req.wallet.getTX(hash); if (!tx) { res.send(404); return; } - details = await req.wallet.toDetails(tx); + const details = await req.wallet.toDetails(tx); res.send(200, details.toJSON()); }); @@ -803,50 +809,37 @@ HTTPServer.prototype.initSockets = function initSockets() { }); this.walletdb.on('tx', (id, tx, details) => { - let json = details.toJSON(); - let channel = 'w:' + id; - this.to(channel, 'wallet tx', json); - this.to('!all', 'wallet tx', id, json); + const json = details.toJSON(); + this.to(`w:${id}`, 'wallet tx', json); }); this.walletdb.on('confirmed', (id, tx, details) => { - let json = details.toJSON(); - let channel = 'w:' + id; - this.to(channel, 'wallet confirmed', json); - this.to('!all', 'wallet confirmed', id, json); + const json = details.toJSON(); + this.to(`w:${id}`, 'wallet confirmed', json); }); this.walletdb.on('unconfirmed', (id, tx, details) => { - let json = details.toJSON(); - let channel = 'w:' + id; - this.to(channel, 'wallet unconfirmed', json); - this.to('!all', 'wallet unconfirmed', id, json); + const json = details.toJSON(); + this.to(`w:${id}`, 'wallet unconfirmed', json); }); this.walletdb.on('conflict', (id, tx, details) => { - let json = details.toJSON(); - let channel = 'w:' + id; - this.to(channel, 'wallet conflict', json); - this.to('!all', 'wallet conflict', id, json); + const json = details.toJSON(); + this.to(`w:${id}`, 'wallet conflict', json); }); this.walletdb.on('balance', (id, balance) => { - let json = balance.toJSON(); - let channel = 'w:' + id; - this.to(channel, 'wallet balance', json); - this.to('!all', 'wallet balance', id, json); + const json = balance.toJSON(); + this.to(`w:${id}`, 'wallet balance', json); }); this.walletdb.on('address', (id, receive) => { - let channel = 'w:' + id; - let json = []; - let addr; + const json = []; - for (addr of receive) + for (const addr of receive) json.push(addr.toJSON()); - this.to(channel, 'wallet address', json); - this.to('!all', 'wallet address', id, json); + this.to(`w:${id}`, 'wallet address', json); }); }; @@ -858,17 +851,21 @@ HTTPServer.prototype.initSockets = function initSockets() { HTTPServer.prototype.handleSocket = function handleSocket(socket) { socket.hook('wallet auth', (args) => { - let valid = new Validator([args]); - let key = valid.str(0); - let hash; - if (socket.auth) throw new Error('Already authed.'); if (!this.options.noAuth) { - hash = hash256(key); + const valid = new Validator([args]); + const key = valid.str(0, ''); + + if (key.length > 255) + throw new Error('Invalid API key.'); + + const data = Buffer.from(key, 'utf8'); + const hash = digest.hash256(data); + if (!ccmp(hash, this.options.apiHash)) - throw new Error('Bad key.'); + throw new Error('Invalid API key.'); } socket.auth = true; @@ -889,23 +886,22 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) { HTTPServer.prototype.handleAuth = function handleAuth(socket) { socket.hook('wallet join', async (args) => { - let valid = new Validator([args]); - let id = valid.str(0, ''); - let token = valid.buf(1); - let channel = 'w:' + id; - let wallet; + const valid = new Validator([args]); + const id = valid.str(0, ''); + const token = valid.buf(1); if (!id) throw new Error('Invalid parameter.'); if (!this.options.walletAuth) { - socket.join(channel); + socket.join(`w:${id}`); return null; } if (!token) throw new Error('Invalid parameter.'); + let wallet; try { wallet = await this.walletdb.auth(id, token); } catch (e) { @@ -918,20 +914,19 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { this.logger.info('Successful wallet auth for %s.', id); - socket.join(channel); + socket.join(`w:${id}`); return null; }); socket.hook('wallet leave', (args) => { - let valid = new Validator([args]); - let id = valid.str(0, ''); - let channel = 'w:' + id; + const valid = new Validator([args]); + const id = valid.str(0, ''); if (!id) throw new Error('Invalid parameter.'); - socket.leave(channel); + socket.leave(`w:${id}`); return null; }); @@ -952,7 +947,7 @@ function HTTPOptions(options) { this.logger = null; this.walletdb = null; this.apiKey = base58.encode(random.randomBytes(20)); - this.apiHash = hash256(this.apiKey); + this.apiHash = digest.hash256(Buffer.from(this.apiKey, 'ascii')); this.serviceHash = this.apiHash; this.noAuth = false; this.walletAuth = false; @@ -992,10 +987,12 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) { if (options.apiKey != null) { assert(typeof options.apiKey === 'string', 'API key must be a string.'); - assert(options.apiKey.length <= 200, - 'API key must be under 200 bytes.'); + assert(options.apiKey.length <= 255, + 'API key must be under 255 bytes.'); + assert(util.isAscii(options.apiKey), + 'API key must be ASCII.'); this.apiKey = options.apiKey; - this.apiHash = hash256(this.apiKey); + this.apiHash = digest.hash256(Buffer.from(this.apiKey, 'ascii')); } if (options.noAuth != null) { @@ -1021,8 +1018,7 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) { } if (options.port != null) { - assert(typeof options.port === 'number', 'Port must be a number.'); - assert(options.port > 0 && options.port <= 0xffff); + assert(util.isU16(options.port), 'Port must be a number.'); this.port = options.port; } @@ -1065,19 +1061,9 @@ HTTPOptions.fromOptions = function fromOptions(options) { * Helpers */ -function hash256(data) { - if (typeof data !== 'string') - return Buffer.alloc(0); - - if (data.length > 200) - return Buffer.alloc(0); - - return digest.hash256(Buffer.from(data, 'utf8')); -} - function enforce(value, msg) { if (!value) { - let err = new Error(msg); + const err = new Error(msg); err.statusCode = 400; throw err; } diff --git a/lib/wallet/layout-browser.js b/lib/wallet/layout-browser.js index 9b0e14acf..cbaa13ff7 100644 --- a/lib/wallet/layout-browser.js +++ b/lib/wallet/layout-browser.js @@ -6,6 +6,7 @@ 'use strict'; +const assert = require('assert'); const util = require('../utils/util'); const pad32 = util.pad32; const layouts = exports; @@ -13,106 +14,139 @@ const layouts = exports; layouts.walletdb = { binary: false, p: function p(hash) { + assert(typeof hash === 'string'); return 'p' + hash; }, pp: function pp(key) { + assert(typeof key === 'string'); return key.slice(1); }, P: function P(wid, hash) { + assert(typeof hash === 'string'); return 'p' + pad32(wid) + hash; }, Pp: function Pp(key) { + assert(typeof key === 'string'); return key.slice(11); }, r: function r(wid, index, hash) { + assert(typeof hash === 'string'); return 'r' + pad32(wid) + pad32(index) + hash; }, rr: function rr(key) { + assert(typeof key === 'string'); return key.slice(21); }, w: function w(wid) { return 'w' + pad32(wid); }, ww: function ww(key) { - return +key.slice(1); + assert(typeof key === 'string'); + return parseInt(key.slice(1), 10); }, l: function l(id) { + assert(typeof id === 'string'); return 'l' + id; }, ll: function ll(key) { + assert(typeof key === 'string'); return key.slice(1); }, a: function a(wid, index) { return 'a' + pad32(wid) + pad32(index); }, i: function i(wid, name) { + assert(typeof name === 'string'); return 'i' + pad32(wid) + name; }, ii: function ii(key) { - return [+key.slice(1, 11), key.slice(11)]; + assert(typeof key === 'string'); + return [parseInt(key.slice(1, 11), 10), key.slice(11)]; }, n: function n(wid, index) { return 'n' + pad32(wid) + pad32(index); }, R: 'R', - h: function c(height) { + h: function h(height) { return 'h' + pad32(height); }, b: function b(height) { return 'b' + pad32(height); }, bb: function bb(key) { - return +key.slice(1); + assert(typeof key === 'string'); + return parseInt(key.slice(1), 10); }, o: function o(hash, index) { + assert(typeof hash === 'string'); return 'o' + hash + pad32(index); }, oo: function oo(key) { - return [key.slice(1, 65), +key.slice(65)]; + return [key.slice(1, 65), parseInt(key.slice(65), 10)]; } }; layouts.txdb = { binary: false, prefix: function prefix(wid, key) { + assert(typeof key === 'string'); return 't' + pad32(wid) + key; }, - pre: function prefix(key) { - return +key.slice(1, 11); + pre: function pre(key) { + assert(typeof key === 'string'); + return parseInt(key.slice(1, 11), 10); }, R: 'R', hi: function hi(ch, hash, index) { + assert(typeof hash === 'string'); return ch + hash + pad32(index); }, hii: function hii(key) { + assert(typeof key === 'string'); key = key.slice(12); - return [key.slice(0, 64), +key.slice(64)]; + return [key.slice(0, 64), parseInt(key.slice(64), 10)]; }, ih: function ih(ch, index, hash) { + assert(typeof hash === 'string'); return ch + pad32(index) + hash; }, ihh: function ihh(key) { + assert(typeof key === 'string'); key = key.slice(12); - return [+key.slice(0, 10), key.slice(10)]; + return [parseInt(key.slice(0, 10), 10), key.slice(10)]; }, iih: function iih(ch, index, num, hash) { + assert(typeof hash === 'string'); return ch + pad32(index) + pad32(num) + hash; }, iihh: function iihh(key) { + assert(typeof key === 'string'); key = key.slice(12); - return [+key.slice(0, 10), +key.slice(10, 20), key.slice(20)]; + return [ + parseInt(key.slice(0, 10), 10), + parseInt(key.slice(10, 20), 10), + key.slice(20) + ]; }, ihi: function ihi(ch, index, hash, num) { + assert(typeof hash === 'string'); return ch + pad32(index) + hash + pad32(num); }, ihii: function ihii(key) { + assert(typeof key === 'string'); key = key.slice(12); - return [+key.slice(0, 10), key.slice(10, 74), +key.slice(74)]; + return [ + parseInt(key.slice(0, 10), 10), + key.slice(10, 74), + parseInt(key.slice(74), 10) + ]; }, ha: function ha(ch, hash) { + assert(typeof hash === 'string'); return ch + hash; }, haa: function haa(key) { + assert(typeof key === 'string'); key = key.slice(12); return key; }, @@ -201,7 +235,8 @@ layouts.txdb = { return 'b' + pad32(height); }, bb: function bb(key) { + assert(typeof key === 'string'); key = key.slice(12); - return +key.slice(0); + return parseInt(key.slice(0), 10); } }; diff --git a/lib/wallet/layout.js b/lib/wallet/layout.js index fb07f95bb..3f888752f 100644 --- a/lib/wallet/layout.js +++ b/lib/wallet/layout.js @@ -6,6 +6,7 @@ 'use strict'; +const assert = require('assert'); const layouts = exports; /* @@ -28,26 +29,36 @@ const layouts = exports; layouts.walletdb = { binary: true, p: function p(hash) { - let key = Buffer.allocUnsafe(1 + (hash.length / 2)); + assert(typeof hash === 'string'); + const key = Buffer.allocUnsafe(1 + (hash.length / 2)); key[0] = 0x70; key.write(hash, 1, 'hex'); return key; }, pp: function pp(key) { + assert(Buffer.isBuffer(key)); + assert(key.length >= 21); return key.toString('hex', 1); }, P: function P(wid, hash) { - let key = Buffer.allocUnsafe(1 + 4 + (hash.length / 2)); + assert(typeof wid === 'number'); + assert(typeof hash === 'string'); + const key = Buffer.allocUnsafe(1 + 4 + (hash.length / 2)); key[0] = 0x50; key.writeUInt32BE(wid, 1, true); key.write(hash, 5, 'hex'); return key; }, Pp: function Pp(key) { + assert(Buffer.isBuffer(key)); + assert(key.length >= 25); return key.toString('hex', 5); }, r: function r(wid, index, hash) { - let key = Buffer.allocUnsafe(1 + 4 + 4 + (hash.length / 2)); + assert(typeof wid === 'number'); + assert(typeof index === 'number'); + assert(typeof hash === 'string'); + const key = Buffer.allocUnsafe(1 + 4 + 4 + (hash.length / 2)); key[0] = 0x72; key.writeUInt32BE(wid, 1, true); key.writeUInt32BE(index, 5, true); @@ -55,38 +66,50 @@ layouts.walletdb = { return key; }, rr: function rr(key) { + assert(Buffer.isBuffer(key)); + assert(key.length >= 29); return key.toString('hex', 9); }, w: function w(wid) { - let key = Buffer.allocUnsafe(5); + assert(typeof wid === 'number'); + const key = Buffer.allocUnsafe(5); key[0] = 0x77; key.writeUInt32BE(wid, 1, true); return key; }, ww: function ww(key) { + assert(Buffer.isBuffer(key)); + assert(key.length === 5); return key.readUInt32BE(1, true); }, l: function l(id) { - let len = Buffer.byteLength(id, 'ascii'); - let key = Buffer.allocUnsafe(1 + len); + assert(typeof id === 'string'); + const len = Buffer.byteLength(id, 'ascii'); + const key = Buffer.allocUnsafe(1 + len); key[0] = 0x6c; if (len > 0) key.write(id, 1, 'ascii'); return key; }, ll: function ll(key) { + assert(Buffer.isBuffer(key)); + assert(key.length >= 1); return key.toString('ascii', 1); }, a: function a(wid, index) { - let key = Buffer.allocUnsafe(9); + assert(typeof wid === 'number'); + assert(typeof index === 'number'); + const key = Buffer.allocUnsafe(9); key[0] = 0x61; key.writeUInt32BE(wid, 1, true); key.writeUInt32BE(index, 5, true); return key; }, i: function i(wid, name) { - let len = Buffer.byteLength(name, 'ascii'); - let key = Buffer.allocUnsafe(5 + len); + assert(typeof wid === 'number'); + assert(typeof name === 'string'); + const len = Buffer.byteLength(name, 'ascii'); + const key = Buffer.allocUnsafe(5 + len); key[0] = 0x69; key.writeUInt32BE(wid, 1, true); if (len > 0) @@ -94,10 +117,14 @@ layouts.walletdb = { return key; }, ii: function ii(key) { + assert(Buffer.isBuffer(key)); + assert(key.length >= 5); return [key.readUInt32BE(1, true), key.toString('ascii', 5)]; }, n: function n(wid, index) { - let key = Buffer.allocUnsafe(9); + assert(typeof wid === 'number'); + assert(typeof index === 'number'); + const key = Buffer.allocUnsafe(9); key[0] = 0x6e; key.writeUInt32BE(wid, 1, true); key.writeUInt32BE(index, 5, true); @@ -105,28 +132,36 @@ layouts.walletdb = { }, R: Buffer.from([0x52]), h: function h(height) { - let key = Buffer.allocUnsafe(5); + assert(typeof height === 'number'); + const key = Buffer.allocUnsafe(5); key[0] = 0x68; key.writeUInt32BE(height, 1, true); return key; }, b: function b(height) { - let key = Buffer.allocUnsafe(5); + assert(typeof height === 'number'); + const key = Buffer.allocUnsafe(5); key[0] = 0x62; key.writeUInt32BE(height, 1, true); return key; }, bb: function bb(key) { + assert(Buffer.isBuffer(key)); + assert(key.length === 5); return key.readUInt32BE(1, true); }, o: function o(hash, index) { - let key = Buffer.allocUnsafe(37); + assert(typeof hash === 'string'); + assert(typeof index === 'number'); + const key = Buffer.allocUnsafe(37); key[0] = 0x6f; key.write(hash, 1, 'hex'); key.writeUInt32BE(index, 33, true); return key; }, oo: function oo(key) { + assert(Buffer.isBuffer(key)); + assert(key.length === 37); return [key.toString('hex', 1, 33), key.readUInt32BE(33, true)]; } }; @@ -152,40 +187,55 @@ layouts.walletdb = { layouts.txdb = { binary: true, prefix: function prefix(wid, key) { - let out = Buffer.allocUnsafe(5 + key.length); + assert(typeof wid === 'number'); + assert(Buffer.isBuffer(key)); + const out = Buffer.allocUnsafe(5 + key.length); out[0] = 0x74; out.writeUInt32BE(wid, 1); key.copy(out, 5); return out; }, - pre: function prefix(key) { + pre: function pre(key) { + assert(Buffer.isBuffer(key)); + assert(key.length >= 5); return key.readUInt32BE(1, true); }, R: Buffer.from([0x52]), hi: function hi(ch, hash, index) { - let key = Buffer.allocUnsafe(37); + assert(typeof hash === 'string'); + assert(typeof index === 'number'); + const key = Buffer.allocUnsafe(37); key[0] = ch; key.write(hash, 1, 'hex'); key.writeUInt32BE(index, 33, true); return key; }, hii: function hii(key) { + assert(Buffer.isBuffer(key)); + assert(key.length - 5 === 37); key = key.slice(6); return [key.toString('hex', 0, 32), key.readUInt32BE(32, true)]; }, ih: function ih(ch, index, hash) { - let key = Buffer.allocUnsafe(37); + assert(typeof index === 'number'); + assert(typeof hash === 'string'); + const key = Buffer.allocUnsafe(37); key[0] = ch; key.writeUInt32BE(index, 1, true); key.write(hash, 5, 'hex'); return key; }, ihh: function ihh(key) { + assert(Buffer.isBuffer(key)); + assert(key.length - 5 === 37); key = key.slice(6); return [key.readUInt32BE(0, true), key.toString('hex', 4, 36)]; }, iih: function iih(ch, index, num, hash) { - let key = Buffer.allocUnsafe(41); + assert(typeof index === 'number'); + assert(typeof num === 'number'); + assert(typeof hash === 'string'); + const key = Buffer.allocUnsafe(41); key[0] = ch; key.writeUInt32BE(index, 1, true); key.writeUInt32BE(num, 5, true); @@ -193,6 +243,8 @@ layouts.txdb = { return key; }, iihh: function iihh(key) { + assert(Buffer.isBuffer(key)); + assert(key.length - 5 === 41); key = key.slice(6); return [ key.readUInt32BE(0, true), @@ -201,7 +253,10 @@ layouts.txdb = { ]; }, ihi: function ihi(ch, index, hash, num) { - let key = Buffer.allocUnsafe(41); + assert(typeof index === 'number'); + assert(typeof hash === 'string'); + assert(typeof num === 'number'); + const key = Buffer.allocUnsafe(41); key[0] = ch; key.writeUInt32BE(index, 1, true); key.write(hash, 5, 'hex'); @@ -209,6 +264,8 @@ layouts.txdb = { return key; }, ihii: function ihii(key) { + assert(Buffer.isBuffer(key)); + assert(key.length - 5 === 41); key = key.slice(6); return [ key.readUInt32BE(0, true), @@ -217,12 +274,15 @@ layouts.txdb = { ]; }, ha: function ha(ch, hash) { - let key = Buffer.allocUnsafe(33); + assert(typeof hash === 'string'); + const key = Buffer.allocUnsafe(33); key[0] = ch; key.write(hash, 1, 'hex'); return key; }, haa: function haa(key) { + assert(Buffer.isBuffer(key)); + assert(key.length - 5 === 33); key = key.slice(6); return key.toString('hex', 0); }, @@ -302,12 +362,15 @@ layouts.txdb = { return this.ha(0x72, hash); }, b: function b(height) { - let key = Buffer.allocUnsafe(5); + assert(typeof height === 'number'); + const key = Buffer.allocUnsafe(5); key[0] = 0x62; key.writeUInt32BE(height, 1, true); return key; }, bb: function bb(key) { + assert(Buffer.isBuffer(key)); + assert(key.length - 5 === 5); key = key.slice(6); return key.readUInt32BE(0, true); } diff --git a/lib/wallet/masterkey.js b/lib/wallet/masterkey.js index 6cc158da1..ed780e482 100644 --- a/lib/wallet/masterkey.js +++ b/lib/wallet/masterkey.js @@ -129,22 +129,22 @@ MasterKey.prototype.fromOptions = function fromOptions(options) { } if (options.rounds != null) { - assert(util.isNumber(options.rounds)); + assert(util.isU32(options.rounds)); this.N = options.rounds; } if (options.N != null) { - assert(util.isNumber(options.N)); + assert(util.isU32(options.N)); this.N = options.N; } if (options.r != null) { - assert(util.isNumber(options.r)); + assert(util.isU32(options.r)); this.r = options.r; } if (options.p != null) { - assert(util.isNumber(options.p)); + assert(util.isU32(options.p)); this.p = options.p; } @@ -169,12 +169,12 @@ MasterKey.fromOptions = function fromOptions(options) { * @returns {Promise} - Returns {@link HDPrivateKey}. */ -MasterKey.prototype.unlock = async function _unlock(passphrase, timeout) { - let unlock = await this.locker.lock(); +MasterKey.prototype.unlock = async function unlock(passphrase, timeout) { + const _unlock = await this.locker.lock(); try { return await this._unlock(passphrase, timeout); } finally { - unlock(); + _unlock(); } }; @@ -187,8 +187,6 @@ MasterKey.prototype.unlock = async function _unlock(passphrase, timeout) { */ MasterKey.prototype._unlock = async function _unlock(passphrase, timeout) { - let data, key; - if (this.key) { if (this.encrypted) { assert(this.timer != null); @@ -202,8 +200,8 @@ MasterKey.prototype._unlock = async function _unlock(passphrase, timeout) { assert(this.encrypted); - key = await this.derive(passphrase); - data = aes.decipher(this.ciphertext, key, this.iv); + const key = await this.derive(passphrase); + const data = aes.decipher(this.ciphertext, key, this.iv); this.fromKeyRaw(data); @@ -253,10 +251,10 @@ MasterKey.prototype.stop = function stop() { */ MasterKey.prototype.derive = async function derive(passwd) { - let salt = MasterKey.SALT; - let N = this.N; - let r = this.r; - let p = this.p; + const salt = MasterKey.SALT; + const N = this.N; + const r = this.r; + const p = this.p; if (typeof passwd === 'string') passwd = Buffer.from(passwd, 'utf8'); @@ -280,7 +278,7 @@ MasterKey.prototype.derive = async function derive(passwd) { MasterKey.prototype.encipher = function encipher(data, iv) { if (!this.aesKey) - return; + return null; if (typeof iv === 'string') iv = Buffer.from(iv, 'hex'); @@ -297,7 +295,7 @@ MasterKey.prototype.encipher = function encipher(data, iv) { MasterKey.prototype.decipher = function decipher(data, iv) { if (!this.aesKey) - return; + return null; if (typeof iv === 'string') iv = Buffer.from(iv, 'hex'); @@ -312,8 +310,8 @@ MasterKey.prototype.decipher = function decipher(data, iv) { * @returns {Promise} */ -MasterKey.prototype.lock = async function _lock() { - let unlock = await this.locker.lock(); +MasterKey.prototype.lock = async function lock() { + const unlock = await this.locker.lock(); try { return await this._lock(); } finally { @@ -327,7 +325,7 @@ MasterKey.prototype.lock = async function _lock() { * the timer if there is one. */ -MasterKey.prototype._lock = function lock() { +MasterKey.prototype._lock = function _lock() { if (!this.encrypted) { assert(this.timer == null); assert(this.key); @@ -363,7 +361,7 @@ MasterKey.prototype.destroy = async function destroy() { */ MasterKey.prototype.decrypt = async function decrypt(passphrase, clean) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._decrypt(passphrase, clean); } finally { @@ -378,9 +376,7 @@ MasterKey.prototype.decrypt = async function decrypt(passphrase, clean) { * @returns {Promise} */ -MasterKey.prototype._decrypt = async function decrypt(passphrase, clean) { - let key, data; - +MasterKey.prototype._decrypt = async function _decrypt(passphrase, clean) { if (!this.encrypted) throw new Error('Master key is not encrypted.'); @@ -389,8 +385,8 @@ MasterKey.prototype._decrypt = async function decrypt(passphrase, clean) { this._lock(); - key = await this.derive(passphrase); - data = aes.decipher(this.ciphertext, key, this.iv); + const key = await this.derive(passphrase); + const data = aes.decipher(this.ciphertext, key, this.iv); this.fromKeyRaw(data); this.encrypted = false; @@ -399,7 +395,7 @@ MasterKey.prototype._decrypt = async function decrypt(passphrase, clean) { if (!clean) { cleanse(key); - return; + return null; } return key; @@ -412,7 +408,7 @@ MasterKey.prototype._decrypt = async function decrypt(passphrase, clean) { */ MasterKey.prototype.encrypt = async function encrypt(passphrase, clean) { - let unlock = await this.locker.lock(); + const unlock = await this.locker.lock(); try { return await this._encrypt(passphrase, clean); } finally { @@ -427,22 +423,20 @@ MasterKey.prototype.encrypt = async function encrypt(passphrase, clean) { * @returns {Promise} */ -MasterKey.prototype._encrypt = async function encrypt(passphrase, clean) { - let key, data, iv; - +MasterKey.prototype._encrypt = async function _encrypt(passphrase, clean) { if (this.encrypted) throw new Error('Master key is already encrypted.'); if (!passphrase) throw new Error('No passphrase provided.'); - data = this.toKeyRaw(); - iv = random.randomBytes(16); + const raw = this.toKeyRaw(); + const iv = random.randomBytes(16); this.stop(); - key = await this.derive(passphrase); - data = aes.encipher(data, key, iv); + const key = await this.derive(passphrase); + const data = aes.encipher(raw, key, iv); this.key = null; this.mnemonic = null; @@ -452,7 +446,7 @@ MasterKey.prototype._encrypt = async function encrypt(passphrase, clean) { if (!clean) { cleanse(key); - return; + return null; } return key; @@ -481,7 +475,7 @@ MasterKey.prototype.getKeySize = function getKeySize() { */ MasterKey.prototype.toKeyRaw = function toKeyRaw() { - let bw = new StaticWriter(this.getKeySize()); + const bw = new StaticWriter(this.getKeySize()); this.key.toWriter(bw); @@ -501,7 +495,7 @@ MasterKey.prototype.toKeyRaw = function toKeyRaw() { */ MasterKey.prototype.fromKeyRaw = function fromKeyRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.key = HD.PrivateKey.fromReader(br); @@ -540,8 +534,7 @@ MasterKey.prototype.getSize = function getSize() { */ MasterKey.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const bw = new StaticWriter(this.getSize()); if (this.encrypted) { bw.writeU8(1); @@ -559,7 +552,7 @@ MasterKey.prototype.toRaw = function toRaw() { bw.writeU8(0); // NOTE: useless varint - size = this.getKeySize(); + const size = this.getKeySize(); bw.writeVarint(size); bw.writeBytes(this.key.toRaw()); @@ -581,7 +574,7 @@ MasterKey.prototype.toRaw = function toRaw() { */ MasterKey.prototype.fromRaw = function fromRaw(raw) { - let br = new BufferReader(raw); + const br = new BufferReader(raw); this.encrypted = br.readU8() === 1; @@ -681,7 +674,7 @@ MasterKey.prototype.toJSON = function toJSON(unsafe) { */ MasterKey.prototype.inspect = function inspect() { - let json = this.toJSON(true); + const json = this.toJSON(true); if (this.key) json.key = this.key.toJSON(); diff --git a/lib/wallet/nodeclient.js b/lib/wallet/nodeclient.js index 9c94ffe8a..d28cca2e8 100644 --- a/lib/wallet/nodeclient.js +++ b/lib/wallet/nodeclient.js @@ -6,7 +6,6 @@ 'use strict'; -const util = require('../utils/util'); const AsyncObject = require('../utils/asyncobject'); /** @@ -30,14 +29,14 @@ function NodeClient(node) { this._init(); } -util.inherits(NodeClient, AsyncObject); +Object.setPrototypeOf(NodeClient.prototype, AsyncObject.prototype); /** * Initialize the client. * @returns {Promise} */ -NodeClient.prototype._init = function init() { +NodeClient.prototype._init = function _init() { this.node.on('connect', (entry, block) => { if (!this.listen) return; @@ -72,7 +71,7 @@ NodeClient.prototype._init = function init() { * @returns {Promise} */ -NodeClient.prototype._open = function open(options) { +NodeClient.prototype._open = function _open(options) { this.listen = true; return Promise.resolve(); }; @@ -82,7 +81,7 @@ NodeClient.prototype._open = function open(options) { * @returns {Promise} */ -NodeClient.prototype._close = function close() { +NodeClient.prototype._close = function _close() { this.listen = false; return Promise.resolve(); }; @@ -103,13 +102,13 @@ NodeClient.prototype.getTip = function getTip() { */ NodeClient.prototype.getEntry = async function getEntry(hash) { - let entry = await this.node.chain.db.getEntry(hash); + const entry = await this.node.chain.db.getEntry(hash); if (!entry) - return; + return null; - if (!(await entry.isMainChain())) - return; + if (!await entry.isMainChain()) + return null; return entry; }; @@ -164,10 +163,11 @@ NodeClient.prototype.resetFilter = function resetFilter() { * @returns {Promise} */ -NodeClient.prototype.estimateFee = function estimateFee(blocks) { +NodeClient.prototype.estimateFee = async function estimateFee(blocks) { if (!this.node.fees) - return Promise.resolve(this.network.feeRate); - return Promise.resolve(this.node.fees.estimateFee(blocks)); + return this.network.feeRate; + + return this.node.fees.estimateFee(blocks); }; /** diff --git a/lib/wallet/path.js b/lib/wallet/path.js index 88db8b55a..ca2bc3a69 100644 --- a/lib/wallet/path.js +++ b/lib/wallet/path.js @@ -104,7 +104,7 @@ Path.fromOptions = function fromOptions(options) { */ Path.prototype.clone = function clone() { - let path = new Path(); + const path = new Path(); path.keyType = this.keyType; @@ -132,7 +132,7 @@ Path.prototype.clone = function clone() { */ Path.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.account = br.readU32(); this.keyType = br.readU8(); @@ -154,7 +154,7 @@ Path.prototype.fromRaw = function fromRaw(data) { break; } - this.version = br.read8(); + this.version = br.readI8(); this.type = br.readU8(); if (this.type === 129 || this.type === 130) @@ -204,8 +204,8 @@ Path.prototype.getSize = function getSize() { */ Path.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeU32(this.account); bw.writeU8(this.keyType); @@ -232,7 +232,7 @@ Path.prototype.toRaw = function toRaw() { break; } - bw.write8(this.version); + bw.writeI8(this.version); bw.writeU8(this.type); return bw.render(); diff --git a/lib/wallet/plugin.js b/lib/wallet/plugin.js index d0b35b547..4334e6e3c 100644 --- a/lib/wallet/plugin.js +++ b/lib/wallet/plugin.js @@ -29,29 +29,28 @@ plugin.id = 'walletdb'; */ plugin.init = function init(node) { - let config = node.config; - let client = new NodeClient(node); - let wdb; + const config = node.config; + const client = new NodeClient(node); - wdb = new WalletDB({ + const wdb = new WalletDB({ network: node.network, logger: node.logger, workers: node.workers, client: client, prefix: config.prefix, db: config.str(['wallet-db', 'db']), - maxFiles: config.num('wallet-max-files'), + maxFiles: config.uint('wallet-max-files'), cacheSize: config.mb('wallet-cache-size'), witness: config.bool('wallet-witness'), checkpoints: config.bool('wallet-checkpoints'), - startHeight: config.num('wallet-start-height'), + startHeight: config.uint('wallet-start-height'), wipeNoReally: config.bool('wallet-wipe-no-really'), apiKey: config.str(['wallet-api-key', 'api-key']), walletAuth: config.bool('wallet-auth'), noAuth: config.bool(['wallet-no-auth', 'no-auth']), ssl: config.str('wallet-ssl'), host: config.str('wallet-host'), - port: config.num('wallet-port'), + port: config.uint('wallet-port'), spv: node.spv, verify: node.spv, listen: false diff --git a/lib/wallet/records.js b/lib/wallet/records.js index a72707655..2b78c808b 100644 --- a/lib/wallet/records.js +++ b/lib/wallet/records.js @@ -38,7 +38,7 @@ function ChainState() { */ ChainState.prototype.clone = function clone() { - let state = new ChainState(); + const state = new ChainState(); state.startHeight = this.startHeight; state.startHash = this.startHash; state.height = this.height; @@ -53,7 +53,7 @@ ChainState.prototype.clone = function clone() { */ ChainState.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.startHeight = br.readU32(); this.startHash = br.readHash('hex'); @@ -83,7 +83,7 @@ ChainState.fromRaw = function fromRaw(data) { */ ChainState.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(41); + const bw = new StaticWriter(41); bw.writeU32(this.startHeight); bw.writeHash(this.startHash); @@ -98,16 +98,16 @@ ChainState.prototype.toRaw = function toRaw() { * @constructor * @param {Hash} hash * @param {Number} height - * @param {Number} ts + * @param {Number} time */ -function BlockMeta(hash, height, ts) { +function BlockMeta(hash, height, time) { if (!(this instanceof BlockMeta)) - return new BlockMeta(hash, height, ts); + return new BlockMeta(hash, height, time); this.hash = hash || encoding.NULL_HASH; this.height = height != null ? height : -1; - this.ts = ts || 0; + this.time = time || 0; } /** @@ -116,7 +116,7 @@ function BlockMeta(hash, height, ts) { */ BlockMeta.prototype.clone = function clone() { - return new BlockMeta(this.hash, this.height, this.ts); + return new BlockMeta(this.hash, this.height, this.time); }; /** @@ -137,7 +137,7 @@ BlockMeta.prototype.toHash = function toHash() { BlockMeta.prototype.fromEntry = function fromEntry(entry) { this.hash = entry.hash; this.height = entry.height; - this.ts = entry.ts; + this.time = entry.time; return this; }; @@ -150,7 +150,7 @@ BlockMeta.prototype.fromEntry = function fromEntry(entry) { BlockMeta.prototype.fromJSON = function fromJSON(json) { this.hash = util.revHex(json.hash); this.height = json.height; - this.ts = json.ts; + this.time = json.time; return this; }; @@ -161,10 +161,10 @@ BlockMeta.prototype.fromJSON = function fromJSON(json) { */ BlockMeta.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.hash = br.readHash('hex'); this.height = br.readU32(); - this.ts = br.readU32(); + this.time = br.readU32(); return this; }; @@ -205,10 +205,10 @@ BlockMeta.fromRaw = function fromRaw(data) { */ BlockMeta.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(42); + const bw = new StaticWriter(42); bw.writeHash(this.hash); bw.writeU32(this.height); - bw.writeU32(this.ts); + bw.writeU32(this.time); return bw.render(); }; @@ -221,7 +221,7 @@ BlockMeta.prototype.toJSON = function toJSON() { return { hash: util.revHex(this.hash), height: this.height, - ts: this.ts + time: this.time }; }; @@ -237,8 +237,7 @@ function BlockMapRecord(height) { return new BlockMapRecord(height); this.height = height != null ? height : -1; - this.txs = []; - this.index = {}; + this.txs = new Map(); } /** @@ -249,14 +248,13 @@ function BlockMapRecord(height) { */ BlockMapRecord.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let count = br.readU32(); + const br = new BufferReader(data); + const count = br.readU32(); for (let i = 0; i < count; i++) { - let hash = br.readHash('hex'); - let tx = TXMapRecord.fromReader(hash, br); - this.txs.push(tx); - this.index[tx.hash] = tx; + const hash = br.readHash('hex'); + const tx = TXMapRecord.fromReader(hash, br); + this.txs.set(tx.hash, tx); } return this; @@ -283,7 +281,7 @@ BlockMapRecord.prototype.getSize = function getSize() { size += 4; - for (let tx of this.txs) { + for (const tx of this.txs.values()) { size += 32; size += tx.getSize(); } @@ -298,13 +296,13 @@ BlockMapRecord.prototype.getSize = function getSize() { */ BlockMapRecord.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); - bw.writeU32(this.txs.length); + bw.writeU32(this.txs.size); - for (let tx of this.txs) { - bw.writeHash(tx.hash); + for (const [hash, tx] of this.txs) { + bw.writeHash(hash); tx.toWriter(bw); } @@ -319,14 +317,11 @@ BlockMapRecord.prototype.toRaw = function toRaw() { */ BlockMapRecord.prototype.add = function add(hash, wid) { - let tx = this.index[hash]; + let tx = this.txs.get(hash); if (!tx) { tx = new TXMapRecord(hash); - tx.wids.push(wid); - this.txs.push(tx); - this.index[tx.hash] = tx; - return true; + this.txs.set(hash, tx); } return tx.add(wid); @@ -340,7 +335,7 @@ BlockMapRecord.prototype.add = function add(hash, wid) { */ BlockMapRecord.prototype.remove = function remove(hash, wid) { - let tx = this.index[hash]; + const tx = this.txs.get(hash); if (!tx) return false; @@ -348,15 +343,26 @@ BlockMapRecord.prototype.remove = function remove(hash, wid) { if (!tx.remove(wid)) return false; - if (tx.wids.length === 0) { - let result = util.binaryRemove(this.txs, tx, cmpid); - assert(result); - delete this.index[tx.hash]; - } + if (tx.wids.size === 0) + this.txs.delete(tx.hash); return true; }; +/** + * Convert tx map to an array. + * @returns {Array} + */ + +BlockMapRecord.prototype.toArray = function toArray() { + const txs = []; + + for (const tx of this.txs.values()) + txs.push(tx); + + return txs; +}; + /** * TX Hash * @constructor @@ -364,18 +370,19 @@ BlockMapRecord.prototype.remove = function remove(hash, wid) { function TXMapRecord(hash, wids) { this.hash = hash || encoding.NULL_HASH; - this.wids = wids || []; - this.id = TXMapRecord.id++; + this.wids = wids || new Set(); } -TXMapRecord.id = 0; - TXMapRecord.prototype.add = function add(wid) { - return util.binaryInsert(this.wids, wid, cmp, true) !== -1; + if (this.wids.has(wid)) + return false; + + this.wids.add(wid); + return true; }; TXMapRecord.prototype.remove = function remove(wid) { - return util.binaryRemove(this.wids, wid, cmp); + return this.wids.delete(wid); }; TXMapRecord.prototype.toWriter = function toWriter(bw) { @@ -387,7 +394,7 @@ TXMapRecord.prototype.getSize = function getSize() { }; TXMapRecord.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -416,15 +423,19 @@ TXMapRecord.fromRaw = function fromRaw(hash, data) { function OutpointMapRecord(hash, index, wids) { this.hash = hash || encoding.NULL_HASH; this.index = index != null ? index : -1; - this.wids = wids || []; + this.wids = wids || new Set(); } OutpointMapRecord.prototype.add = function add(wid) { - return util.binaryInsert(this.wids, wid, cmp, true) !== -1; + if (this.wids.has(wid)) + return false; + + this.wids.add(wid); + return true; }; OutpointMapRecord.prototype.remove = function remove(wid) { - return util.binaryRemove(this.wids, wid, cmp); + return this.wids.delete(wid); }; OutpointMapRecord.prototype.toWriter = function toWriter(bw) { @@ -436,7 +447,7 @@ OutpointMapRecord.prototype.getSize = function getSize() { }; OutpointMapRecord.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -464,15 +475,19 @@ OutpointMapRecord.fromRaw = function fromRaw(hash, index, data) { function PathMapRecord(hash, wids) { this.hash = hash || encoding.NULL_HASH; - this.wids = wids || []; + this.wids = wids || new Set(); } PathMapRecord.prototype.add = function add(wid) { - return util.binaryInsert(this.wids, wid, cmp, true) !== -1; + if (this.wids.has(wid)) + return false; + + this.wids.add(wid); + return true; }; PathMapRecord.prototype.remove = function remove(wid) { - return util.binaryRemove(this.wids, wid, cmp); + return this.wids.delete(wid); }; PathMapRecord.prototype.toWriter = function toWriter(bw) { @@ -484,7 +499,7 @@ PathMapRecord.prototype.getSize = function getSize() { }; PathMapRecord.prototype.toRaw = function toRaw() { - let size = this.getSize(); + const size = this.getSize(); return this.toWriter(new StaticWriter(size)).render(); }; @@ -518,11 +533,11 @@ function TXRecord(tx, block) { this.tx = null; this.hash = null; - this.ps = util.now(); + this.mtime = util.now(); this.height = -1; this.block = null; this.index = -1; - this.ts = 0; + this.time = 0; if (tx) this.fromTX(tx, block); @@ -565,7 +580,7 @@ TXRecord.fromTX = function fromTX(tx, block) { TXRecord.prototype.setBlock = function setBlock(block) { this.height = block.height; this.block = block.hash; - this.ts = block.ts; + this.time = block.time; }; /** @@ -575,7 +590,7 @@ TXRecord.prototype.setBlock = function setBlock(block) { TXRecord.prototype.unsetBlock = function unsetBlock() { this.height = -1; this.block = null; - this.ts = 0; + this.time = 0; }; /** @@ -585,8 +600,9 @@ TXRecord.prototype.unsetBlock = function unsetBlock() { TXRecord.prototype.getBlock = function getBlock() { if (this.height === -1) - return; - return new BlockMeta(this.block, this.height, this.ts); + return null; + + return new BlockMeta(this.block, this.height, this.time); }; /** @@ -635,13 +651,13 @@ TXRecord.prototype.getSize = function getSize() { */ TXRecord.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); let index = this.index; this.tx.toWriter(bw); - bw.writeU32(this.ps); + bw.writeU32(this.mtime); if (this.block) { if (index === -1) @@ -650,7 +666,7 @@ TXRecord.prototype.toRaw = function toRaw() { bw.writeU8(1); bw.writeHash(this.block); bw.writeU32(this.height); - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU32(index); } else { bw.writeU8(0); @@ -666,18 +682,18 @@ TXRecord.prototype.toRaw = function toRaw() { */ TXRecord.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.tx = new TX(); this.tx.fromReader(br); this.hash = this.tx.hash('hex'); - this.ps = br.readU32(); + this.mtime = br.readU32(); if (br.readU8() === 1) { this.block = br.readHash('hex'); this.height = br.readU32(); - this.ts = br.readU32(); + this.time = br.readU32(); this.index = br.readU32(); if (this.index === 0x7fffffff) this.index = -1; @@ -701,32 +717,24 @@ TXRecord.fromRaw = function fromRaw(data) { * Helpers */ -function cmp(a, b) { - return a - b; -} - -function cmpid(a, b) { - return a.id - b.id; -} - function parseWallets(br) { - let count = br.readU32(); - let wids = []; + const count = br.readU32(); + const wids = new Set(); for (let i = 0; i < count; i++) - wids.push(br.readU32()); + wids.add(br.readU32()); return wids; } function sizeWallets(wids) { - return 4 + wids.length * 4; + return 4 + wids.size * 4; } function serializeWallets(bw, wids) { - bw.writeU32(wids.length); + bw.writeU32(wids.size); - for (let wid of wids) + for (const wid of wids) bw.writeU32(wid); return bw; diff --git a/lib/wallet/rpc.js b/lib/wallet/rpc.js index 31ee1a4b6..44d16e0c5 100644 --- a/lib/wallet/rpc.js +++ b/lib/wallet/rpc.js @@ -49,12 +49,11 @@ function RPC(wdb) { this.client = wdb.client; this.wallet = null; - this.feeRate = null; this.init(); } -util.inherits(RPC, RPCBase); +Object.setPrototypeOf(RPC.prototype, RPCBase.prototype); RPC.prototype.init = function init() { this.add('help', this.help); @@ -110,13 +109,11 @@ RPC.prototype.init = function init() { this.add('setloglevel', this.setLogLevel); }; -RPC.prototype.help = async function _help(args, help) { - let json; - +RPC.prototype.help = async function help(args, _help) { if (args.length === 0) return 'Select a command.'; - json = { + const json = { method: args[0], params: [] }; @@ -134,43 +131,43 @@ RPC.prototype.stop = async function stop(args, help) { }; RPC.prototype.fundRawTransaction = async function fundRawTransaction(args, help) { - let valid = new Validator([args]); - let data = valid.buf(0); - let options = valid.obj(1); - let wallet = this.wallet; - let rate = this.feeRate; - let change, tx; - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'fundrawtransaction "hexstring" ( options )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + const data = valid.buf(0); + const options = valid.obj(1); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid hex string.'); - tx = MTX.fromRaw(data); + const tx = MTX.fromRaw(data); if (tx.outputs.length === 0) { throw new RPCError(errs.INVALID_PARAMETER, 'TX must have at least one output.'); } + let rate = null; + let change = null; + if (options) { - valid = new Validator([options]); + const valid = new Validator([options]); + + rate = valid.ufixed('feeRate', 8); change = valid.str('changeAddress'); - rate = valid.btc('feeRate'); if (change) change = parseAddress(change, this.network); } - options = { + await wallet.fund(tx, { rate: rate, changeAddress: change - }; - - await wallet.fund(tx, options); + }); return { hex: tx.toRaw().toString('hex'), @@ -184,16 +181,14 @@ RPC.prototype.fundRawTransaction = async function fundRawTransaction(args, help) */ RPC.prototype.resendWalletTransactions = async function resendWalletTransactions(args, help) { - let wallet = this.wallet; - let hashes = []; - let txs; - if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'resendwallettransactions'); - txs = await wallet.resend(); + const wallet = this.wallet; + const txs = await wallet.resend(); + const hashes = []; - for (let tx of txs) + for (const tx of txs) hashes.push(tx.txid()); return hashes; @@ -218,8 +213,8 @@ RPC.prototype.addWitnessAddress = async function addWitnessAddress(args, help) { }; RPC.prototype.backupWallet = async function backupWallet(args, help) { - let valid = new Validator([args]); - let dest = valid.str(0); + const valid = new Validator([args]); + const dest = valid.str(0); if (help || args.length !== 1 || !dest) throw new RPCError(errs.MISC_ERROR, 'backupwallet "destination"'); @@ -230,16 +225,15 @@ RPC.prototype.backupWallet = async function backupWallet(args, help) { }; RPC.prototype.dumpPrivKey = async function dumpPrivKey(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let hash, ring; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'dumpprivkey "bitcoinaddress"'); - hash = parseHash(addr, this.network); - ring = await wallet.getPrivateKey(hash); + const wallet = this.wallet; + const valid = new Validator([args]); + const addr = valid.str(0, ''); + + const hash = parseHash(addr, this.network); + const ring = await wallet.getPrivateKey(hash); if (!ring) throw new RPCError(errs.MISC_ERROR, 'Key not found.'); @@ -248,21 +242,20 @@ RPC.prototype.dumpPrivKey = async function dumpPrivKey(args, help) { }; RPC.prototype.dumpWallet = async function dumpWallet(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let file = valid.str(0); - let time = util.date(); - let tip, out, hashes; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'dumpwallet "filename"'); + const wallet = this.wallet; + const valid = new Validator([args]); + const file = valid.str(0); + if (!file) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - tip = await this.wdb.getTip(); + const tip = await this.wdb.getTip(); + const time = util.date(); - out = [ + const out = [ util.fmt('# Wallet Dump created by Bcoin %s', pkg.version), util.fmt('# * Created on %s', time), util.fmt('# * Best block at time of backup was %d (%s).', @@ -271,22 +264,22 @@ RPC.prototype.dumpWallet = async function dumpWallet(args, help) { '' ]; - hashes = await wallet.getAddressHashes(); + const hashes = await wallet.getAddressHashes(); - for (let hash of hashes) { - let ring = await wallet.getPrivateKey(hash); - let addr, fmt, str; + for (const hash of hashes) { + const ring = await wallet.getPrivateKey(hash); if (!ring) continue; - addr = ring.getAddress('string'); - fmt = '%s %s label= addr=%s'; + const addr = ring.getAddress('string'); + + let fmt = '%s %s label= addr=%s'; if (ring.branch === 1) fmt = '%s %s change=1 addr=%s'; - str = util.fmt(fmt, ring.toSecret(), time, addr); + const str = util.fmt(fmt, ring.toSecret(), time, addr); out.push(str); } @@ -295,24 +288,25 @@ RPC.prototype.dumpWallet = async function dumpWallet(args, help) { out.push('# End of dump'); out.push(''); - out = out.join('\n'); + const dump = out.join('\n'); if (fs.unsupported) - return out; + return dump; - await fs.writeFile(file, out, 'utf8'); + await fs.writeFile(file, dump, 'utf8'); return null; }; RPC.prototype.encryptWallet = async function encryptWallet(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let passphrase = valid.str(0, ''); + const wallet = this.wallet; if (!wallet.master.encrypted && (help || args.length !== 1)) throw new RPCError(errs.MISC_ERROR, 'encryptwallet "passphrase"'); + const valid = new Validator([args]); + const passphrase = valid.str(0, ''); + if (wallet.master.encrypted) { throw new RPCError(errs.WALLET_WRONG_ENC_STATE, 'Already running with an encrypted wallet.'); @@ -331,18 +325,17 @@ RPC.prototype.encryptWallet = async function encryptWallet(args, help) { }; RPC.prototype.getAccountAddress = async function getAccountAddress(args, help) { - let valid = new Validator([args]); - let wallet = this.wallet; - let name = valid.str(0, ''); - let account; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'getaccountaddress "account"'); + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0, ''); + if (!name) name = 'default'; - account = await wallet.getAccount(name); + const account = await wallet.getAccount(name); if (!account) return ''; @@ -351,16 +344,15 @@ RPC.prototype.getAccountAddress = async function getAccountAddress(args, help) { }; RPC.prototype.getAccount = async function getAccount(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let hash, path; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'getaccount "bitcoinaddress"'); - hash = parseHash(addr, this.network); - path = await wallet.getPath(hash); + const wallet = this.wallet; + const valid = new Validator([args]); + const addr = valid.str(0, ''); + + const hash = parseHash(addr, this.network); + const path = await wallet.getPath(hash); if (!path) return ''; @@ -369,22 +361,21 @@ RPC.prototype.getAccount = async function getAccount(args, help) { }; RPC.prototype.getAddressesByAccount = async function getAddressesByAccount(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0, ''); - let addrs = []; - let paths; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'getaddressesbyaccount "account"'); + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0, ''); + const addrs = []; + if (name === '') name = 'default'; - paths = await wallet.getPaths(name); + const paths = await wallet.getPaths(name); - for (let path of paths) { - let addr = path.toAddress(); + for (const path of paths) { + const addr = path.toAddress(); addrs.push(addr.toString(this.network)); } @@ -392,18 +383,17 @@ RPC.prototype.getAddressesByAccount = async function getAddressesByAccount(args, }; RPC.prototype.getBalance = async function getBalance(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0); - let minconf = valid.u32(1, 0); - let watchOnly = valid.bool(2, false); - let value, balance; - if (help || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'getbalance ( "account" minconf includeWatchonly )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0); + const minconf = valid.u32(1, 0); + const watchOnly = valid.bool(2, false); + if (name === '') name = 'default'; @@ -413,8 +403,9 @@ RPC.prototype.getBalance = async function getBalance(args, help) { if (wallet.watchOnly !== watchOnly) return 0; - balance = await wallet.getBalance(name); + const balance = await wallet.getBalance(name); + let value; if (minconf > 0) value = balance.confirmed; else @@ -424,62 +415,59 @@ RPC.prototype.getBalance = async function getBalance(args, help) { }; RPC.prototype.getNewAddress = async function getNewAddress(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0); - let addr; - if (help || args.length > 1) throw new RPCError(errs.MISC_ERROR, 'getnewaddress ( "account" )'); + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0); + if (name === '') name = 'default'; - addr = await wallet.createReceive(name); + const addr = await wallet.createReceive(name); return addr.getAddress('string'); }; RPC.prototype.getRawChangeAddress = async function getRawChangeAddress(args, help) { - let wallet = this.wallet; - let addr; - if (help || args.length > 1) throw new RPCError(errs.MISC_ERROR, 'getrawchangeaddress'); - addr = await wallet.createChange(); + const wallet = this.wallet; + const addr = await wallet.createChange(); return addr.getAddress('string'); }; RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0); - let minconf = valid.u32(0, 0); - let height = this.wdb.state.height; - let total = 0; - let filter = {}; - let lastConf = -1; - let paths, txs; - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'getreceivedbyaccount "account" ( minconf )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0); + const minconf = valid.u32(1, 0); + const height = this.wdb.state.height; + if (name === '') name = 'default'; - paths = await wallet.getPaths(name); + const paths = await wallet.getPaths(name); + const filter = new Set(); + + for (const path of paths) + filter.add(path.hash); - for (let path of paths) - filter[path.hash] = true; + const txs = await wallet.getHistory(name); - txs = await wallet.getHistory(name); + let total = 0; + let lastConf = -1; - for (let wtx of txs) { - let conf = wtx.getDepth(height); + for (const wtx of txs) { + const conf = wtx.getDepth(height); if (conf < minconf) continue; @@ -487,9 +475,9 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h if (lastConf === -1 || conf < lastConf) lastConf = conf; - for (let output of wtx.tx.outputs) { - let hash = output.getHash('hex'); - if (hash && filter[hash]) + for (const output of wtx.tx.outputs) { + const hash = output.getHash('hex'); + if (hash && filter.has(hash)) total += output.value; } } @@ -498,27 +486,27 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h }; RPC.prototype.getReceivedByAddress = async function getReceivedByAddress(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let minconf = valid.u32(1, 0); - let height = this.wdb.state.height; - let total = 0; - let hash, txs; - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'getreceivedbyaddress "bitcoinaddress" ( minconf )'); } - hash = parseHash(addr, this.network); - txs = await wallet.getHistory(); + const wallet = this.wallet; + const valid = new Validator([args]); + const addr = valid.str(0, ''); + const minconf = valid.u32(1, 0); + const height = this.wdb.state.height; - for (let wtx of txs) { + const hash = parseHash(addr, this.network); + const txs = await wallet.getHistory(); + + let total = 0; + + for (const wtx of txs) { if (wtx.getDepth(height) < minconf) continue; - for (let output of wtx.tx.outputs) { + for (const output of wtx.tx.outputs) { if (output.getHash('hex') === hash) total += output.value; } @@ -528,25 +516,26 @@ RPC.prototype.getReceivedByAddress = async function getReceivedByAddress(args, h }; RPC.prototype._toWalletTX = async function _toWalletTX(wtx) { - let wallet = this.wallet; - let details = await wallet.toDetails(wtx); - let det = []; - let sent = 0; - let received = 0; - let receive = true; + const wallet = this.wallet; + const details = await wallet.toDetails(wtx); if (!details) throw new RPCError(errs.WALLET_ERROR, 'TX not found.'); - for (let member of details.inputs) { + let receive = true; + for (const member of details.inputs) { if (member.path) { receive = false; break; } } + const det = []; + let sent = 0; + let received = 0; + for (let i = 0; i < details.outputs.length; i++) { - let member = details.outputs[i]; + const member = details.outputs[i]; if (member.path) { if (member.path.branch === 1) @@ -588,11 +577,11 @@ RPC.prototype._toWalletTX = async function _toWalletTX(wtx) { confirmations: details.confirmations, blockhash: details.block ? util.revHex(details.block) : null, blockindex: details.index, - blocktime: details.ts, + blocktime: details.time, txid: util.revHex(details.hash), walletconflicts: [], - time: details.ps, - timereceived: details.ps, + time: details.mtime, + timereceived: details.mtime, 'bip125-replaceable': 'no', details: det, hex: details.tx.toRaw().toString('hex') @@ -600,41 +589,39 @@ RPC.prototype._toWalletTX = async function _toWalletTX(wtx) { }; RPC.prototype.getTransaction = async function getTransaction(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let hash = valid.hash(0); - let watchOnly = valid.bool(1, false); - let wtx; - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'gettransaction "txid" ( includeWatchonly )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + const hash = valid.hash(0); + const watchOnly = valid.bool(1, false); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter'); - wtx = await wallet.getTX(hash); + const wtx = await wallet.getTX(hash); if (!wtx) - throw new RPCError(errs.WALLET_ERROR, 'TX not found.'); + throw new RPCError(errs.INVALID_ADDRESS_OR_KEY, 'TX not found.'); return await this._toWalletTX(wtx, watchOnly); }; RPC.prototype.abandonTransaction = async function abandonTransaction(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let hash = valid.hash(0); - let result; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'abandontransaction "txid"'); + const wallet = this.wallet; + const valid = new Validator([args]); + const hash = valid.hash(0); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - result = await wallet.abandon(hash); + const result = await wallet.abandon(hash); if (!result) throw new RPCError(errs.WALLET_ERROR, 'Transaction not in wallet.'); @@ -643,25 +630,21 @@ RPC.prototype.abandonTransaction = async function abandonTransaction(args, help) }; RPC.prototype.getUnconfirmedBalance = async function getUnconfirmedBalance(args, help) { - let wallet = this.wallet; - let balance; - if (help || args.length > 0) throw new RPCError(errs.MISC_ERROR, 'getunconfirmedbalance'); - balance = await wallet.getBalance(); + const wallet = this.wallet; + const balance = await wallet.getBalance(); return Amount.btc(balance.unconfirmed, true); }; RPC.prototype.getWalletInfo = async function getWalletInfo(args, help) { - let wallet = this.wallet; - let balance; - if (help || args.length !== 0) throw new RPCError(errs.MISC_ERROR, 'getwalletinfo'); - balance = await wallet.getBalance(); + const wallet = this.wallet; + const balance = await wallet.getBalance(); return { walletid: wallet.id, @@ -672,25 +655,22 @@ RPC.prototype.getWalletInfo = async function getWalletInfo(args, help) { keypoololdest: 0, keypoolsize: 0, unlocked_until: wallet.master.until, - paytxfee: this.feeRate != null - ? Amount.btc(this.feeRate, true) - : 0 + paytxfee: Amount.btc(this.wdb.feeRate, true) }; }; RPC.prototype.importPrivKey = async function importPrivKey(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let secret = valid.str(0); - let rescan = valid.bool(2, false); - let key; - if (help || args.length < 1 || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'importprivkey "bitcoinprivkey" ( "label" rescan )'); } - key = parseSecret(secret, this.network); + const wallet = this.wallet; + const valid = new Validator([args]); + const secret = valid.str(0); + const rescan = valid.bool(2, false); + + const key = parseSecret(secret, this.network); await wallet.importKey(0, key); @@ -701,26 +681,22 @@ RPC.prototype.importPrivKey = async function importPrivKey(args, help) { }; RPC.prototype.importWallet = async function importWallet(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let file = valid.str(0); - let rescan = valid.bool(1, false); - let keys = []; - let data, lines; - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'importwallet "filename" ( rescan )'); + const wallet = this.wallet; + const valid = new Validator([args]); + const file = valid.str(0); + const rescan = valid.bool(1, false); + if (fs.unsupported) throw new RPCError(errs.INTERNAL_ERROR, 'FS not available.'); - data = await fs.readFile(file, 'utf8'); - - lines = data.split(/\n+/); + const data = await fs.readFile(file, 'utf8'); + const lines = data.split(/\n+/); + const keys = []; for (let line of lines) { - let parts, secret; - line = line.trim(); if (line.length === 0) @@ -729,17 +705,17 @@ RPC.prototype.importWallet = async function importWallet(args, help) { if (/^\s*#/.test(line)) continue; - parts = line.split(/\s+/); + const parts = line.split(/\s+/); if (parts.length < 4) throw new RPCError(errs.DESERIALIZATION_ERROR, 'Malformed wallet.'); - secret = parseSecret(parts[0], this.network); + const secret = parseSecret(parts[0], this.network); keys.push(secret); } - for (let key of keys) + for (const key of keys) await wallet.importKey(0, key); if (rescan) @@ -749,20 +725,19 @@ RPC.prototype.importWallet = async function importWallet(args, help) { }; RPC.prototype.importAddress = async function importAddress(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let rescan = valid.bool(2, false); - let p2sh = valid.bool(3, false); - let script; - if (help || args.length < 1 || args.length > 4) { throw new RPCError(errs.MISC_ERROR, 'importaddress "address" ( "label" rescan p2sh )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + let addr = valid.str(0, ''); + const rescan = valid.bool(2, false); + const p2sh = valid.bool(3, false); + if (p2sh) { - script = valid.buf(0); + let script = valid.buf(0); if (!script) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameters.'); @@ -784,21 +759,20 @@ RPC.prototype.importAddress = async function importAddress(args, help) { }; RPC.prototype.importPubkey = async function importPubkey(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let data = valid.buf(0); - let rescan = valid.bool(2, false); - let key; - if (help || args.length < 1 || args.length > 4) { throw new RPCError(errs.MISC_ERROR, 'importpubkey "pubkey" ( "label" rescan )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + const data = valid.buf(0); + const rescan = valid.bool(2, false); + if (!data) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - key = KeyRing.fromPublic(data, this.network); + const key = KeyRing.fromPublic(data, this.network); await wallet.importKey(0, key); @@ -815,22 +789,21 @@ RPC.prototype.keyPoolRefill = async function keyPoolRefill(args, help) { }; RPC.prototype.listAccounts = async function listAccounts(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let minconf = valid.u32(0, 0); - let watchOnly = valid.bool(1, false); - let map = {}; - let accounts; - if (help || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'listaccounts ( minconf includeWatchonly)'); } - accounts = await wallet.getAccounts(); + const wallet = this.wallet; + const valid = new Validator([args]); + const minconf = valid.u32(0, 0); + const watchOnly = valid.bool(1, false); - for (let account of accounts) { - let balance = await wallet.getBalance(account); + const accounts = await wallet.getAccounts(); + const map = {}; + + for (const account of accounts) { + const balance = await wallet.getBalance(account); let value = balance.unconfirmed; if (minconf > 0) @@ -852,16 +825,14 @@ RPC.prototype.listAddressGroupings = async function listAddressGroupings(args, h }; RPC.prototype.listLockUnspent = async function listLockUnspent(args, help) { - let wallet = this.wallet; - let out = []; - let outpoints; - if (help || args.length > 0) throw new RPCError(errs.MISC_ERROR, 'listlockunspent'); - outpoints = wallet.getLocked(); + const wallet = this.wallet; + const outpoints = wallet.getLocked(); + const out = []; - for (let outpoint of outpoints) { + for (const outpoint of outpoints) { out.push({ txid: outpoint.txid(), vout: outpoint.index @@ -872,71 +843,67 @@ RPC.prototype.listLockUnspent = async function listLockUnspent(args, help) { }; RPC.prototype.listReceivedByAccount = async function listReceivedByAccount(args, help) { - let valid = new Validator([args]); - let minconf = valid.u32(0, 0); - let includeEmpty = valid.bool(1, false); - let watchOnly = valid.bool(2, false); - if (help || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'listreceivedbyaccount ( minconf includeempty includeWatchonly )'); } + const valid = new Validator([args]); + const minconf = valid.u32(0, 0); + const includeEmpty = valid.bool(1, false); + const watchOnly = valid.bool(2, false); + return await this._listReceived(minconf, includeEmpty, watchOnly, true); }; RPC.prototype.listReceivedByAddress = async function listReceivedByAddress(args, help) { - let valid = new Validator([args]); - let minconf = valid.u32(0, 0); - let includeEmpty = valid.bool(1, false); - let watchOnly = valid.bool(2, false); - if (help || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'listreceivedbyaddress ( minconf includeempty includeWatchonly )'); } + const valid = new Validator([args]); + const minconf = valid.u32(0, 0); + const includeEmpty = valid.bool(1, false); + const watchOnly = valid.bool(2, false); + return await this._listReceived(minconf, includeEmpty, watchOnly, false); }; RPC.prototype._listReceived = async function _listReceived(minconf, empty, watchOnly, account) { - let wallet = this.wallet; - let paths = await wallet.getPaths(); - let height = this.wdb.state.height; - let out = []; - let result = []; - let map = {}; - let txs, keys; - - for (let path of paths) { - let addr = path.toAddress(); - map[path.hash] = { + const wallet = this.wallet; + const paths = await wallet.getPaths(); + const height = this.wdb.state.height; + + const map = new Map(); + for (const path of paths) { + const addr = path.toAddress(); + map.set(path.hash, { involvesWatchonly: wallet.watchOnly, address: addr.toString(this.network), account: path.name, amount: 0, confirmations: -1, - label: '', - }; + label: '' + }); } - txs = await wallet.getHistory(); + const txs = await wallet.getHistory(); - for (let wtx of txs) { - let conf = wtx.getDepth(height); + for (const wtx of txs) { + const conf = wtx.getDepth(height); if (conf < minconf) continue; - for (let output of wtx.tx.outputs) { - let addr = output.getAddress(); - let hash, entry; + for (const output of wtx.tx.outputs) { + const addr = output.getAddress(); if (!addr) continue; - hash = addr.getHash('hex'); - entry = map[hash]; + const hash = addr.getHash('hex'); + const entry = map.get(hash); if (entry) { if (entry.confirmations === -1 || conf < entry.confirmations) @@ -947,20 +914,17 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch } } - keys = Object.keys(map); - - for (let key of keys) { - let entry = map[key]; + let out = []; + for (const entry of map.values()) out.push(entry); - } if (account) { - let map = {}; + const map = new Map(); - for (let entry of out) { - let item = map[entry.account]; + for (const entry of out) { + const item = map.get(entry.account); if (!item) { - map[entry.account] = entry; + map.set(entry.account, entry); entry.address = undefined; continue; } @@ -969,13 +933,12 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch out = []; - for (let key of Object.keys(map)) { - let entry = map[key]; + for (const entry of map.values()) out.push(entry); - } } - for (let entry of out) { + const result = []; + for (const entry of out) { if (!empty && entry.amount === 0) continue; @@ -990,15 +953,12 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch }; RPC.prototype.listSinceBlock = async function listSinceBlock(args, help) { - let wallet = this.wallet; - let chainHeight = this.wdb.state.height; - let valid = new Validator([args]); - let block = valid.hash(0); - let minconf = valid.u32(1, 0); - let watchOnly = valid.bool(2, false); - let height = -1; - let out = []; - let txs, highest; + const wallet = this.wallet; + const chainHeight = this.wdb.state.height; + const valid = new Validator([args]); + const block = valid.hash(0); + const minconf = valid.u32(1, 0); + const watchOnly = valid.bool(2, false); if (help) { throw new RPCError(errs.MISC_ERROR, @@ -1006,10 +966,11 @@ RPC.prototype.listSinceBlock = async function listSinceBlock(args, help) { } if (wallet.watchOnly !== watchOnly) - return out; + return []; + let height = -1; if (block) { - let entry = await this.client.getEntry(block); + const entry = await this.client.getEntry(block); if (entry) height = entry.height; } @@ -1017,11 +978,11 @@ RPC.prototype.listSinceBlock = async function listSinceBlock(args, help) { if (height === -1) height = this.chain.height; - txs = await wallet.getHistory(); - - for (let wtx of txs) { - let json; + const txs = await wallet.getHistory(); + const out = []; + let highest; + for (const wtx of txs) { if (wtx.height < height) continue; @@ -1031,7 +992,7 @@ RPC.prototype.listSinceBlock = async function listSinceBlock(args, help) { if (!highest || wtx.height > highest) highest = wtx; - json = await this._toListTX(wtx); + const json = await this._toListTX(wtx); out.push(json); } @@ -1045,26 +1006,25 @@ RPC.prototype.listSinceBlock = async function listSinceBlock(args, help) { }; RPC.prototype._toListTX = async function _toListTX(wtx) { - let wallet = this.wallet; - let details = await wallet.toDetails(wtx); - let sent = 0; - let received = 0; - let receive = true; - let sendMember, recMember, sendIndex, recIndex; - let member, index; + const wallet = this.wallet; + const details = await wallet.toDetails(wtx); if (!details) throw new RPCError(errs.WALLET_ERROR, 'TX not found.'); - for (let member of details.inputs) { + let receive = true; + for (const member of details.inputs) { if (member.path) { receive = false; break; } } + let sent = 0; + let received = 0; + let sendMember, recMember, sendIndex, recIndex; for (let i = 0; i < details.outputs.length; i++) { - let member = details.outputs[i]; + const member = details.outputs[i]; if (member.path) { if (member.path.branch === 1) @@ -1080,6 +1040,7 @@ RPC.prototype._toListTX = async function _toListTX(wtx) { sendIndex = i; } + let member, index; if (receive) { member = recMember; index = recIndex; @@ -1107,46 +1068,45 @@ RPC.prototype._toListTX = async function _toListTX(wtx) { confirmations: details.getDepth(), blockhash: details.block ? util.revHex(details.block) : null, blockindex: details.index, - blocktime: details.ts, + blocktime: details.time, txid: util.revHex(details.hash), walletconflicts: [], - time: details.ps, - timereceived: details.ps, + time: details.mtime, + timereceived: details.mtime, 'bip125-replaceable': 'no' }; }; RPC.prototype.listTransactions = async function listTransactions(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0); - let count = valid.u32(1, 10); - let from = valid.u32(2, 0); - let watchOnly = valid.bool(3, false); - let end = from + count; - let out = []; - let txs; - if (help || args.length > 4) { throw new RPCError(errs.MISC_ERROR, 'listtransactions ( "account" count from includeWatchonly)'); } + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0); + const count = valid.u32(1, 10); + const from = valid.u32(2, 0); + const watchOnly = valid.bool(3, false); + if (wallet.watchOnly !== watchOnly) - return out; + return []; if (name === '') name = 'default'; - txs = await wallet.getHistory(); + const txs = await wallet.getHistory(); common.sortTX(txs); - end = Math.min(end, txs.length); + const end = from + count; + const to = Math.min(end, txs.length); + const out = []; - for (let i = from; i < end; i++) { - let wtx = txs[i]; - let json = await this._toListTX(wtx); + for (let i = from; i < to; i++) { + const wtx = txs[i]; + const json = await this._toListTX(wtx); out.push(json); } @@ -1154,58 +1114,58 @@ RPC.prototype.listTransactions = async function listTransactions(args, help) { }; RPC.prototype.listUnspent = async function listUnspent(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let minDepth = valid.u32(0, 1); - let maxDepth = valid.u32(1, 9999999); - let addrs = valid.array(2); - let height = this.wdb.state.height; - let out = []; - let map = {}; - let coins; - if (help || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'listunspent ( minconf maxconf ["address",...] )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + const minDepth = valid.u32(0, 1); + const maxDepth = valid.u32(1, 9999999); + const addrs = valid.array(2); + const height = this.wdb.state.height; + + const map = new Set(); + if (addrs) { - let valid = new Validator([addrs]); + const valid = new Validator([addrs]); for (let i = 0; i < addrs.length; i++) { - let addr = valid.str(i, ''); - let hash = parseHash(addr, this.network); + const addr = valid.str(i, ''); + const hash = parseHash(addr, this.network); - if (map[hash]) + if (map.has(hash)) throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address.'); - map[hash] = true; + map.add(hash); } } - coins = await wallet.getCoins(); + const coins = await wallet.getCoins(); common.sortCoins(coins); - for (let coin of coins) { - let depth = coin.getDepth(height); - let addr, hash, ring; + const out = []; - if (!(depth >= minDepth && depth <= maxDepth)) + for (const coin of coins) { + const depth = coin.getDepth(height); + + if (depth < minDepth || depth > maxDepth) continue; - addr = coin.getAddress(); + const addr = coin.getAddress(); if (!addr) continue; - hash = coin.getHash('hex'); + const hash = coin.getHash('hex'); if (addrs) { - if (!hash || !map[hash]) + if (!hash || !map.has(hash)) continue; } - ring = await wallet.getKey(hash); + const ring = await wallet.getKey(hash); out.push({ txid: coin.txid(), @@ -1227,16 +1187,16 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) { }; RPC.prototype.lockUnspent = async function lockUnspent(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let unlock = valid.bool(0, false); - let outputs = valid.array(1); - if (help || args.length < 1 || args.length > 2) { throw new RPCError(errs.MISC_ERROR, 'lockunspent unlock ([{"txid":"txid","vout":n},...])'); } + const wallet = this.wallet; + const valid = new Validator([args]); + const unlock = valid.bool(0, false); + const outputs = valid.array(1); + if (args.length === 1) { if (unlock) wallet.unlockCoins(); @@ -1246,18 +1206,15 @@ RPC.prototype.lockUnspent = async function lockUnspent(args, help) { if (!outputs) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - for (let output of outputs) { - let valid = new Validator([output]); - let hash = valid.hash('txid'); - let index = valid.u32('vout'); - let outpoint; + for (const output of outputs) { + const valid = new Validator([output]); + const hash = valid.hash('txid'); + const index = valid.u32('vout'); if (hash == null || index == null) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); - outpoint = new Outpoint(); - outpoint.hash = hash; - outpoint.index = index; + const outpoint = new Outpoint(hash, index); if (unlock) { wallet.unlockCoin(outpoint); @@ -1276,32 +1233,29 @@ RPC.prototype.move = async function move(args, help) { }; RPC.prototype.sendFrom = async function sendFrom(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0); - let addr = valid.str(1); - let value = valid.btc(2); - let minconf = valid.u32(3, 0); - let options, tx; - if (help || args.length < 3 || args.length > 6) { throw new RPCError(errs.MISC_ERROR, 'sendfrom "fromaccount" "tobitcoinaddress"' + ' amount ( minconf "comment" "comment-to" )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0); + const str = valid.str(1); + const value = valid.ufixed(2, 8); + const minconf = valid.u32(3, 0); + + const addr = parseAddress(str, this.network); + if (!addr || value == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - addr = parseAddress(addr, this.network); - if (name === '') name = 'default'; - options = { + const options = { account: name, - subtractFee: false, - rate: this.feeRate, depth: minconf, outputs: [{ address: addr, @@ -1309,98 +1263,93 @@ RPC.prototype.sendFrom = async function sendFrom(args, help) { }] }; - tx = await wallet.send(options); + const tx = await wallet.send(options); return tx.txid(); }; RPC.prototype.sendMany = async function sendMany(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let name = valid.str(0); - let sendTo = valid.obj(1); - let minconf = valid.u32(2, 1); - let subtractFee = valid.bool(4, false); - let outputs = []; - let uniq = {}; - let keys, options, tx; - if (help || args.length < 2 || args.length > 5) { throw new RPCError(errs.MISC_ERROR, 'sendmany "fromaccount" {"address":amount,...}' + ' ( minconf "comment" ["address",...] )'); } + const wallet = this.wallet; + const valid = new Validator([args]); + let name = valid.str(0); + const sendTo = valid.obj(1); + const minconf = valid.u32(2, 1); + const subtract = valid.bool(4, false); + if (name === '') name = 'default'; if (!sendTo) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - keys = Object.keys(sendTo); - valid = new Validator([sendTo]); + const to = new Validator([sendTo]); + const uniq = new Set(); + const outputs = []; - for (let key of keys) { - let value = valid.btc(key); - let addr = parseAddress(key, this.network); - let hash = addr.getHash('hex'); - let output; + for (const key of Object.keys(sendTo)) { + const value = to.ufixed(key, 8); + const addr = parseAddress(key, this.network); + const hash = addr.getHash('hex'); if (value == null) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); - if (uniq[hash]) + if (uniq.has(hash)) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); - uniq[hash] = true; + uniq.add(hash); - output = new Output(); + const output = new Output(); output.value = value; output.script.fromAddress(addr); outputs.push(output); } - options = { + const options = { outputs: outputs, - subtractFee: subtractFee, + subtractFee: subtract, account: name, depth: minconf }; - tx = await wallet.send(options); + const tx = await wallet.send(options); return tx.txid(); }; RPC.prototype.sendToAddress = async function sendToAddress(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let addr = valid.str(0); - let value = valid.btc(1); - let subtractFee = valid.bool(4, false); - let options, tx; - if (help || args.length < 2 || args.length > 5) { throw new RPCError(errs.MISC_ERROR, 'sendtoaddress "bitcoinaddress" amount' + ' ( "comment" "comment-to" subtractfeefromamount )'); } - addr = parseAddress(addr, this.network); + const wallet = this.wallet; + const valid = new Validator([args]); + const str = valid.str(0); + const value = valid.ufixed(1, 8); + const subtract = valid.bool(4, false); + + const addr = parseAddress(str, this.network); if (!addr || value == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - options = { - subtractFee: subtractFee, - rate: this.feeRate, + const options = { + subtractFee: subtract, outputs: [{ address: addr, value: value }] }; - tx = await wallet.send(options); + const tx = await wallet.send(options); return tx.txid(); }; @@ -1416,8 +1365,8 @@ RPC.prototype.setAccount = async function setAccount(args, help) { }; RPC.prototype.setTXFee = async function setTXFee(args, help) { - let valid = new Validator([args]); - let rate = valid.btc(0); + const valid = new Validator([args]); + const rate = valid.ufixed(0, 8); if (help || args.length < 1 || args.length > 1) throw new RPCError(errs.MISC_ERROR, 'settxfee amount'); @@ -1425,26 +1374,25 @@ RPC.prototype.setTXFee = async function setTXFee(args, help) { if (rate == null) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - this.feeRate = rate; + this.wdb.feeRate = rate; return true; }; RPC.prototype.signMessage = async function signMessage(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let addr = valid.str(0, ''); - let msg = valid.str(1, ''); - let sig, ring; - if (help || args.length !== 2) { throw new RPCError(errs.MISC_ERROR, 'signmessage "bitcoinaddress" "message"'); } - addr = parseHash(addr, this.network); + const wallet = this.wallet; + const valid = new Validator([args]); + const b58 = valid.str(0, ''); + const str = valid.str(1, ''); - ring = await wallet.getKey(addr); + const addr = parseHash(b58, this.network); + + const ring = await wallet.getKey(addr); if (!ring) throw new RPCError(errs.WALLET_ERROR, 'Address not found.'); @@ -1452,16 +1400,16 @@ RPC.prototype.signMessage = async function signMessage(args, help) { if (!wallet.master.key) throw new RPCError(errs.WALLET_UNLOCK_NEEDED, 'Wallet is locked.'); - msg = Buffer.from(MAGIC_STRING + msg, 'utf8'); - msg = digest.hash256(msg); + const msg = Buffer.from(MAGIC_STRING + str, 'utf8'); + const hash = digest.hash256(msg); - sig = ring.sign(msg); + const sig = ring.sign(hash); return sig.toString('base64'); }; RPC.prototype.walletLock = async function walletLock(args, help) { - let wallet = this.wallet; + const wallet = this.wallet; if (help || (wallet.master.encrypted && args.length !== 0)) throw new RPCError(errs.MISC_ERROR, 'walletlock'); @@ -1475,16 +1423,17 @@ RPC.prototype.walletLock = async function walletLock(args, help) { }; RPC.prototype.walletPassphraseChange = async function walletPassphraseChange(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let old = valid.str(0, ''); - let new_ = valid.str(1, ''); + const wallet = this.wallet; if (help || (wallet.master.encrypted && args.length !== 2)) { throw new RPCError(errs.MISC_ERROR, 'walletpassphrasechange' + ' "oldpassphrase" "newpassphrase"'); } + const valid = new Validator([args]); + const old = valid.str(0, ''); + const new_ = valid.str(1, ''); + if (!wallet.master.encrypted) throw new RPCError(errs.WALLET_WRONG_ENC_STATE, 'Wallet is not encrypted.'); @@ -1497,10 +1446,10 @@ RPC.prototype.walletPassphraseChange = async function walletPassphraseChange(arg }; RPC.prototype.walletPassphrase = async function walletPassphrase(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let passphrase = valid.str(0, ''); - let timeout = valid.u32(1); + const wallet = this.wallet; + const valid = new Validator([args]); + const passphrase = valid.str(0, ''); + const timeout = valid.u32(1); if (help || (wallet.master.encrypted && args.length !== 2)) { throw new RPCError(errs.MISC_ERROR, @@ -1522,22 +1471,21 @@ RPC.prototype.walletPassphrase = async function walletPassphrase(args, help) { }; RPC.prototype.importPrunedFunds = async function importPrunedFunds(args, help) { - let valid = new Validator([args]); - let tx = valid.buf(0); - let block = valid.buf(1); - let hash, height; - if (help || args.length < 2 || args.length > 3) { throw new RPCError(errs.MISC_ERROR, 'importprunedfunds "rawtransaction" "txoutproof" ( "label" )'); } - if (!tx || !block) + const valid = new Validator([args]); + const txRaw = valid.buf(0); + const blockRaw = valid.buf(1); + + if (!txRaw || !blockRaw) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - tx = TX.fromRaw(tx); - block = MerkleBlock.fromRaw(block); - hash = block.hash('hex'); + const tx = TX.fromRaw(txRaw); + const block = MerkleBlock.fromRaw(blockRaw); + const hash = block.hash('hex'); if (!block.verify()) throw new RPCError(errs.VERIFY_ERROR, 'Invalid proof.'); @@ -1545,49 +1493,48 @@ RPC.prototype.importPrunedFunds = async function importPrunedFunds(args, help) { if (!block.hasTX(tx.hash('hex'))) throw new RPCError(errs.VERIFY_ERROR, 'Invalid proof.'); - height = await this.client.getEntry(hash); + const height = await this.client.getEntry(hash); if (height === -1) throw new RPCError(errs.VERIFY_ERROR, 'Invalid proof.'); - block = { + const entry = { hash: hash, - ts: block.ts, + time: block.time, height: height }; - if (!(await this.wdb.addTX(tx, block))) + if (!await this.wdb.addTX(tx, entry)) throw new RPCError(errs.WALLET_ERROR, 'No tracked address for TX.'); return null; }; RPC.prototype.removePrunedFunds = async function removePrunedFunds(args, help) { - let wallet = this.wallet; - let valid = new Validator([args]); - let hash = valid.hash(0); - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'removeprunedfunds "txid"'); + const wallet = this.wallet; + const valid = new Validator([args]); + const hash = valid.hash(0); + if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); - if (!(await wallet.remove(hash))) + if (!await wallet.remove(hash)) throw new RPCError(errs.WALLET_ERROR, 'Transaction not in wallet.'); return null; }; RPC.prototype.selectWallet = async function selectWallet(args, help) { - let valid = new Validator([args]); - let id = valid.str(0); - let wallet; + const valid = new Validator([args]); + const id = valid.str(0); if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'selectwallet "id"'); - wallet = await this.wdb.get(id); + const wallet = await this.wdb.get(id); if (!wallet) throw new RPCError(errs.WALLET_ERROR, 'Wallet not found.'); @@ -1605,12 +1552,12 @@ RPC.prototype.getMemoryInfo = async function getMemoryInfo(args, help) { }; RPC.prototype.setLogLevel = async function setLogLevel(args, help) { - let valid = new Validator([args]); - let level = valid.str(0, ''); - if (help || args.length !== 1) throw new RPCError(errs.MISC_ERROR, 'setloglevel "level"'); + const valid = new Validator([args]); + const level = valid.str(0, ''); + this.logger.setLevel(level); return null; @@ -1621,7 +1568,7 @@ RPC.prototype.setLogLevel = async function setLogLevel(args, help) { */ function parseHash(raw, network) { - let addr = parseAddress(raw, network); + const addr = parseAddress(raw, network); return addr.getHash('hex'); } diff --git a/lib/wallet/server.js b/lib/wallet/server.js index b9cac845d..e1610db1b 100644 --- a/lib/wallet/server.js +++ b/lib/wallet/server.js @@ -25,9 +25,8 @@ const server = exports; */ server.create = function create(options) { - let config = new Config('bcoin'); + const config = new Config('bcoin'); let logger = new Logger('debug'); - let client, wdb, workers; config.inject(options); config.load(options); @@ -38,7 +37,7 @@ server.create = function create(options) { if (config.has('logger')) logger = config.obj('logger'); - client = new Client({ + const client = new Client({ network: config.network, uri: config.str('node-uri'), apiKey: config.str('node-api-key') @@ -53,52 +52,31 @@ server.create = function create(options) { shrink: config.bool('log-shrink') }); - workers = new WorkerPool({ + const workers = new WorkerPool({ enabled: config.str('workers-enabled'), - size: config.num('workers-size'), - timeout: config.num('workers-timeout') + size: config.uint('workers-size'), + timeout: config.uint('workers-timeout') }); - workers.on('spawn', (child) => { - logger.info('Spawning worker process: %d.', child.id); - }); - - workers.on('exit', (code, child) => { - logger.warning('Worker %d exited: %s.', child.id, code); - }); - - workers.on('log', (text, child) => { - logger.debug('Worker %d says:', child.id); - logger.debug(text); - }); - - workers.on('error', (err, child) => { - if (child) { - logger.error('Worker %d error: %s', child.id, err.message); - return; - } - wdb.emit('error', err); - }); - - wdb = new WalletDB({ + const wdb = new WalletDB({ network: config.network, logger: logger, workers: workers, client: client, prefix: config.prefix, db: config.str('db'), - maxFiles: config.num('max-files'), + maxFiles: config.uint('max-files'), cacheSize: config.mb('cache-size'), witness: config.bool('witness'), checkpoints: config.bool('checkpoints'), - startHeight: config.num('start-height'), + startHeight: config.uint('start-height'), wipeNoReally: config.bool('wipe-no-really'), apiKey: config.str('api-key'), walletAuth: config.bool('auth'), noAuth: config.bool('no-auth'), ssl: config.str('ssl'), host: config.str('host'), - port: config.num('port'), + port: config.uint('port'), spv: config.bool('spv'), verify: config.bool('spv'), listen: true @@ -106,5 +84,26 @@ server.create = function create(options) { wdb.on('error', () => {}); + workers.on('spawn', (child) => { + logger.info('Spawning worker process: %d.', child.id); + }); + + workers.on('exit', (code, child) => { + logger.warning('Worker %d exited: %s.', child.id, code); + }); + + workers.on('log', (text, child) => { + logger.debug('Worker %d says:', child.id); + logger.debug(text); + }); + + workers.on('error', (err, child) => { + if (child) { + logger.error('Worker %d error: %s', child.id, err.message); + return; + } + wdb.emit('error', err); + }); + return wdb; }; diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index 8b15fbde8..b7367af53 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -63,7 +63,7 @@ TXDB.layout = layout; */ TXDB.prototype.open = async function open() { - let state = await this.getState(); + const state = await this.getState(); if (state) { this.state = state; @@ -139,7 +139,7 @@ TXDB.prototype.commit = async function commit() { // Emit buffered events now that // we know everything is written. - for (let [event, data, details] of this.events) { + for (const [event, data, details] of this.events) { this.walletdb.emit(event, this.wallet.id, data, details); this.wallet.emit(event, data, details); } @@ -221,8 +221,10 @@ TXDB.prototype.has = function has(key) { TXDB.prototype.range = function range(options) { if (options.gte) options.gte = this.prefix(options.gte); + if (options.lte) options.lte = this.prefix(options.lte); + return this.db.range(options); }; @@ -235,8 +237,10 @@ TXDB.prototype.range = function range(options) { TXDB.prototype.keys = function keys(options) { if (options.gte) options.gte = this.prefix(options.gte); + if (options.lte) options.lte = this.prefix(options.lte); + return this.db.keys(options); }; @@ -249,8 +253,10 @@ TXDB.prototype.keys = function keys(options) { TXDB.prototype.values = function values(options) { if (options.gte) options.gte = this.prefix(options.gte); + if (options.lte) options.lte = this.prefix(options.lte); + return this.db.values(options); }; @@ -260,13 +266,13 @@ TXDB.prototype.values = function values(options) { * @returns {Promise} - Returns {@link Path}. */ -TXDB.prototype.getPath = function getPath(output) { - let addr = output.getAddress(); +TXDB.prototype.getPath = async function getPath(output) { + const addr = output.getAddress(); if (!addr) - return Promise.resolve(); + return null; - return this.wallet.getPath(addr); + return await this.wallet.getPath(addr); }; /** @@ -275,13 +281,13 @@ TXDB.prototype.getPath = function getPath(output) { * @returns {Promise} - Returns Boolean. */ -TXDB.prototype.hasPath = function hasPath(output) { - let addr = output.getAddress(); +TXDB.prototype.hasPath = async function hasPath(output) { + const addr = output.getAddress(); if (!addr) - return Promise.resolve(false); + return false; - return this.wallet.hasPath(addr); + return await this.wallet.hasPath(addr); }; /** @@ -291,9 +297,9 @@ TXDB.prototype.hasPath = function hasPath(output) { */ TXDB.prototype.saveCredit = async function saveCredit(credit, path) { - let coin = credit.coin; - let key = coin.toKey(); - let raw = credit.toRaw(); + const coin = credit.coin; + const key = coin.toKey(); + const raw = credit.toRaw(); await this.addOutpointMap(coin.hash, coin.index); @@ -310,8 +316,8 @@ TXDB.prototype.saveCredit = async function saveCredit(credit, path) { */ TXDB.prototype.removeCredit = async function removeCredit(credit, path) { - let coin = credit.coin; - let key = coin.toKey(); + const coin = credit.coin; + const key = coin.toKey(); await this.removeOutpointMap(coin.hash, coin.index); @@ -329,8 +335,8 @@ TXDB.prototype.removeCredit = async function removeCredit(credit, path) { */ TXDB.prototype.spendCredit = function spendCredit(credit, tx, index) { - let prevout = tx.inputs[index].prevout; - let spender = Outpoint.fromTX(tx, index); + const prevout = tx.inputs[index].prevout; + const spender = Outpoint.fromTX(tx, index); this.put(layout.s(prevout.hash, prevout.index), spender.toRaw()); this.put(layout.d(spender.hash, spender.index), credit.coin.toRaw()); }; @@ -342,8 +348,8 @@ TXDB.prototype.spendCredit = function spendCredit(credit, tx, index) { */ TXDB.prototype.unspendCredit = function unspendCredit(tx, index) { - let prevout = tx.inputs[index].prevout; - let spender = Outpoint.fromTX(tx, index); + const prevout = tx.inputs[index].prevout; + const spender = Outpoint.fromTX(tx, index); this.del(layout.s(prevout.hash, prevout.index)); this.del(layout.d(spender.hash, spender.index)); }; @@ -355,8 +361,8 @@ TXDB.prototype.unspendCredit = function unspendCredit(tx, index) { */ TXDB.prototype.writeInput = function writeInput(tx, index) { - let prevout = tx.inputs[index].prevout; - let spender = Outpoint.fromTX(tx, index); + const prevout = tx.inputs[index].prevout; + const spender = Outpoint.fromTX(tx, index); this.put(layout.s(prevout.hash, prevout.index), spender.toRaw()); }; @@ -367,7 +373,7 @@ TXDB.prototype.writeInput = function writeInput(tx, index) { */ TXDB.prototype.removeInput = function removeInput(tx, index) { - let prevout = tx.inputs[index].prevout; + const prevout = tx.inputs[index].prevout; this.del(layout.s(prevout.hash, prevout.index)); }; @@ -381,9 +387,8 @@ TXDB.prototype.removeInput = function removeInput(tx, index) { */ TXDB.prototype.resolveInput = async function resolveInput(tx, index, height, path, own) { - let hash = tx.hash('hex'); - let spent = await this.getSpent(hash, index); - let stx, credit; + const hash = tx.hash('hex'); + const spent = await this.getSpent(hash, index); if (!spent) return false; @@ -395,11 +400,11 @@ TXDB.prototype.resolveInput = async function resolveInput(tx, index, height, pat // Get the spending transaction so // we can properly add the undo coin. - stx = await this.getTX(spent.hash); + const stx = await this.getTX(spent.hash); assert(stx); // Crete the credit and add the undo coin. - credit = Credit.fromTX(tx, index, height); + const credit = Credit.fromTX(tx, index, height); credit.own = own; this.spendCredit(credit, stx.tx, spent.index); @@ -428,9 +433,8 @@ TXDB.prototype.resolveInput = async function resolveInput(tx, index, height, pat */ TXDB.prototype.isDoubleSpend = async function isDoubleSpend(tx) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let spent = await this.isSpent(prevout.hash, prevout.index); + for (const {prevout} of tx.inputs) { + const spent = await this.isSpent(prevout.hash, prevout.index); if (spent) return true; } @@ -449,9 +453,9 @@ TXDB.prototype.isRBF = async function isRBF(tx) { if (tx.isRBF()) return true; - for (let input of tx.inputs) { - let prevout = input.prevout; - if (await this.has(layout.r(prevout.hash))) + for (const {prevout} of tx.inputs) { + const key = layout.r(prevout.hash); + if (await this.has(key)) return true; } @@ -466,10 +470,10 @@ TXDB.prototype.isRBF = async function isRBF(tx) { */ TXDB.prototype.getSpent = async function getSpent(hash, index) { - let data = await this.get(layout.s(hash, index)); + const data = await this.get(layout.s(hash, index)); if (!data) - return; + return null; return Outpoint.fromRaw(data); }; @@ -512,7 +516,7 @@ TXDB.prototype.addOutpointMap = async function addOutpointMap(hash, i) { */ TXDB.prototype.removeOutpointMap = async function removeOutpointMap(hash, i) { - let map = await this.walletdb.getOutpointMap(hash, i); + const map = await this.walletdb.getOutpointMap(hash, i); if (!map) return; @@ -520,7 +524,7 @@ TXDB.prototype.removeOutpointMap = async function removeOutpointMap(hash, i) { if (!map.remove(this.wallet.wid)) return; - if (map.wids.length === 0) { + if (map.wids.size === 0) { this.walletdb.unwriteOutpointMap(this.wallet, hash, i); return; } @@ -555,7 +559,7 @@ TXDB.prototype.addBlockMap = async function addBlockMap(hash, height) { */ TXDB.prototype.removeBlockMap = async function removeBlockMap(hash, height) { - let block = await this.walletdb.getBlockMap(height); + const block = await this.walletdb.getBlockMap(height); if (!block) return; @@ -563,7 +567,7 @@ TXDB.prototype.removeBlockMap = async function removeBlockMap(hash, height) { if (!block.remove(hash, this.wallet.wid)) return; - if (block.txs.length === 0) { + if (block.txs.size === 0) { this.walletdb.unwriteBlockMap(this.wallet, height); return; } @@ -591,10 +595,10 @@ TXDB.prototype.getBlocks = function getBlocks() { */ TXDB.prototype.getBlock = async function getBlock(height) { - let data = await this.get(layout.b(height)); + const data = await this.get(layout.b(height)); if (!data) - return; + return null; return BlockRecord.fromRaw(data); }; @@ -607,9 +611,9 @@ TXDB.prototype.getBlock = async function getBlock(height) { */ TXDB.prototype.addBlock = async function addBlock(hash, meta) { - let key = layout.b(meta.height); + const key = layout.b(meta.height); let data = await this.get(key); - let block, size; + let block; if (!data) { block = BlockRecord.fromMeta(meta); @@ -619,7 +623,7 @@ TXDB.prototype.addBlock = async function addBlock(hash, meta) { block = Buffer.allocUnsafe(data.length + 32); data.copy(block, 0); - size = block.readUInt32LE(40, true); + const size = block.readUInt32LE(40, true); block.writeUInt32LE(size + 1, 40, true); hash.copy(block, data.length); @@ -634,14 +638,13 @@ TXDB.prototype.addBlock = async function addBlock(hash, meta) { */ TXDB.prototype.removeBlock = async function removeBlock(hash, height) { - let key = layout.b(height); - let data = await this.get(key); - let block, size; + const key = layout.b(height); + const data = await this.get(key); if (!data) return; - size = data.readUInt32LE(40, true); + const size = data.readUInt32LE(40, true); assert(size > 0); assert(data.slice(-32).equals(hash)); @@ -651,7 +654,7 @@ TXDB.prototype.removeBlock = async function removeBlock(hash, height) { return; } - block = data.slice(0, -32); + const block = data.slice(0, -32); block.writeUInt32LE(size - 1, 40, true); this.put(key, block); @@ -684,7 +687,7 @@ TXDB.prototype.addBlockSlow = async function addBlockSlow(hash, meta) { */ TXDB.prototype.removeBlockSlow = async function removeBlockSlow(hash, height) { - let block = await this.getBlock(height); + const block = await this.getBlock(height); if (!block) return; @@ -709,10 +712,9 @@ TXDB.prototype.removeBlockSlow = async function removeBlockSlow(hash, height) { */ TXDB.prototype.add = async function add(tx, block) { - let result; - this.start(); + let result; try { result = await this._add(tx, block); } catch (e) { @@ -732,28 +734,27 @@ TXDB.prototype.add = async function add(tx, block) { * @returns {Promise} */ -TXDB.prototype._add = async function add(tx, block) { - let hash = tx.hash('hex'); - let existing = await this.getTX(hash); - let wtx; +TXDB.prototype._add = async function _add(tx, block) { + const hash = tx.hash('hex'); + const existing = await this.getTX(hash); assert(!tx.mutable, 'Cannot add mutable TX to wallet.'); if (existing) { // Existing tx is already confirmed. Ignore. if (existing.height !== -1) - return; + return null; // The incoming tx won't confirm the // existing one anyway. Ignore. if (!block) - return; + return null; // Confirm transaction. return await this._confirm(existing, block); } - wtx = TXRecord.fromTX(tx, block); + const wtx = TXRecord.fromTX(tx, block); if (!block) { // We ignore any unconfirmed txs @@ -763,13 +764,13 @@ TXDB.prototype._add = async function add(tx, block) { // hash to detect "passive" // replace-by-fee. this.put(layout.r(hash), null); - return; + return null; } // Potentially remove double-spenders. // Only remove if they're not confirmed. - if (!(await this.removeConflicts(tx, true))) - return; + if (!await this.removeConflicts(tx, true)) + return null; } else { // Potentially remove double-spenders. await this.removeConflicts(tx, false); @@ -791,20 +792,20 @@ TXDB.prototype._add = async function add(tx, block) { */ TXDB.prototype.insert = async function insert(wtx, block) { - let tx = wtx.tx; - let hash = wtx.hash; - let height = block ? block.height : -1; - let details = new Details(this, wtx, block); + const tx = wtx.tx; + const hash = wtx.hash; + const height = block ? block.height : -1; + const details = new Details(this, wtx, block); + const accounts = new Set(); let own = false; let updated = false; if (!tx.isCoinbase()) { // We need to potentially spend some coins here. for (let i = 0; i < tx.inputs.length; i++) { - let input = tx.inputs[i]; - let prevout = input.prevout; - let credit = await this.getCredit(prevout.hash, prevout.index); - let coin, path; + const input = tx.inputs[i]; + const prevout = input.prevout; + const credit = await this.getCredit(prevout.hash, prevout.index); if (!credit) { // Maintain an stxo list for every @@ -822,22 +823,23 @@ TXDB.prototype.insert = async function insert(wtx, block) { continue; } - coin = credit.coin; + const coin = credit.coin; // Do some verification. if (!block) { - if (!(await this.verifyInput(tx, i, coin))) { + if (!await this.verifyInput(tx, i, coin)) { this.clear(); - return; + return null; } } - path = await this.getPath(coin); + const path = await this.getPath(coin); assert(path); // Build the tx details object // as we go, for speed. details.setInput(i, path, coin); + accounts.add(path.account); // Write an undo coin for the credit // and add it to the stxo set. @@ -878,14 +880,14 @@ TXDB.prototype.insert = async function insert(wtx, block) { // Potentially add coins to the utxo set. for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let path = await this.getPath(output); - let credit; + const output = tx.outputs[i]; + const path = await this.getPath(output); if (!path) continue; details.setOutput(i, path); + accounts.add(path.account); // Attempt to resolve an input we // did not know was ours at the time. @@ -894,7 +896,7 @@ TXDB.prototype.insert = async function insert(wtx, block) { continue; } - credit = Credit.fromTX(tx, i, height); + const credit = Credit.fromTX(tx, i, height); credit.own = own; this.pending.coin++; @@ -913,12 +915,12 @@ TXDB.prototype.insert = async function insert(wtx, block) { if (!updated) { // Clear the spent list inserts. this.clear(); - return; + return null; } // Save and index the transaction record. this.put(layout.t(hash), wtx.toRaw()); - this.put(layout.m(wtx.ps, hash), null); + this.put(layout.m(wtx.mtime, hash), null); if (!block) this.put(layout.p(hash), null); @@ -928,9 +930,9 @@ TXDB.prototype.insert = async function insert(wtx, block) { // Do some secondary indexing for account-based // queries. This saves us a lot of time for // queries later. - for (let account of details.accounts) { + for (const account of accounts) { this.put(layout.T(account, hash), null); - this.put(layout.M(account, wtx.ps, hash), null); + this.put(layout.M(account, wtx.mtime, hash), null); if (!block) this.put(layout.P(account, hash), null); @@ -975,11 +977,10 @@ TXDB.prototype.insert = async function insert(wtx, block) { */ TXDB.prototype.confirm = async function confirm(hash, block) { - let wtx = await this.getTX(hash); - let details; + const wtx = await this.getTX(hash); if (!wtx) - return; + return null; if (wtx.height !== -1) throw new Error('TX is already confirmed.'); @@ -988,6 +989,8 @@ TXDB.prototype.confirm = async function confirm(hash, block) { this.start(); + let details; + try { details = await this._confirm(wtx, block); } catch (e) { @@ -1008,25 +1011,25 @@ TXDB.prototype.confirm = async function confirm(hash, block) { * @returns {Promise} */ -TXDB.prototype._confirm = async function confirm(wtx, block) { - let tx = wtx.tx; - let hash = wtx.hash; - let height = block.height; - let details = new Details(this, wtx, block); +TXDB.prototype._confirm = async function _confirm(wtx, block) { + const tx = wtx.tx; + const hash = wtx.hash; + const height = block.height; + const details = new Details(this, wtx, block); + const accounts = new Set(); wtx.setBlock(block); if (!tx.isCoinbase()) { - let credits = await this.getSpentCredits(tx); + const credits = await this.getSpentCredits(tx); // Potentially spend coins. Now that the tx // is mined, we can actually _remove_ coins // from the utxo state. for (let i = 0; i < tx.inputs.length; i++) { - let input = tx.inputs[i]; - let prevout = input.prevout; + const input = tx.inputs[i]; + const prevout = input.prevout; let credit = credits[i]; - let coin, path; // There may be new credits available // that we haven't seen yet. @@ -1047,14 +1050,15 @@ TXDB.prototype._confirm = async function confirm(wtx, block) { this.pending.unconfirmed -= credit.coin.value; } - coin = credit.coin; + const coin = credit.coin; assert(coin.height !== -1); - path = await this.getPath(coin); + const path = await this.getPath(coin); assert(path); details.setInput(i, path, coin); + accounts.add(path.account); // We can now safely remove the credit // entirely, now that we know it's also @@ -1067,16 +1071,16 @@ TXDB.prototype._confirm = async function confirm(wtx, block) { // Update credit heights, including undo coins. for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let path = await this.getPath(output); - let credit, coin; + const output = tx.outputs[i]; + const path = await this.getPath(output); if (!path) continue; details.setOutput(i, path); + accounts.add(path.account); - credit = await this.getCredit(hash, i); + const credit = await this.getCredit(hash, i); assert(credit); // Credits spent in the mempool add an @@ -1088,7 +1092,7 @@ TXDB.prototype._confirm = async function confirm(wtx, block) { // Update coin height and confirmed // balance. Save once again. - coin = credit.coin; + const coin = credit.coin; coin.height = height; this.pending.confirmed += output.value; @@ -1107,7 +1111,7 @@ TXDB.prototype._confirm = async function confirm(wtx, block) { this.put(layout.h(height, hash), null); // Secondary indexing also needs to change. - for (let account of details.accounts) { + for (const account of accounts) { this.del(layout.P(account, hash)); this.put(layout.H(account, height, hash), null); } @@ -1136,10 +1140,10 @@ TXDB.prototype._confirm = async function confirm(wtx, block) { */ TXDB.prototype.remove = async function remove(hash) { - let wtx = await this.getTX(hash); + const wtx = await this.getTX(hash); if (!wtx) - return; + return null; return await this.removeRecursive(wtx); }; @@ -1153,20 +1157,20 @@ TXDB.prototype.remove = async function remove(hash) { */ TXDB.prototype.erase = async function erase(wtx, block) { - let tx = wtx.tx; - let hash = wtx.hash; - let height = block ? block.height : -1; - let details = new Details(this, wtx, block); + const tx = wtx.tx; + const hash = wtx.hash; + const height = block ? block.height : -1; + const details = new Details(this, wtx, block); + const accounts = new Set(); if (!tx.isCoinbase()) { // We need to undo every part of the // state this transaction ever touched. // Start by getting the undo coins. - let credits = await this.getSpentCredits(tx); + const credits = await this.getSpentCredits(tx); for (let i = 0; i < tx.inputs.length; i++) { - let credit = credits[i]; - let coin, path; + const credit = credits[i]; if (!credit) { // This input never had an undo @@ -1176,11 +1180,12 @@ TXDB.prototype.erase = async function erase(wtx, block) { continue; } - coin = credit.coin; - path = await this.getPath(coin); + const coin = credit.coin; + const path = await this.getPath(coin); assert(path); details.setInput(i, path, coin); + accounts.add(path.account); // Recalculate the balance, remove // from stxo set, remove the undo @@ -1199,16 +1204,16 @@ TXDB.prototype.erase = async function erase(wtx, block) { // We need to remove all credits // this transaction created. for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let path = await this.getPath(output); - let credit; + const output = tx.outputs[i]; + const path = await this.getPath(output); if (!path) continue; details.setOutput(i, path); + accounts.add(path.account); - credit = Credit.fromTX(tx, i, height); + const credit = Credit.fromTX(tx, i, height); this.pending.coin--; this.pending.unconfirmed -= output.value; @@ -1225,7 +1230,7 @@ TXDB.prototype.erase = async function erase(wtx, block) { // Remove the transaction data // itself as well as unindex. this.del(layout.t(hash)); - this.del(layout.m(wtx.ps, hash)); + this.del(layout.m(wtx.mtime, hash)); if (!block) this.del(layout.p(hash)); @@ -1233,9 +1238,9 @@ TXDB.prototype.erase = async function erase(wtx, block) { this.del(layout.h(height, hash)); // Remove all secondary indexing. - for (let account of details.accounts) { + for (const account of accounts) { this.del(layout.T(account, hash)); - this.del(layout.M(account, wtx.ps, hash)); + this.del(layout.M(account, wtx.mtime, hash)); if (!block) this.del(layout.P(account, hash)); @@ -1270,19 +1275,17 @@ TXDB.prototype.erase = async function erase(wtx, block) { */ TXDB.prototype.removeRecursive = async function removeRecursive(wtx) { - let tx = wtx.tx; - let hash = wtx.hash; - let details; + const tx = wtx.tx; + const hash = wtx.hash; for (let i = 0; i < tx.outputs.length; i++) { - let spent = await this.getSpent(hash, i); - let stx; + const spent = await this.getSpent(hash, i); if (!spent) continue; // Remove all of the spender's spenders first. - stx = await this.getTX(spent.hash); + const stx = await this.getTX(spent.hash); assert(stx); @@ -1292,7 +1295,7 @@ TXDB.prototype.removeRecursive = async function removeRecursive(wtx) { this.start(); // Remove the spender. - details = await this.erase(wtx, wtx.getBlock()); + const details = await this.erase(wtx, wtx.getBlock()); assert(details); @@ -1308,10 +1311,9 @@ TXDB.prototype.removeRecursive = async function removeRecursive(wtx) { */ TXDB.prototype.unconfirm = async function unconfirm(hash) { - let details; - this.start(); + let details; try { details = await this._unconfirm(hash); } catch (e) { @@ -1331,14 +1333,14 @@ TXDB.prototype.unconfirm = async function unconfirm(hash) { * @returns {Promise} */ -TXDB.prototype._unconfirm = async function unconfirm(hash) { - let wtx = await this.getTX(hash); +TXDB.prototype._unconfirm = async function _unconfirm(hash) { + const wtx = await this.getTX(hash); if (!wtx) - return; + return null; if (wtx.height === -1) - return; + return null; return await this.disconnect(wtx, wtx.getBlock()); }; @@ -1350,10 +1352,11 @@ TXDB.prototype._unconfirm = async function unconfirm(hash) { */ TXDB.prototype.disconnect = async function disconnect(wtx, block) { - let tx = wtx.tx; - let hash = wtx.hash; - let height = block.height; - let details = new Details(this, wtx, block); + const tx = wtx.tx; + const hash = wtx.hash; + const height = block.height; + const details = new Details(this, wtx, block); + const accounts = new Set(); assert(block); @@ -1363,23 +1366,23 @@ TXDB.prototype.disconnect = async function disconnect(wtx, block) { // We need to reconnect the coins. Start // by getting all of the undo coins we know // about. - let credits = await this.getSpentCredits(tx); + const credits = await this.getSpentCredits(tx); for (let i = 0; i < tx.inputs.length; i++) { - let credit = credits[i]; - let path, coin; + const credit = credits[i]; if (!credit) continue; - coin = credit.coin; + const coin = credit.coin; assert(coin.height !== -1); - path = await this.getPath(coin); + const path = await this.getPath(coin); assert(path); details.setInput(i, path, coin); + accounts.add(path.account); this.pending.confirmed += coin.value; @@ -1393,14 +1396,13 @@ TXDB.prototype.disconnect = async function disconnect(wtx, block) { // We need to remove heights on // the credits and undo coins. for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let path = await this.getPath(output); - let credit, coin; + const output = tx.outputs[i]; + const path = await this.getPath(output); if (!path) continue; - credit = await this.getCredit(hash, i); + const credit = await this.getCredit(hash, i); // Potentially update undo coin height. if (!credit) { @@ -1412,10 +1414,11 @@ TXDB.prototype.disconnect = async function disconnect(wtx, block) { await this.updateSpentCoin(tx, i, height); details.setOutput(i, path); + accounts.add(path.account); // Update coin height and confirmed // balance. Save once again. - coin = credit.coin; + const coin = credit.coin; coin.height = -1; this.pending.confirmed -= output.value; @@ -1434,7 +1437,7 @@ TXDB.prototype.disconnect = async function disconnect(wtx, block) { this.del(layout.h(height, hash)); // Secondary indexing also needs to change. - for (let account of details.accounts) { + for (const account of accounts) { this.put(layout.P(account, hash), null); this.del(layout.H(account, height, hash)); } @@ -1462,14 +1465,13 @@ TXDB.prototype.disconnect = async function disconnect(wtx, block) { */ TXDB.prototype.removeConflict = async function removeConflict(wtx) { - let tx = wtx.tx; - let details; + const tx = wtx.tx; this.logger.warning('Handling conflicting tx: %s.', tx.txid()); this.drop(); - details = await this.removeRecursive(wtx); + const details = await this.removeRecursive(wtx); this.start(); @@ -1490,20 +1492,19 @@ TXDB.prototype.removeConflict = async function removeConflict(wtx) { */ TXDB.prototype.removeConflicts = async function removeConflicts(tx, conf) { - let hash = tx.hash('hex'); - let spends = []; + const hash = tx.hash('hex'); + const spends = []; if (tx.isCoinbase()) return true; // Gather all spent records first. for (let i = 0; i < tx.inputs.length; i++) { - let input = tx.inputs[i]; - let prevout = input.prevout; - let spent, spender, block; + const input = tx.inputs[i]; + const prevout = input.prevout; // Is it already spent? - spent = await this.getSpent(prevout.hash, prevout.index); + const spent = await this.getSpent(prevout.hash, prevout.index); if (!spent) continue; @@ -1512,9 +1513,10 @@ TXDB.prototype.removeConflicts = async function removeConflicts(tx, conf) { if (spent.hash === hash) continue; - spender = await this.getTX(spent.hash); + const spender = await this.getTX(spent.hash); assert(spender); - block = spender.getBlock(); + + const block = spender.getBlock(); if (conf && block) return false; @@ -1525,7 +1527,7 @@ TXDB.prototype.removeConflicts = async function removeConflicts(tx, conf) { // Once we know we're not going to // screw things up, remove the double // spenders. - for (let spender of spends) { + for (const spender of spends) { if (!spender) continue; @@ -1546,9 +1548,11 @@ TXDB.prototype.removeConflicts = async function removeConflicts(tx, conf) { */ TXDB.prototype.verifyInput = async function verifyInput(tx, index, coin) { - let flags = Script.flags.MANDATORY_VERIFY_FLAGS; + const flags = Script.flags.MANDATORY_VERIFY_FLAGS; + if (!this.options.verify) return true; + return await tx.verifyInputAsync(index, coin, flags); }; @@ -1561,7 +1565,7 @@ TXDB.prototype.lockTX = function lockTX(tx) { if (tx.isCoinbase()) return; - for (let input of tx.inputs) + for (const input of tx.inputs) this.lockCoin(input.prevout); }; @@ -1574,7 +1578,7 @@ TXDB.prototype.unlockTX = function unlockTX(tx) { if (tx.isCoinbase()) return; - for (let input of tx.inputs) + for (const input of tx.inputs) this.unlockCoin(input.prevout); }; @@ -1584,7 +1588,7 @@ TXDB.prototype.unlockTX = function unlockTX(tx) { */ TXDB.prototype.lockCoin = function lockCoin(coin) { - let key = coin.toKey(); + const key = coin.toKey(); this.locked.add(key); }; @@ -1594,7 +1598,7 @@ TXDB.prototype.lockCoin = function lockCoin(coin) { */ TXDB.prototype.unlockCoin = function unlockCoin(coin) { - let key = coin.toKey(); + const key = coin.toKey(); return this.locked.delete(key); }; @@ -1604,7 +1608,7 @@ TXDB.prototype.unlockCoin = function unlockCoin(coin) { */ TXDB.prototype.isLocked = function isLocked(coin) { - let key = coin.toKey(); + const key = coin.toKey(); return this.locked.has(key); }; @@ -1616,9 +1620,9 @@ TXDB.prototype.isLocked = function isLocked(coin) { */ TXDB.prototype.filterLocked = function filterLocked(coins) { - let out = []; + const out = []; - for (let coin of coins) { + for (const coin of coins) { if (!this.isLocked(coin)) out.push(coin); } @@ -1632,9 +1636,9 @@ TXDB.prototype.filterLocked = function filterLocked(coins) { */ TXDB.prototype.getLocked = function getLocked() { - let outpoints = []; + const outpoints = []; - for (let key of this.locked.keys()) + for (const key of this.locked.keys()) outpoints.push(Outpoint.fromKey(key)); return outpoints; @@ -1646,12 +1650,12 @@ TXDB.prototype.getLocked = function getLocked() { * @returns {Promise} - Returns {@link Hash}[]. */ -TXDB.prototype.getAccountHistoryHashes = function getHistoryHashes(account) { +TXDB.prototype.getAccountHistoryHashes = function getAccountHistoryHashes(account) { return this.keys({ gte: layout.T(account, encoding.NULL_HASH), lte: layout.T(account, encoding.HIGH_HASH), parse: (key) => { - let [, hash] = layout.Tt(key); + const [, hash] = layout.Tt(key); return hash; } }); @@ -1685,7 +1689,7 @@ TXDB.prototype.getAccountPendingHashes = function getAccountPendingHashes(accoun gte: layout.P(account, encoding.NULL_HASH), lte: layout.P(account, encoding.HIGH_HASH), parse: (key) => { - let [, hash] = layout.Pp(key); + const [, hash] = layout.Pp(key); return hash; } }); @@ -1719,7 +1723,7 @@ TXDB.prototype.getAccountOutpoints = function getAccountOutpoints(account) { gte: layout.C(account, encoding.NULL_HASH, 0), lte: layout.C(account, encoding.HIGH_HASH, 0xffffffff), parse: (key) => { - let [, hash, index] = layout.Cc(key); + const [, hash, index] = layout.Cc(key); return new Outpoint(hash, index); } }); @@ -1739,7 +1743,7 @@ TXDB.prototype.getOutpoints = function getOutpoints(account) { gte: layout.c(encoding.NULL_HASH, 0), lte: layout.c(encoding.HIGH_HASH, 0xffffffff), parse: (key) => { - let [hash, index] = layout.cc(key); + const [hash, index] = layout.cc(key); return new Outpoint(hash, index); } }); @@ -1757,8 +1761,8 @@ TXDB.prototype.getOutpoints = function getOutpoints(account) { */ TXDB.prototype.getAccountHeightRangeHashes = function getAccountHeightRangeHashes(account, options) { - let start = options.start || 0; - let end = options.end || 0xffffffff; + const start = options.start || 0; + const end = options.end || 0xffffffff; return this.keys({ gte: layout.H(account, start, encoding.NULL_HASH), @@ -1766,7 +1770,7 @@ TXDB.prototype.getAccountHeightRangeHashes = function getAccountHeightRangeHashe limit: options.limit, reverse: options.reverse, parse: (key) => { - let [,, hash] = layout.Hh(key); + const [,, hash] = layout.Hh(key); return hash; } }); @@ -1784,8 +1788,6 @@ TXDB.prototype.getAccountHeightRangeHashes = function getAccountHeightRangeHashe */ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, options) { - let start, end; - if (account && typeof account === 'object') { options = account; account = null; @@ -1794,8 +1796,8 @@ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, opt if (account != null) return this.getAccountHeightRangeHashes(account, options); - start = options.start || 0; - end = options.end || 0xffffffff; + const start = options.start || 0; + const end = options.end || 0xffffffff; return this.keys({ gte: layout.h(start, encoding.NULL_HASH), @@ -1803,7 +1805,7 @@ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, opt limit: options.limit, reverse: options.reverse, parse: (key) => { - let [, hash] = layout.hh(key); + const [, hash] = layout.hh(key); return hash; } }); @@ -1831,8 +1833,8 @@ TXDB.prototype.getHeightHashes = function getHeightHashes(height) { */ TXDB.prototype.getAccountRangeHashes = function getAccountRangeHashes(account, options) { - let start = options.start || 0; - let end = options.end || 0xffffffff; + const start = options.start || 0; + const end = options.end || 0xffffffff; return this.keys({ gte: layout.M(account, start, encoding.NULL_HASH), @@ -1840,7 +1842,7 @@ TXDB.prototype.getAccountRangeHashes = function getAccountRangeHashes(account, o limit: options.limit, reverse: options.reverse, parse: (key) => { - let [,, hash] = layout.Mm(key); + const [,, hash] = layout.Mm(key); return hash; } }); @@ -1858,8 +1860,6 @@ TXDB.prototype.getAccountRangeHashes = function getAccountRangeHashes(account, o */ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options) { - let start, end; - if (account && typeof account === 'object') { options = account; account = null; @@ -1868,8 +1868,8 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options) { if (account != null) return this.getAccountRangeHashes(account, options); - start = options.start || 0; - end = options.end || 0xffffffff; + const start = options.start || 0; + const end = options.end || 0xffffffff; return this.keys({ gte: layout.m(start, encoding.NULL_HASH), @@ -1877,7 +1877,7 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options) { limit: options.limit, reverse: options.reverse, parse: (key) => { - let [, hash] = layout.mm(key); + const [, hash] = layout.mm(key); return hash; } }); @@ -1895,18 +1895,17 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options) { */ TXDB.prototype.getRange = async function getRange(account, options) { - let txs = []; - let hashes; + const txs = []; if (account && typeof account === 'object') { options = account; account = null; } - hashes = await this.getRangeHashes(account, options); + const hashes = await this.getRangeHashes(account, options); - for (let hash of hashes) { - let tx = await this.getTX(hash); + for (const hash of hashes) { + const tx = await this.getTX(hash); assert(tx); txs.push(tx); } @@ -1956,11 +1955,11 @@ TXDB.prototype.getHistory = function getHistory(account) { */ TXDB.prototype.getAccountHistory = async function getAccountHistory(account) { - let hashes = await this.getHistoryHashes(account); - let txs = []; + const hashes = await this.getHistoryHashes(account); + const txs = []; - for (let hash of hashes) { - let tx = await this.getTX(hash); + for (const hash of hashes) { + const tx = await this.getTX(hash); assert(tx); txs.push(tx); } @@ -1975,11 +1974,11 @@ TXDB.prototype.getAccountHistory = async function getAccountHistory(account) { */ TXDB.prototype.getPending = async function getPending(account) { - let hashes = await this.getPendingHashes(account); - let txs = []; + const hashes = await this.getPendingHashes(account); + const txs = []; - for (let hash of hashes) { - let tx = await this.getTX(hash); + for (const hash of hashes) { + const tx = await this.getTX(hash); assert(tx); txs.push(tx); } @@ -2003,9 +2002,9 @@ TXDB.prototype.getCredits = function getCredits(account) { gte: layout.c(encoding.NULL_HASH, 0x00000000), lte: layout.c(encoding.HIGH_HASH, 0xffffffff), parse: (key, value) => { - let [hash, index] = layout.cc(key); - let credit = Credit.fromRaw(value); - let ckey = Outpoint.toKey(hash, index); + const [hash, index] = layout.cc(key); + const credit = Credit.fromRaw(value); + const ckey = Outpoint.toKey(hash, index); credit.coin.hash = hash; credit.coin.index = index; this.coinCache.set(ckey, value); @@ -2021,11 +2020,11 @@ TXDB.prototype.getCredits = function getCredits(account) { */ TXDB.prototype.getAccountCredits = async function getAccountCredits(account) { - let outpoints = await this.getOutpoints(account); - let credits = []; + const outpoints = await this.getOutpoints(account); + const credits = []; - for (let prevout of outpoints) { - let credit = await this.getCredit(prevout.hash, prevout.index); + for (const prevout of outpoints) { + const credit = await this.getCredit(prevout.hash, prevout.index); assert(credit); credits.push(credit); } @@ -2040,24 +2039,22 @@ TXDB.prototype.getAccountCredits = async function getAccountCredits(account) { */ TXDB.prototype.getSpentCredits = async function getSpentCredits(tx) { - let credits = []; - let hash; + if (tx.isCoinbase()) + return []; + + const hash = tx.hash('hex'); + const credits = []; for (let i = 0; i < tx.inputs.length; i++) credits.push(null); - if (tx.isCoinbase()) - return credits; - - hash = tx.hash('hex'); - await this.range({ gte: layout.d(hash, 0x00000000), lte: layout.d(hash, 0xffffffff), parse: (key, value) => { - let [, index] = layout.dd(key); - let coin = Coin.fromRaw(value); - let input = tx.inputs[index]; + const [, index] = layout.dd(key); + const coin = Coin.fromRaw(value); + const input = tx.inputs[index]; assert(input); coin.hash = input.prevout.hash; coin.index = input.prevout.index; @@ -2075,10 +2072,10 @@ TXDB.prototype.getSpentCredits = async function getSpentCredits(tx) { */ TXDB.prototype.getCoins = async function getCoins(account) { - let credits = await this.getCredits(account); - let coins = []; + const credits = await this.getCredits(account); + const coins = []; - for (let credit of credits) { + for (const credit of credits) { if (credit.spent) continue; @@ -2095,10 +2092,10 @@ TXDB.prototype.getCoins = async function getCoins(account) { */ TXDB.prototype.getAccountCoins = async function getAccountCoins(account) { - let credits = await this.getAccountCredits(account); - let coins = []; + const credits = await this.getAccountCredits(account); + const coins = []; - for (let credit of credits) { + for (const credit of credits) { if (credit.spent) continue; @@ -2115,15 +2112,13 @@ TXDB.prototype.getAccountCoins = async function getAccountCoins(account) { */ TXDB.prototype.getSpentCoins = async function getSpentCoins(tx) { - let coins = []; - let credits; - if (tx.isCoinbase()) - return coins; + return []; - credits = await this.getSpentCredits(tx); + const credits = await this.getSpentCredits(tx); + const coins = []; - for (let credit of credits) { + for (const credit of credits) { if (!credit) { coins.push(null); continue; @@ -2142,14 +2137,14 @@ TXDB.prototype.getSpentCoins = async function getSpentCoins(tx) { */ TXDB.prototype.getCoinView = async function getCoinView(tx) { - let view = new CoinView(); + const view = new CoinView(); if (tx.isCoinbase()) return view; - for (let input of tx.inputs) { - let prevout = input.prevout; - let coin = await this.getCoin(prevout.hash, prevout.index); + for (const input of tx.inputs) { + const prevout = input.prevout; + const coin = await this.getCoin(prevout.hash, prevout.index); if (!coin) continue; @@ -2167,15 +2162,14 @@ TXDB.prototype.getCoinView = async function getCoinView(tx) { */ TXDB.prototype.getSpentView = async function getSpentView(tx) { - let view = new CoinView(); - let coins; + const view = new CoinView(); if (tx.isCoinbase()) return view; - coins = await this.getSpentCoins(tx); + const coins = await this.getSpentCoins(tx); - for (let coin of coins) { + for (const coin of coins) { if (!coin) continue; @@ -2191,10 +2185,10 @@ TXDB.prototype.getSpentView = async function getSpentView(tx) { */ TXDB.prototype.getState = async function getState() { - let data = await this.get(layout.R); + const data = await this.get(layout.R); if (!data) - return; + return null; return TXDBState.fromRaw(this.wallet.wid, this.wallet.id, data); }; @@ -2206,10 +2200,10 @@ TXDB.prototype.getState = async function getState() { */ TXDB.prototype.getTX = async function getTX(hash) { - let raw = await this.get(layout.t(hash)); + const raw = await this.get(layout.t(hash)); if (!raw) - return; + return null; return TXRecord.fromRaw(raw); }; @@ -2221,10 +2215,10 @@ TXDB.prototype.getTX = async function getTX(hash) { */ TXDB.prototype.getDetails = async function getDetails(hash) { - let wtx = await this.getTX(hash); + const wtx = await this.getTX(hash); if (!wtx) - return; + return null; return await this.toDetails(wtx); }; @@ -2236,13 +2230,13 @@ TXDB.prototype.getDetails = async function getDetails(hash) { */ TXDB.prototype.toDetails = async function toDetails(wtxs) { - let out = []; + const out = []; if (!Array.isArray(wtxs)) return await this._toDetails(wtxs); - for (let wtx of wtxs) { - let details = await this._toDetails(wtx); + for (const wtx of wtxs) { + const details = await this._toDetails(wtx); if (!details) continue; @@ -2261,13 +2255,13 @@ TXDB.prototype.toDetails = async function toDetails(wtxs) { */ TXDB.prototype._toDetails = async function _toDetails(wtx) { - let tx = wtx.tx; - let block = wtx.getBlock(); - let details = new Details(this, wtx, block); - let coins = await this.getSpentCoins(tx); + const tx = wtx.tx; + const block = wtx.getBlock(); + const details = new Details(this, wtx, block); + const coins = await this.getSpentCoins(tx); for (let i = 0; i < tx.inputs.length; i++) { - let coin = coins[i]; + const coin = coins[i]; let path = null; if (coin) @@ -2277,8 +2271,8 @@ TXDB.prototype._toDetails = async function _toDetails(wtx) { } for (let i = 0; i < tx.outputs.length; i++) { - let output = tx.outputs[i]; - let path = await this.getPath(output); + const output = tx.outputs[i]; + const path = await this.getPath(output); details.setOutput(i, path); } @@ -2303,10 +2297,10 @@ TXDB.prototype.hasTX = function hasTX(hash) { */ TXDB.prototype.getCoin = async function getCoin(hash, index) { - let credit = await this.getCredit(hash, index); + const credit = await this.getCredit(hash, index); if (!credit) - return; + return null; return credit.coin; }; @@ -2319,24 +2313,23 @@ TXDB.prototype.getCoin = async function getCoin(hash, index) { */ TXDB.prototype.getCredit = async function getCredit(hash, index) { - let state = this.state; - let key = Outpoint.toKey(hash, index); - let data = this.coinCache.get(key); - let credit; + const state = this.state; + const key = Outpoint.toKey(hash, index); + const cache = this.coinCache.get(key); - if (data) { - credit = Credit.fromRaw(data); + if (cache) { + const credit = Credit.fromRaw(cache); credit.coin.hash = hash; credit.coin.index = index; return credit; } - data = await this.get(layout.c(hash, index)); + const data = await this.get(layout.c(hash, index)); if (!data) - return; + return null; - credit = Credit.fromRaw(data); + const credit = Credit.fromRaw(data); credit.coin.hash = hash; credit.coin.index = index; @@ -2354,13 +2347,12 @@ TXDB.prototype.getCredit = async function getCredit(hash, index) { */ TXDB.prototype.getSpentCoin = async function getSpentCoin(spent, prevout) { - let data = await this.get(layout.d(spent.hash, spent.index)); - let coin; + const data = await this.get(layout.d(spent.hash, spent.index)); if (!data) - return; + return null; - coin = Coin.fromRaw(data); + const coin = Coin.fromRaw(data); coin.hash = prevout.hash; coin.index = prevout.index; @@ -2386,14 +2378,13 @@ TXDB.prototype.hasSpentCoin = function hasSpentCoin(spent) { */ TXDB.prototype.updateSpentCoin = async function updateSpentCoin(tx, index, height) { - let prevout = Outpoint.fromTX(tx, index); - let spent = await this.getSpent(prevout.hash, prevout.index); - let coin; + const prevout = Outpoint.fromTX(tx, index); + const spent = await this.getSpent(prevout.hash, prevout.index); if (!spent) return; - coin = await this.getSpentCoin(spent, prevout); + const coin = await this.getSpentCoin(spent, prevout); if (!coin) return; @@ -2409,13 +2400,13 @@ TXDB.prototype.updateSpentCoin = async function updateSpentCoin(tx, index, heigh * @returns {Promise} - Returns Boolean. */ -TXDB.prototype.hasCoin = function hasCoin(hash, index) { - let key = Outpoint.toKey(hash, index); +TXDB.prototype.hasCoin = async function hasCoin(hash, index) { + const key = Outpoint.toKey(hash, index); if (this.coinCache.has(key)) - return Promise.resolve(true); + return true; - return this.has(layout.c(hash, index)); + return await this.has(layout.c(hash, index)); }; /** @@ -2440,11 +2431,11 @@ TXDB.prototype.getBalance = async function getBalance(account) { */ TXDB.prototype.getWalletBalance = async function getWalletBalance() { - let credits = await this.getCredits(); - let balance = new Balance(this.wallet.wid, this.wallet.id, -1); + const credits = await this.getCredits(); + const balance = new Balance(this.wallet.wid, this.wallet.id, -1); - for (let credit of credits) { - let coin = credit.coin; + for (const credit of credits) { + const coin = credit.coin; if (coin.height !== -1) balance.confirmed += coin.value; @@ -2463,11 +2454,11 @@ TXDB.prototype.getWalletBalance = async function getWalletBalance() { */ TXDB.prototype.getAccountBalance = async function getAccountBalance(account) { - let credits = await this.getAccountCredits(account); - let balance = new Balance(this.wallet.wid, this.wallet.id, account); + const credits = await this.getAccountCredits(account); + const balance = new Balance(this.wallet.wid, this.wallet.id, account); - for (let credit of credits) { - let coin = credit.coin; + for (const credit of credits) { + const coin = credit.coin; if (coin.height !== -1) balance.confirmed += coin.value; @@ -2487,22 +2478,22 @@ TXDB.prototype.getAccountBalance = async function getAccountBalance(account) { */ TXDB.prototype.zap = async function zap(account, age) { - let hashes = []; - let now = util.now(); - let txs; + assert(util.isU32(age)); - assert(util.isUInt32(age)); + const now = util.now(); - txs = await this.getRange(account, { + const txs = await this.getRange(account, { start: 0, end: now - age }); - for (let wtx of txs) { + const hashes = []; + + for (const wtx of txs) { if (wtx.height !== -1) continue; - assert(now - wtx.ps >= age); + assert(now - wtx.mtime >= age); this.logger.debug('Zapping TX: %s (%s)', wtx.tx.txid(), this.wallet.id); @@ -2522,7 +2513,7 @@ TXDB.prototype.zap = async function zap(account, age) { */ TXDB.prototype.abandon = async function abandon(hash) { - let result = await this.has(layout.p(hash)); + const result = await this.has(layout.p(hash)); if (!result) throw new Error('TX not eligible.'); @@ -2623,7 +2614,7 @@ function TXDBState(wid, id) { */ TXDBState.prototype.clone = function clone() { - let state = new TXDBState(this.wid, this.id); + const state = new TXDBState(this.wid, this.id); state.tx = this.tx; state.coin = this.coin; state.unconfirmed = this.unconfirmed; @@ -2647,7 +2638,7 @@ TXDBState.prototype.commit = function commit() { */ TXDBState.prototype.toBalance = function toBalance() { - let balance = new Balance(this.wid, this.id, -1); + const balance = new Balance(this.wid, this.id, -1); balance.unconfirmed = this.unconfirmed; balance.confirmed = this.confirmed; return balance; @@ -2659,7 +2650,7 @@ TXDBState.prototype.toBalance = function toBalance() { */ TXDBState.prototype.toRaw = function toRaw() { - let bw = new StaticWriter(32); + const bw = new StaticWriter(32); bw.writeU64(this.tx); bw.writeU64(this.coin); @@ -2677,7 +2668,7 @@ TXDBState.prototype.toRaw = function toRaw() { */ TXDBState.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.tx = br.readU53(); this.coin = br.readU53(); this.unconfirmed = br.readU53(); @@ -2747,7 +2738,7 @@ function Credit(coin, spent) { */ Credit.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); + const br = new BufferReader(data); this.coin.fromReader(br); this.spent = br.readU8() === 1; this.own = true; @@ -2784,8 +2775,8 @@ Credit.prototype.getSize = function getSize() { */ Credit.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); this.coin.toWriter(bw); bw.writeU8(this.spent ? 1 : 0); bw.writeU8(this.own ? 1 : 0); @@ -2839,24 +2830,22 @@ function Details(txdb, wtx, block) { this.hash = wtx.hash; this.tx = wtx.tx; - this.ps = wtx.ps; + this.mtime = wtx.mtime; this.size = this.tx.getSize(); this.vsize = this.tx.getVirtualSize(); this.block = null; this.height = -1; - this.ts = 0; - this.index = -1; + this.time = 0; if (block) { this.block = block.hash; this.height = block.height; - this.ts = block.ts; + this.time = block.time; } this.inputs = []; this.outputs = []; - this.accounts = []; this.init(); } @@ -2867,14 +2856,14 @@ function Details(txdb, wtx, block) { */ Details.prototype.init = function init() { - for (let input of this.tx.inputs) { - let member = new DetailsMember(); + for (const input of this.tx.inputs) { + const member = new DetailsMember(); member.address = input.getAddress(); this.inputs.push(member); } - for (let output of this.tx.outputs) { - let member = new DetailsMember(); + for (const output of this.tx.outputs) { + const member = new DetailsMember(); member.value = output.value; member.address = output.getAddress(); this.outputs.push(member); @@ -2889,17 +2878,15 @@ Details.prototype.init = function init() { */ Details.prototype.setInput = function setInput(i, path, coin) { - let member = this.inputs[i]; + const member = this.inputs[i]; if (coin) { member.value = coin.value; member.address = coin.getAddress(); } - if (path) { + if (path) member.path = path; - util.binaryInsert(this.accounts, path.account, cmp, true); - } }; /** @@ -2909,12 +2896,10 @@ Details.prototype.setInput = function setInput(i, path, coin) { */ Details.prototype.setOutput = function setOutput(i, path) { - let member = this.outputs[i]; + const member = this.outputs[i]; - if (path) { + if (path) member.path = path; - util.binaryInsert(this.accounts, path.account, cmp, true); - } }; /** @@ -2923,12 +2908,10 @@ Details.prototype.setOutput = function setOutput(i, path) { */ Details.prototype.getDepth = function getDepth() { - let depth; - if (this.height === -1) return 0; - depth = this.chainHeight - this.height; + const depth = this.chainHeight - this.height; if (depth < 0) return 0; @@ -2946,14 +2929,14 @@ Details.prototype.getFee = function getFee() { let inputValue = 0; let outputValue = 0; - for (let input of this.inputs) { + for (const input of this.inputs) { if (!input.path) return 0; inputValue += input.value; } - for (let output of this.outputs) + for (const output of this.outputs) outputValue += output.value; return inputValue - outputValue; @@ -2976,11 +2959,11 @@ Details.prototype.getRate = function getRate(fee) { */ Details.prototype.toJSON = function toJSON() { - let fee = this.getFee(); + const fee = this.getFee(); let rate = this.getRate(fee); // Rate can exceed 53 bits in testing. - if (!util.isSafeInteger(rate)) + if (!Number.isSafeInteger(rate)) rate = 0; return { @@ -2989,10 +2972,9 @@ Details.prototype.toJSON = function toJSON() { hash: util.revHex(this.hash), height: this.height, block: this.block ? util.revHex(this.block) : null, - ts: this.ts, - ps: this.ps, - date: util.date(this.ts || this.ps), - index: this.index, + time: this.time, + mtime: this.mtime, + date: util.date(this.time || this.mtime), size: this.size, virtualSize: this.vsize, fee: fee, @@ -3059,18 +3041,18 @@ DetailsMember.prototype.getJSON = function getJSON(network) { * @constructor * @param {Hash} hash * @param {Number} height - * @param {Number} ts + * @param {Number} time */ -function BlockRecord(hash, height, ts) { +function BlockRecord(hash, height, time) { if (!(this instanceof BlockRecord)) - return new BlockRecord(hash, height, ts); + return new BlockRecord(hash, height, time); this.hash = hash || encoding.NULL_HASH; this.height = height != null ? height : -1; - this.ts = ts || 0; + this.time = time || 0; this.hashes = []; - this.index = {}; + this.index = new Set(); } /** @@ -3080,10 +3062,10 @@ function BlockRecord(hash, height, ts) { */ BlockRecord.prototype.add = function add(hash) { - if (this.index[hash]) + if (this.index.has(hash)) return false; - this.index[hash] = true; + this.index.add(hash); this.hashes.push(hash); return true; @@ -3096,12 +3078,10 @@ BlockRecord.prototype.add = function add(hash) { */ BlockRecord.prototype.remove = function remove(hash) { - let index; - - if (!this.index[hash]) + if (!this.index.has(hash)) return false; - delete this.index[hash]; + this.index.delete(hash); // Fast case if (this.hashes[this.hashes.length - 1] === hash) { @@ -3109,7 +3089,7 @@ BlockRecord.prototype.remove = function remove(hash) { return true; } - index = this.hashes.indexOf(hash); + const index = this.hashes.indexOf(hash); assert(index !== -1); @@ -3125,18 +3105,17 @@ BlockRecord.prototype.remove = function remove(hash) { */ BlockRecord.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let count; + const br = new BufferReader(data); this.hash = br.readHash('hex'); this.height = br.readU32(); - this.ts = br.readU32(); + this.time = br.readU32(); - count = br.readU32(); + const count = br.readU32(); for (let i = 0; i < count; i++) { - let hash = br.readHash('hex'); - this.index[hash] = true; + const hash = br.readHash('hex'); + this.index.add(hash); this.hashes.push(hash); } @@ -3168,16 +3147,16 @@ BlockRecord.prototype.getSize = function getSize() { */ BlockRecord.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeHash(this.hash); bw.writeU32(this.height); - bw.writeU32(this.ts); + bw.writeU32(this.time); bw.writeU32(this.hashes.length); - for (let hash of this.hashes) + for (const hash of this.hashes) bw.writeHash(hash); return bw.render(); @@ -3192,7 +3171,7 @@ BlockRecord.prototype.toJSON = function toJSON() { return { hash: util.revHex(this.hash), height: this.height, - ts: this.ts, + time: this.time, hashes: this.hashes.map(util.revHex) }; }; @@ -3206,7 +3185,7 @@ BlockRecord.prototype.toJSON = function toJSON() { BlockRecord.prototype.fromMeta = function fromMeta(block) { this.hash = block.hash; this.height = block.height; - this.ts = block.ts; + this.time = block.time; return this; }; @@ -3220,14 +3199,6 @@ BlockRecord.fromMeta = function fromMeta(block) { return new BlockRecord().fromMeta(block); }; -/* - * Helpers - */ - -function cmp(a, b) { - return a - b; -} - /* * Expose */ diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index 6282d2d7f..9f39edd33 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -57,6 +57,8 @@ const Mnemonic = HD.Mnemonic; * @param {Number?} options.m - `m` value for multisig. * @param {Number?} options.n - `n` value for multisig. * @param {String?} options.id - Wallet ID (used for storage) + * @param {String?} options.mnemonic - mnemonic phrase to use to instantiate an + * hd private key for wallet * (default=account key "address"). */ @@ -95,7 +97,7 @@ function Wallet(db, options) { this.fromOptions(options); } -util.inherits(Wallet, EventEmitter); +Object.setPrototypeOf(Wallet.prototype, EventEmitter.prototype); /** * Inject properties from options object. @@ -124,7 +126,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) { this.master.fromKey(key, mnemonic); if (options.wid != null) { - assert(util.isNumber(options.wid)); + assert(util.isU32(options.wid)); this.wid = options.wid; } @@ -144,7 +146,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) { } if (options.accountDepth != null) { - assert(util.isNumber(options.accountDepth)); + assert(util.isU32(options.accountDepth)); this.accountDepth = options.accountDepth; } @@ -155,7 +157,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) { } if (options.tokenDepth != null) { - assert(util.isNumber(options.tokenDepth)); + assert(util.isU32(options.tokenDepth)); this.tokenDepth = options.tokenDepth; } @@ -191,8 +193,7 @@ Wallet.fromOptions = function fromOptions(db, options) { */ Wallet.prototype.init = async function init(options) { - let passphrase = options.passphrase; - let account; + const passphrase = options.passphrase; assert(!this.initialized); this.initialized = true; @@ -200,7 +201,7 @@ Wallet.prototype.init = async function init(options) { if (passphrase) await this.master.encrypt(passphrase); - account = await this._createAccount(options, passphrase); + const account = await this._createAccount(options, passphrase); assert(account); this.account = account; @@ -216,11 +217,9 @@ Wallet.prototype.init = async function init(options) { */ Wallet.prototype.open = async function open() { - let account; - assert(this.initialized); - account = await this.getAccount(0); + const account = await this.getAccount(0); if (!account) throw new Error('Default account not found.'); @@ -238,8 +237,8 @@ Wallet.prototype.open = async function open() { */ Wallet.prototype.destroy = async function destroy() { - let unlock1 = await this.writeLock.lock(); - let unlock2 = await this.fundLock.lock(); + const unlock1 = await this.writeLock.lock(); + const unlock2 = await this.fundLock.lock(); try { this.db.unregister(this); await this.master.destroy(); @@ -261,7 +260,7 @@ Wallet.prototype.destroy = async function destroy() { */ Wallet.prototype.addSharedKey = async function addSharedKey(acct, key) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._addSharedKey(acct, key); } finally { @@ -277,9 +276,7 @@ Wallet.prototype.addSharedKey = async function addSharedKey(acct, key) { * @returns {Promise} */ -Wallet.prototype._addSharedKey = async function addSharedKey(acct, key) { - let account, result; - +Wallet.prototype._addSharedKey = async function _addSharedKey(acct, key) { if (!key) { key = acct; acct = null; @@ -288,13 +285,14 @@ Wallet.prototype._addSharedKey = async function addSharedKey(acct, key) { if (acct == null) acct = 0; - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); this.start(); + let result; try { result = await account.addSharedKey(key); } catch (e) { @@ -315,7 +313,7 @@ Wallet.prototype._addSharedKey = async function addSharedKey(acct, key) { */ Wallet.prototype.removeSharedKey = async function removeSharedKey(acct, key) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._removeSharedKey(acct, key); } finally { @@ -331,9 +329,7 @@ Wallet.prototype.removeSharedKey = async function removeSharedKey(acct, key) { * @returns {Promise} */ -Wallet.prototype._removeSharedKey = async function removeSharedKey(acct, key) { - let account, result; - +Wallet.prototype._removeSharedKey = async function _removeSharedKey(acct, key) { if (!key) { key = acct; acct = null; @@ -342,13 +338,14 @@ Wallet.prototype._removeSharedKey = async function removeSharedKey(acct, key) { if (acct == null) acct = 0; - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); this.start(); + let result; try { result = await account.removeSharedKey(key); } catch (e) { @@ -388,7 +385,7 @@ Wallet.prototype.setPassphrase = async function setPassphrase(old, new_) { */ Wallet.prototype.encrypt = async function encrypt(passphrase) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._encrypt(passphrase); } finally { @@ -403,8 +400,8 @@ Wallet.prototype.encrypt = async function encrypt(passphrase) { * @returns {Promise} */ -Wallet.prototype._encrypt = async function encrypt(passphrase) { - let key = await this.master.encrypt(passphrase, true); +Wallet.prototype._encrypt = async function _encrypt(passphrase) { + const key = await this.master.encrypt(passphrase, true); this.start(); @@ -430,7 +427,7 @@ Wallet.prototype._encrypt = async function encrypt(passphrase) { */ Wallet.prototype.decrypt = async function decrypt(passphrase) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._decrypt(passphrase); } finally { @@ -445,8 +442,8 @@ Wallet.prototype.decrypt = async function decrypt(passphrase) { * @returns {Promise} */ -Wallet.prototype._decrypt = async function decrypt(passphrase) { - let key = await this.master.decrypt(passphrase, true); +Wallet.prototype._decrypt = async function _decrypt(passphrase) { + const key = await this.master.decrypt(passphrase, true); this.start(); @@ -472,7 +469,7 @@ Wallet.prototype._decrypt = async function decrypt(passphrase) { */ Wallet.prototype.retoken = async function retoken(passphrase) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._retoken(passphrase); } finally { @@ -487,7 +484,7 @@ Wallet.prototype.retoken = async function retoken(passphrase) { * @returns {Promise} */ -Wallet.prototype._retoken = async function retoken(passphrase) { +Wallet.prototype._retoken = async function _retoken(passphrase) { await this.unlock(passphrase); this.tokenDepth++; @@ -508,7 +505,7 @@ Wallet.prototype._retoken = async function retoken(passphrase) { */ Wallet.prototype.rename = async function rename(id) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this.db.rename(this, id); } finally { @@ -524,7 +521,7 @@ Wallet.prototype.rename = async function rename(id) { */ Wallet.prototype.renameAccount = async function renameAccount(acct, name) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._renameAccount(acct, name); } finally { @@ -541,12 +538,10 @@ Wallet.prototype.renameAccount = async function renameAccount(acct, name) { */ Wallet.prototype._renameAccount = async function _renameAccount(acct, name) { - let account, old, paths; - if (!common.isName(name)) throw new Error('Bad account name.'); - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); @@ -557,7 +552,7 @@ Wallet.prototype._renameAccount = async function _renameAccount(acct, name) { if (await this.hasAccount(name)) throw new Error('Account name not available.'); - old = account.name; + const old = account.name; this.start(); @@ -567,9 +562,9 @@ Wallet.prototype._renameAccount = async function _renameAccount(acct, name) { this.indexCache.remove(old); - paths = this.pathCache.values(); + const paths = this.pathCache.values(); - for (let path of paths) { + for (const path of paths) { if (path.account !== account.accountIndex) continue; @@ -582,8 +577,8 @@ Wallet.prototype._renameAccount = async function _renameAccount(acct, name) { */ Wallet.prototype.lock = async function lock() { - let unlock1 = await this.writeLock.lock(); - let unlock2 = await this.fundLock.lock(); + const unlock1 = await this.writeLock.lock(); + const unlock2 = await this.fundLock.lock(); try { await this.master.lock(); } finally { @@ -612,26 +607,24 @@ Wallet.prototype.unlock = function unlock(passphrase, timeout) { */ Wallet.prototype.getID = function getID() { - let bw, key, hash; - assert(this.master.key, 'Cannot derive id.'); - key = this.master.key.derive(44); + const key = this.master.key.derive(44); - bw = new StaticWriter(37); + const bw = new StaticWriter(37); bw.writeBytes(key.publicKey); bw.writeU32(this.network.magic); - hash = digest.hash160(bw.render()); + const hash = digest.hash160(bw.render()); - bw = new StaticWriter(27); - bw.writeU8(0x03); - bw.writeU8(0xbe); - bw.writeU8(0x04); - bw.writeBytes(hash); - bw.writeChecksum(); + const b58 = new StaticWriter(27); + b58.writeU8(0x03); + b58.writeU8(0xbe); + b58.writeU8(0x04); + b58.writeBytes(hash); + b58.writeChecksum(); - return base58.encode(bw.render()); + return base58.encode(b58.render()); }; /** @@ -644,13 +637,11 @@ Wallet.prototype.getID = function getID() { */ Wallet.prototype.getToken = function getToken(nonce) { - let bw, key; - assert(this.master.key, 'Cannot derive token.'); - key = this.master.key.derive(44, true); + const key = this.master.key.derive(44, true); - bw = new StaticWriter(36); + const bw = new StaticWriter(36); bw.writeBytes(key.privateKey); bw.writeU32(nonce); @@ -664,7 +655,7 @@ Wallet.prototype.getToken = function getToken(nonce) { */ Wallet.prototype.createAccount = async function createAccount(options, passphrase) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._createAccount(options, passphrase); } finally { @@ -678,20 +669,18 @@ Wallet.prototype.createAccount = async function createAccount(options, passphras * @returns {Promise} - Returns {@link Account}. */ -Wallet.prototype._createAccount = async function createAccount(options, passphrase) { +Wallet.prototype._createAccount = async function _createAccount(options, passphrase) { let name = options.name; - let key, account, exists; if (!name) - name = this.accountDepth + ''; + name = this.accountDepth.toString(10); - exists = await this.hasAccount(name); - - if (exists) + if (await this.hasAccount(name)) throw new Error('Account already exists.'); await this.unlock(passphrase); + let key; if (this.watchOnly && options.accountKey) { key = options.accountKey; @@ -705,11 +694,11 @@ Wallet.prototype._createAccount = async function createAccount(options, passphra 'Network mismatch for watch only key.'); } else { assert(this.master.key); - key = this.master.key.deriveBIP44(this.accountDepth); + key = this.master.key.deriveAccount(44, this.accountDepth); key = key.toPublic(); } - options = { + const opt = { wid: this.wid, id: this.id, name: this.accountDepth === 0 ? 'default' : name, @@ -725,8 +714,9 @@ Wallet.prototype._createAccount = async function createAccount(options, passphra this.start(); + let account; try { - account = Account.fromOptions(this.db, options); + account = Account.fromOptions(this.db, opt); account.wallet = this; await account.init(); } catch (e) { @@ -754,8 +744,8 @@ Wallet.prototype._createAccount = async function createAccount(options, passphra */ Wallet.prototype.ensureAccount = async function ensureAccount(options, passphrase) { - let name = options.name; - let account = await this.getAccount(name); + const name = options.name; + const account = await this.getAccount(name); if (account) return account; @@ -791,7 +781,7 @@ Wallet.prototype.getAddressHashes = function getAddressHashes(acct) { */ Wallet.prototype.getAccountHashes = async function getAccountHashes(acct) { - let index = await this.ensureIndex(acct, true); + const index = await this.ensureIndex(acct, true); return await this.db.getAccountHashes(this.wid, index); }; @@ -802,19 +792,17 @@ Wallet.prototype.getAccountHashes = async function getAccountHashes(acct) { */ Wallet.prototype.getAccount = async function getAccount(acct) { - let index, unlock; - if (this.account) { if (acct === 0 || acct === 'default') return this.account; } - index = await this.getAccountIndex(acct); + const index = await this.getAccountIndex(acct); if (index === -1) - return; + return null; - unlock = await this.readLock.lock(index); + const unlock = await this.readLock.lock(index); try { return await this._getAccount(index); @@ -829,16 +817,16 @@ Wallet.prototype.getAccount = async function getAccount(acct) { * @returns {Promise} - Returns {@link Account}. */ -Wallet.prototype._getAccount = async function getAccount(index) { - let account = this.accountCache.get(index); +Wallet.prototype._getAccount = async function _getAccount(index) { + const cache = this.accountCache.get(index); - if (account) - return account; + if (cache) + return cache; - account = await this.db.getAccount(this.wid, index); + const account = await this.db.getAccount(this.wid, index); if (!account) - return; + return null; account.wallet = this; account.wid = this.wid; @@ -860,20 +848,18 @@ Wallet.prototype._getAccount = async function getAccount(index) { */ Wallet.prototype.getAccountIndex = async function getAccountIndex(name) { - let index; - if (name == null) return -1; if (typeof name === 'number') return name; - index = this.indexCache.get(name); + const cache = this.indexCache.get(name); - if (index != null) - return index; + if (cache != null) + return cache; - index = await this.db.getAccountIndex(this.wid, name); + const index = await this.db.getAccountIndex(this.wid, name); if (index === -1) return -1; @@ -891,12 +877,10 @@ Wallet.prototype.getAccountIndex = async function getAccountIndex(name) { */ Wallet.prototype.getAccountName = async function getAccountName(index) { - let account; - if (typeof index === 'string') return index; - account = this.accountCache.get(index); + const account = this.accountCache.get(index); if (account) return account.name; @@ -911,7 +895,7 @@ Wallet.prototype.getAccountName = async function getAccountName(index) { */ Wallet.prototype.hasAccount = async function hasAccount(acct) { - let index = await this.getAccountIndex(acct); + const index = await this.getAccountIndex(acct); if (index === -1) return false; @@ -960,7 +944,7 @@ Wallet.prototype.createNested = function createNested(acct) { */ Wallet.prototype.createKey = async function createKey(acct, branch) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._createKey(acct, branch); } finally { @@ -976,9 +960,7 @@ Wallet.prototype.createKey = async function createKey(acct, branch) { * @returns {Promise} - Returns {@link WalletKey}. */ -Wallet.prototype._createKey = async function createKey(acct, branch) { - let account, result; - +Wallet.prototype._createKey = async function _createKey(acct, branch) { if (branch == null) { branch = acct; acct = null; @@ -987,13 +969,14 @@ Wallet.prototype._createKey = async function createKey(acct, branch) { if (acct == null) acct = 0; - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); this.start(); + let result; try { result = await account.createKey(branch); } catch (e) { @@ -1059,8 +1042,8 @@ Wallet.prototype.commit = function commit() { */ Wallet.prototype.hasAddress = async function hasAddress(address) { - let hash = Address.getHash(address, 'hex'); - let path = await this.getPath(hash); + const hash = Address.getHash(address, 'hex'); + const path = await this.getPath(hash); return path != null; }; @@ -1071,10 +1054,10 @@ Wallet.prototype.hasAddress = async function hasAddress(address) { */ Wallet.prototype.getPath = async function getPath(address) { - let path = await this.readPath(address); + const path = await this.readPath(address); if (!path) - return; + return null; path.name = await this.getAccountName(path.account); @@ -1093,16 +1076,16 @@ Wallet.prototype.getPath = async function getPath(address) { */ Wallet.prototype.readPath = async function readPath(address) { - let hash = Address.getHash(address, 'hex'); - let path = this.pathCache.get(hash); + const hash = Address.getHash(address, 'hex'); + const cache = this.pathCache.get(hash); - if (path) - return path; + if (cache) + return cache; - path = await this.db.getPath(this.wid, hash); + const path = await this.db.getPath(this.wid, hash); if (!path) - return; + return null; path.id = this.id; @@ -1116,7 +1099,7 @@ Wallet.prototype.readPath = async function readPath(address) { */ Wallet.prototype.hasPath = async function hasPath(address) { - let hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address, 'hex'); if (this.pathCache.has(hash)) return true; @@ -1131,15 +1114,13 @@ Wallet.prototype.hasPath = async function hasPath(address) { */ Wallet.prototype.getPaths = async function getPaths(acct) { - let paths, result; - if (acct != null) return await this.getAccountPaths(acct); - paths = await this.db.getWalletPaths(this.wid); - result = []; + const paths = await this.db.getWalletPaths(this.wid); + const result = []; - for (let path of paths) { + for (const path of paths) { path.id = this.id; path.name = await this.getAccountName(path.account); @@ -1160,15 +1141,16 @@ Wallet.prototype.getPaths = async function getPaths(acct) { */ Wallet.prototype.getAccountPaths = async function getAccountPaths(acct) { - let index = await this.ensureIndex(acct, true); - let hashes = await this.getAccountHashes(index); - let name = await this.getAccountName(acct); - let result = []; + const index = await this.ensureIndex(acct, true); + const hashes = await this.getAccountHashes(index); + const name = await this.getAccountName(acct); assert(name); - for (let hash of hashes) { - let path = await this.readPath(hash); + const result = []; + + for (const hash of hashes) { + const path = await this.readPath(hash); assert(path); assert(path.account === index); @@ -1193,7 +1175,7 @@ Wallet.prototype.getAccountPaths = async function getAccountPaths(acct) { */ Wallet.prototype.importKey = async function importKey(acct, ring, passphrase) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._importKey(acct, ring, passphrase); } finally { @@ -1210,9 +1192,7 @@ Wallet.prototype.importKey = async function importKey(acct, ring, passphrase) { * @returns {Promise} */ -Wallet.prototype._importKey = async function importKey(acct, ring, passphrase) { - let account, exists, path; - +Wallet.prototype._importKey = async function _importKey(acct, ring, passphrase) { if (acct && typeof acct === 'object') { passphrase = ring; ring = acct; @@ -1233,12 +1213,12 @@ Wallet.prototype._importKey = async function importKey(acct, ring, passphrase) { throw new Error('Cannot import privkey into watch-only wallet.'); } - exists = await this.getPath(ring.getHash('hex')); + const hash = ring.getHash('hex'); - if (exists) + if (await this.getPath(hash)) throw new Error('Key already exists.'); - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); @@ -1248,8 +1228,8 @@ Wallet.prototype._importKey = async function importKey(acct, ring, passphrase) { await this.unlock(passphrase); - ring = WalletKey.fromRing(account, ring); - path = ring.toPath(); + const key = WalletKey.fromRing(account, ring); + const path = key.toPath(); if (this.master.encrypted) { path.data = this.master.encipher(path.data, path.hash); @@ -1279,7 +1259,7 @@ Wallet.prototype._importKey = async function importKey(acct, ring, passphrase) { */ Wallet.prototype.importAddress = async function importAddress(acct, address) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._importAddress(acct, address); } finally { @@ -1296,9 +1276,7 @@ Wallet.prototype.importAddress = async function importAddress(acct, address) { * @returns {Promise} */ -Wallet.prototype._importAddress = async function importAddress(acct, address) { - let account, exists, path; - +Wallet.prototype._importAddress = async function _importAddress(acct, address) { if (!address) { address = acct; acct = null; @@ -1313,12 +1291,10 @@ Wallet.prototype._importAddress = async function importAddress(acct, address) { if (!this.watchOnly) throw new Error('Cannot import address into non watch-only wallet.'); - exists = await this.getPath(address); - - if (exists) + if (await this.getPath(address)) throw new Error('Address already exists.'); - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); @@ -1326,7 +1302,7 @@ Wallet.prototype._importAddress = async function importAddress(acct, address) { if (account.type !== Account.types.PUBKEYHASH) throw new Error('Cannot import into non-pkh account.'); - path = Path.fromAddress(account, address); + const path = Path.fromAddress(account, address); this.start(); @@ -1365,7 +1341,7 @@ Wallet.prototype._importAddress = async function importAddress(acct, address) { */ Wallet.prototype.fund = async function fund(mtx, options, force) { - let unlock = await this.fundLock.lock(force); + const unlock = await this.fundLock.lock(force); try { return await this._fund(mtx, options); } finally { @@ -1380,9 +1356,7 @@ Wallet.prototype.fund = async function fund(mtx, options, force) { * @see MTX#fill */ -Wallet.prototype._fund = async function fund(mtx, options) { - let rate, account, coins; - +Wallet.prototype._fund = async function _fund(mtx, options) { if (!options) options = {}; @@ -1392,6 +1366,7 @@ Wallet.prototype._fund = async function fund(mtx, options) { if (this.watchOnly) throw new Error('Cannot fund from watch-only wallet.'); + let account; if (options.account != null) { account = await this.getAccount(options.account); if (!account) @@ -1403,11 +1378,11 @@ Wallet.prototype._fund = async function fund(mtx, options) { if (!account.initialized) throw new Error('Account is not initialized.'); - rate = options.rate; - + let rate = options.rate; if (rate == null) rate = await this.db.estimateFee(options.blocks); + let coins; if (options.smart) { coins = await this.getSmartCoins(options.account); } else { @@ -1421,11 +1396,12 @@ Wallet.prototype._fund = async function fund(mtx, options) { depth: options.depth, hardFee: options.hardFee, subtractFee: options.subtractFee, + subtractIndex: options.subtractIndex, changeAddress: account.change.getAddress(), height: this.db.state.height, rate: rate, maxFee: options.maxFee, - estimate: this.estimateSize.bind(this) + estimate: prev => this.estimateSize(prev) }); assert(mtx.getFee() <= MTX.Selector.MAX_FEE, 'TX exceeds MAX_FEE.'); @@ -1438,11 +1414,11 @@ Wallet.prototype._fund = async function fund(mtx, options) { */ Wallet.prototype.getAccountByAddress = async function getAccountByAddress(address) { - let hash = Address.getHash(address, 'hex'); - let path = await this.getPath(hash); + const hash = Address.getHash(address, 'hex'); + const path = await this.getPath(hash); if (!path) - return; + return null; return await this.getAccount(path.account); }; @@ -1454,19 +1430,19 @@ Wallet.prototype.getAccountByAddress = async function getAccountByAddress(addres */ Wallet.prototype.estimateSize = async function estimateSize(prev) { - let scale = consensus.WITNESS_SCALE_FACTOR; - let address = prev.getAddress(); - let size = 0; - let account; + const scale = consensus.WITNESS_SCALE_FACTOR; + const address = prev.getAddress(); if (!address) return -1; - account = await this.getAccountByAddress(address); + const account = await this.getAccountByAddress(address); if (!account) return -1; + let size = 0; + if (prev.isScripthash()) { // Nested bullshit. if (account.witness) { @@ -1535,17 +1511,16 @@ Wallet.prototype.estimateSize = async function estimateSize(prev) { */ Wallet.prototype.createTX = async function createTX(options, force) { - let outputs = options.outputs; - let mtx = new MTX(); - let output, addr, total; + const outputs = options.outputs; + const mtx = new MTX(); assert(Array.isArray(outputs), 'Outputs must be an array.'); assert(outputs.length > 0, 'No outputs available.'); // Add the outputs - for (output of outputs) { - output = new Output(output); - addr = output.getAddress(); + for (const obj of outputs) { + const output = new Output(obj); + const addr = output.getAddress(); if (output.isDust()) throw new Error('Output is dust.'); @@ -1574,9 +1549,10 @@ Wallet.prototype.createTX = async function createTX(options, force) { // Consensus sanity checks. assert(mtx.isSane(), 'TX failed sanity check.'); - assert(mtx.verifyInputs(this.db.state.height + 1), 'TX failed context check.'); + assert(mtx.verifyInputs(this.db.state.height + 1), + 'TX failed context check.'); - total = await this.template(mtx); + const total = await this.template(mtx); if (total === 0) throw new Error('Templating failed.'); @@ -1595,7 +1571,7 @@ Wallet.prototype.createTX = async function createTX(options, force) { */ Wallet.prototype.send = async function send(options, passphrase) { - let unlock = await this.fundLock.lock(); + const unlock = await this.fundLock.lock(); try { return await this._send(options, passphrase); } finally { @@ -1611,16 +1587,15 @@ Wallet.prototype.send = async function send(options, passphrase) { * @returns {Promise} - Returns {@link TX}. */ -Wallet.prototype._send = async function send(options, passphrase) { - let mtx = await this.createTX(options, true); - let tx; +Wallet.prototype._send = async function _send(options, passphrase) { + const mtx = await this.createTX(options, true); await this.sign(mtx, passphrase); if (!mtx.isSigned()) throw new Error('TX could not be fully signed.'); - tx = mtx.toTX(); + const tx = mtx.toTX(); // Policy sanity checks. if (tx.getSigopsCost(mtx.view) > policy.MAX_TX_SIGOPS_COST) @@ -1648,10 +1623,9 @@ Wallet.prototype._send = async function send(options, passphrase) { */ Wallet.prototype.increaseFee = async function increaseFee(hash, rate, passphrase) { - let wtx = await this.getTX(hash); - let tx, mtx, view, oldFee, fee, change; + assert(util.isU32(rate), 'Rate must be a number.'); - assert(util.isUInt32(rate), 'Rate must be a number.'); + const wtx = await this.getTX(hash); if (!wtx) throw new Error('Transaction not found.'); @@ -1659,18 +1633,19 @@ Wallet.prototype.increaseFee = async function increaseFee(hash, rate, passphrase if (wtx.height !== -1) throw new Error('Transaction is confirmed.'); - tx = wtx.tx; + const tx = wtx.tx; if (tx.isCoinbase()) throw new Error('Transaction is a coinbase.'); - view = await this.getSpentView(tx); + const view = await this.getSpentView(tx); if (!tx.hasCoins(view)) throw new Error('Not all coins available.'); - oldFee = tx.getFee(view); - fee = tx.getMinFee(null, rate); + const oldFee = tx.getFee(view); + + let fee = tx.getMinFee(null, rate); if (fee > MTX.Selector.MAX_FEE) fee = MTX.Selector.MAX_FEE; @@ -1678,25 +1653,23 @@ Wallet.prototype.increaseFee = async function increaseFee(hash, rate, passphrase if (oldFee >= fee) throw new Error('Fee is not increasing.'); - mtx = MTX.fromTX(tx); + const mtx = MTX.fromTX(tx); mtx.view = view; - for (let input of mtx.inputs) { - input.script.length = 0; - input.script.compile(); - input.witness.length = 0; - input.witness.compile(); + for (const input of mtx.inputs) { + input.script.clear(); + input.witness.clear(); } + let change; for (let i = 0; i < mtx.outputs.length; i++) { - let output = mtx.outputs[i]; - let addr = output.getAddress(); - let path; + const output = mtx.outputs[i]; + const addr = output.getAddress(); if (!addr) continue; - path = await this.getPath(addr); + const path = await this.getPath(addr); if (!path) continue; @@ -1731,16 +1704,16 @@ Wallet.prototype.increaseFee = async function increaseFee(hash, rate, passphrase if (!mtx.isSigned()) throw new Error('TX could not be fully signed.'); - tx = mtx.toTX(); + const ntx = mtx.toTX(); this.logger.debug( 'Increasing fee for wallet tx (%s): %s', - this.id, tx.txid()); + this.id, ntx.txid()); - await this.db.addTX(tx); - await this.db.send(tx); + await this.db.addTX(ntx); + await this.db.send(ntx); - return tx; + return ntx; }; /** @@ -1749,18 +1722,19 @@ Wallet.prototype.increaseFee = async function increaseFee(hash, rate, passphrase */ Wallet.prototype.resend = async function resend() { - let wtxs = await this.getPending(); - let txs = []; + const wtxs = await this.getPending(); if (wtxs.length > 0) this.logger.info('Rebroadcasting %d transactions.', wtxs.length); - for (let wtx of wtxs) + const txs = []; + + for (const wtx of wtxs) txs.push(wtx.tx); - txs = common.sortDeps(txs); + const sorted = common.sortDeps(txs); - for (let tx of txs) + for (const tx of sorted) await this.db.send(tx); return txs; @@ -1774,21 +1748,18 @@ Wallet.prototype.resend = async function resend() { */ Wallet.prototype.deriveInputs = async function deriveInputs(mtx) { - let rings = []; - let paths; - assert(mtx.mutable); - paths = await this.getInputPaths(mtx); + const paths = await this.getInputPaths(mtx); + const rings = []; - for (let path of paths) { - let account = await this.getAccount(path.account); - let ring; + for (const path of paths) { + const account = await this.getAccount(path.account); if (!account) continue; - ring = account.derivePath(path, this.master); + const ring = account.derivePath(path, this.master); if (ring) rings.push(ring); @@ -1804,17 +1775,16 @@ Wallet.prototype.deriveInputs = async function deriveInputs(mtx) { */ Wallet.prototype.getKey = async function getKey(address) { - let hash = Address.getHash(address, 'hex'); - let path = await this.getPath(hash); - let account; + const hash = Address.getHash(address, 'hex'); + const path = await this.getPath(hash); if (!path) - return; + return null; - account = await this.getAccount(path.account); + const account = await this.getAccount(path.account); if (!account) - return; + return null; return account.derivePath(path, this.master); }; @@ -1828,24 +1798,23 @@ Wallet.prototype.getKey = async function getKey(address) { */ Wallet.prototype.getPrivateKey = async function getPrivateKey(address, passphrase) { - let hash = Address.getHash(address, 'hex'); - let path = await this.getPath(hash); - let account, key; + const hash = Address.getHash(address, 'hex'); + const path = await this.getPath(hash); if (!path) - return; + return null; - account = await this.getAccount(path.account); + const account = await this.getAccount(path.account); if (!account) - return; + return null; await this.unlock(passphrase); - key = account.derivePath(path, this.master); + const key = account.derivePath(path, this.master); if (!key.privateKey) - return; + return null; return key; }; @@ -1857,18 +1826,16 @@ Wallet.prototype.getPrivateKey = async function getPrivateKey(address, passphras */ Wallet.prototype.getInputPaths = async function getInputPaths(mtx) { - let paths = []; - let hashes; - assert(mtx.mutable); if (!mtx.hasCoins()) throw new Error('Not all coins available.'); - hashes = mtx.getInputHashes('hex'); + const hashes = mtx.getInputHashes('hex'); + const paths = []; - for (let hash of hashes) { - let path = await this.getPath(hash); + for (const hash of hashes) { + const path = await this.getPath(hash); if (path) paths.push(path); } @@ -1883,11 +1850,11 @@ Wallet.prototype.getInputPaths = async function getInputPaths(mtx) { */ Wallet.prototype.getOutputPaths = async function getOutputPaths(tx) { - let paths = []; - let hashes = tx.getOutputHashes('hex'); + const paths = []; + const hashes = tx.getOutputHashes('hex'); - for (let hash of hashes) { - let path = await this.getPath(hash); + for (const hash of hashes) { + const path = await this.getPath(hash); if (path) paths.push(path); } @@ -1903,7 +1870,7 @@ Wallet.prototype.getOutputPaths = async function getOutputPaths(tx) { */ Wallet.prototype.setLookahead = async function setLookahead(acct, lookahead) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return this._setLookahead(acct, lookahead); } finally { @@ -1919,9 +1886,7 @@ Wallet.prototype.setLookahead = async function setLookahead(acct, lookahead) { * @returns {Promise} */ -Wallet.prototype._setLookahead = async function setLookahead(acct, lookahead) { - let account; - +Wallet.prototype._setLookahead = async function _setLookahead(acct, lookahead) { if (lookahead == null) { lookahead = acct; acct = null; @@ -1930,7 +1895,7 @@ Wallet.prototype._setLookahead = async function setLookahead(acct, lookahead) { if (acct == null) acct = 0; - account = await this.getAccount(acct); + const account = await this.getAccount(acct); if (!account) throw new Error('Account not found.'); @@ -1956,14 +1921,10 @@ Wallet.prototype._setLookahead = async function setLookahead(acct, lookahead) { */ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { - let derived = []; - let accounts = {}; + const map = new Map(); - if (!details) - return derived; - - for (let output of details.outputs) { - let path = output.path; + for (const output of details.outputs) { + const path = output.path; if (!path) continue; @@ -1971,22 +1932,20 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { if (path.index === -1) continue; - if (!accounts[path.account]) - accounts[path.account] = []; + if (!map.has(path.account)) + map.set(path.account, []); - accounts[path.account].push(path); + map.get(path.account).push(path); } - accounts = util.values(accounts); + const derived = []; - for (let paths of accounts) { - let acct = paths[0].account; + for (const [acct, paths] of map) { let receive = -1; let change = -1; let nested = -1; - let account, ring; - for (let path of paths) { + for (const path of paths) { switch (path.branch) { case 0: if (path.index > receive) @@ -2007,10 +1966,10 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { change += 2; nested += 2; - account = await this.getAccount(acct); + const account = await this.getAccount(acct); assert(account); - ring = await account.syncDepth(receive, change, nested); + const ring = await account.syncDepth(receive, change, nested); if (ring) derived.push(ring); @@ -2026,15 +1985,13 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { */ Wallet.prototype.getRedeem = async function getRedeem(hash) { - let ring; - if (typeof hash === 'string') hash = Buffer.from(hash, 'hex'); - ring = await this.getKey(hash.toString('hex')); + const ring = await this.getKey(hash.toString('hex')); if (!ring) - return; + return null; return ring.getRedeem(hash); }; @@ -2049,7 +2006,7 @@ Wallet.prototype.getRedeem = async function getRedeem(hash) { */ Wallet.prototype.template = async function template(mtx) { - let rings = await this.deriveInputs(mtx); + const rings = await this.deriveInputs(mtx); return mtx.template(rings); }; @@ -2063,14 +2020,12 @@ Wallet.prototype.template = async function template(mtx) { */ Wallet.prototype.sign = async function sign(mtx, passphrase) { - let rings; - if (this.watchOnly) throw new Error('Cannot sign from a watch-only wallet.'); await this.unlock(passphrase); - rings = await this.deriveInputs(mtx); + const rings = await this.deriveInputs(mtx); return await mtx.signAsync(rings, Script.hashType.ALL, this.db.workers); }; @@ -2162,7 +2117,7 @@ Wallet.prototype.getBlock = function getBlock(height) { */ Wallet.prototype.add = async function add(tx, block) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._add(tx, block); } finally { @@ -2178,14 +2133,14 @@ Wallet.prototype.add = async function add(tx, block) { * @returns {Promise} */ -Wallet.prototype._add = async function add(tx, block) { - let details, derived; - +Wallet.prototype._add = async function _add(tx, block) { this.txdb.start(); + let details, derived; try { details = await this.txdb._add(tx, block); - derived = await this.syncOutputDepth(details); + if (details) + derived = await this.syncOutputDepth(details); } catch (e) { this.txdb.drop(); throw e; @@ -2193,7 +2148,7 @@ Wallet.prototype._add = async function add(tx, block) { await this.txdb.commit(); - if (derived.length > 0) { + if (derived && derived.length > 0) { this.db.emit('address', this.id, derived); this.emit('address', derived); } @@ -2208,7 +2163,7 @@ Wallet.prototype._add = async function add(tx, block) { */ Wallet.prototype.unconfirm = async function unconfirm(hash) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this.txdb.unconfirm(hash); } finally { @@ -2223,7 +2178,7 @@ Wallet.prototype.unconfirm = async function unconfirm(hash) { */ Wallet.prototype.remove = async function remove(hash) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this.txdb.remove(hash); } finally { @@ -2239,7 +2194,7 @@ Wallet.prototype.remove = async function remove(hash) { */ Wallet.prototype.zap = async function zap(acct, age) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._zap(acct, age); } finally { @@ -2255,8 +2210,8 @@ Wallet.prototype.zap = async function zap(acct, age) { * @returns {Promise} */ -Wallet.prototype._zap = async function zap(acct, age) { - let account = await this.ensureIndex(acct); +Wallet.prototype._zap = async function _zap(acct, age) { + const account = await this.ensureIndex(acct); return await this.txdb.zap(account, age); }; @@ -2267,7 +2222,7 @@ Wallet.prototype._zap = async function zap(acct, age) { */ Wallet.prototype.abandon = async function abandon(hash) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._abandon(hash); } finally { @@ -2282,7 +2237,7 @@ Wallet.prototype.abandon = async function abandon(hash) { * @returns {Promise} */ -Wallet.prototype._abandon = function abandon(hash) { +Wallet.prototype._abandon = function _abandon(hash) { return this.txdb.abandon(hash); }; @@ -2329,7 +2284,7 @@ Wallet.prototype.getLocked = function getLocked() { */ Wallet.prototype.getHistory = async function getHistory(acct) { - let account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return this.txdb.getHistory(account); }; @@ -2340,7 +2295,7 @@ Wallet.prototype.getHistory = async function getHistory(acct) { */ Wallet.prototype.getCoins = async function getCoins(acct) { - let account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return await this.txdb.getCoins(account); }; @@ -2351,7 +2306,7 @@ Wallet.prototype.getCoins = async function getCoins(acct) { */ Wallet.prototype.getCredits = async function getCredits(acct) { - let account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return await this.txdb.getCredits(account); }; @@ -2362,11 +2317,11 @@ Wallet.prototype.getCredits = async function getCredits(acct) { */ Wallet.prototype.getSmartCoins = async function getSmartCoins(acct) { - let credits = await this.getCredits(acct); - let coins = []; + const credits = await this.getCredits(acct); + const coins = []; - for (let credit of credits) { - let coin = credit.coin; + for (const credit of credits) { + const coin = credit.coin; if (credit.spent) continue; @@ -2401,7 +2356,7 @@ Wallet.prototype.getSmartCoins = async function getSmartCoins(acct) { */ Wallet.prototype.getPending = async function getPending(acct) { - let account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return await this.txdb.getPending(account); }; @@ -2412,7 +2367,7 @@ Wallet.prototype.getPending = async function getPending(acct) { */ Wallet.prototype.getBalance = async function getBalance(acct) { - let account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return await this.txdb.getBalance(account); }; @@ -2426,12 +2381,11 @@ Wallet.prototype.getBalance = async function getBalance(acct) { */ Wallet.prototype.getRange = async function getRange(acct, options) { - let account; if (acct && typeof acct === 'object') { options = acct; acct = null; } - account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return await this.txdb.getRange(account, options); }; @@ -2443,7 +2397,7 @@ Wallet.prototype.getRange = async function getRange(acct, options) { */ Wallet.prototype.getLast = async function getLast(acct, limit) { - let account = await this.ensureIndex(acct); + const account = await this.ensureIndex(acct); return await this.txdb.getLast(account, limit); }; @@ -2456,15 +2410,13 @@ Wallet.prototype.getLast = async function getLast(acct, limit) { */ Wallet.prototype.ensureIndex = async function ensureIndex(acct, enforce) { - let index; - if (acct == null) { if (enforce) throw new Error('No account provided.'); return null; } - index = await this.getAccountIndex(acct); + const index = await this.getAccountIndex(acct); if (index === -1) throw new Error('Account not found.'); @@ -2575,8 +2527,8 @@ Wallet.prototype.getSize = function getSize() { */ Wallet.prototype.toRaw = function toRaw() { - let size = this.getSize(); - let bw = new StaticWriter(size); + const size = this.getSize(); + const bw = new StaticWriter(size); bw.writeU32(this.network.magic); bw.writeU32(this.wid); @@ -2598,8 +2550,8 @@ Wallet.prototype.toRaw = function toRaw() { */ Wallet.prototype.fromRaw = function fromRaw(data) { - let br = new BufferReader(data); - let network = Network.fromMagic(br.readU32()); + const br = new BufferReader(data); + const network = Network.fromMagic(br.readU32()); this.wid = br.readU32(); this.id = br.readVarString('ascii'); diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 7e6376257..f2f2c4ff0 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -62,7 +62,11 @@ function WalletDB(options) { this.network = this.options.network; this.logger = this.options.logger.context('wallet'); + this.workers = this.options.workers; + this.client = this.options.client; + this.feeRate = this.options.feeRate; + this.db = LDB(this.options); this.rpc = new RPC(this); this.primary = null; @@ -101,7 +105,7 @@ function WalletDB(options) { this._init(); } -util.inherits(WalletDB, AsyncObject); +Object.setPrototypeOf(WalletDB.prototype, AsyncObject.prototype); /** * Database layout. @@ -138,9 +142,7 @@ WalletDB.prototype._init = function _init() { * @returns {Promise} */ -WalletDB.prototype._open = async function open() { - let wallet; - +WalletDB.prototype._open = async function _open() { if (this.options.listen) await this.logger.open(); @@ -160,7 +162,7 @@ WalletDB.prototype._open = async function open() { this.state.height, this.state.startHeight); - wallet = await this.ensure({ + const wallet = await this.ensure({ id: 'primary' }); @@ -181,15 +183,13 @@ WalletDB.prototype._open = async function open() { * @returns {Promise} */ -WalletDB.prototype._close = async function close() { - let wallet; - +WalletDB.prototype._close = async function _close() { await this.disconnect(); if (this.http && this.options.listen) await this.http.close(); - for (wallet of this.wallets.values()) + for (const wallet of this.wallets.values()) await wallet.destroy(); await this.db.close(); @@ -204,7 +204,7 @@ WalletDB.prototype._close = async function close() { */ WalletDB.prototype.load = async function load() { - let unlock = await this.txLock.lock(); + const unlock = await this.txLock.lock(); try { await this.connect(); await this.init(); @@ -308,15 +308,15 @@ WalletDB.prototype.disconnect = async function disconnect() { */ WalletDB.prototype.init = async function init() { - let state = await this.getState(); - let startHeight = this.options.startHeight; - let tip; + const state = await this.getState(); + const startHeight = this.options.startHeight; if (state) { this.state = state; return; } + let tip; if (this.client) { if (startHeight != null) { tip = await this.client.getEntry(startHeight); @@ -344,23 +344,22 @@ WalletDB.prototype.init = async function init() { */ WalletDB.prototype.watch = async function watch() { - let hashes = 0; - let outpoints = 0; - let iter; - - iter = this.db.iterator({ + let iter = this.db.iterator({ gte: layout.p(encoding.NULL_HASH), lte: layout.p(encoding.HIGH_HASH) }); + let hashes = 0; + let outpoints = 0; + for (;;) { - let item = await iter.next(); + const item = await iter.next(); if (!item) break; try { - let data = layout.pp(item.key); + const data = layout.pp(item.key); this.filter.add(data, 'hex'); } catch (e) { await iter.end(); @@ -376,15 +375,15 @@ WalletDB.prototype.watch = async function watch() { }); for (;;) { - let item = await iter.next(); + const item = await iter.next(); if (!item) break; try { - let [hash, index] = layout.oo(item.key); - let outpoint = new Outpoint(hash, index); - let data = outpoint.toRaw(); + const [hash, index] = layout.oo(item.key); + const outpoint = new Outpoint(hash, index); + const data = outpoint.toRaw(); this.filter.add(data); } catch (e) { await iter.end(); @@ -407,14 +406,14 @@ WalletDB.prototype.watch = async function watch() { */ WalletDB.prototype.sync = async function sync() { - let height = this.state.height; - let entry; - if (!this.client) return; + let height = this.state.height; + let entry; + while (height >= 0) { - let tip = await this.getBlock(height); + const tip = await this.getBlock(height); if (!tip) break; @@ -446,15 +445,13 @@ WalletDB.prototype.sync = async function sync() { */ WalletDB.prototype.scan = async function scan(height) { - let tip; - if (!this.client) return; if (height == null) height = this.state.startHeight; - assert(util.isUInt32(height), 'WDB: Must pass in a height.'); + assert(util.isU32(height), 'WDB: Must pass in a height.'); await this.rollback(height); @@ -462,7 +459,7 @@ WalletDB.prototype.scan = async function scan(height) { 'WalletDB is scanning %d blocks.', this.state.height - height + 1); - tip = await this.getTip(); + const tip = await this.getTip(); try { this.rescanning = true; @@ -479,7 +476,7 @@ WalletDB.prototype.scan = async function scan(height) { */ WalletDB.prototype.rescan = async function rescan(height) { - let unlock = await this.txLock.lock(); + const unlock = await this.txLock.lock(); try { return await this._rescan(height); } finally { @@ -494,7 +491,7 @@ WalletDB.prototype.rescan = async function rescan(height) { * @returns {Promise} */ -WalletDB.prototype._rescan = async function rescan(height) { +WalletDB.prototype._rescan = async function _rescan(height) { return await this.scan(height); }; @@ -520,12 +517,13 @@ WalletDB.prototype.send = async function send(tx) { */ WalletDB.prototype.estimateFee = async function estimateFee(blocks) { - let rate; + if (this.feeRate > 0) + return this.feeRate; if (!this.client) return this.network.feeRate; - rate = await this.client.estimateFee(blocks); + const rate = await this.client.estimateFee(blocks); if (rate < this.network.feeRate) return this.network.feeRate; @@ -598,20 +596,19 @@ WalletDB.prototype.backup = function backup(path) { */ WalletDB.prototype.wipe = async function wipe() { - let batch = this.db.batch(); - let total = 0; - let iter; - this.logger.warning('Wiping WalletDB TXDB...'); this.logger.warning('I hope you know what you\'re doing.'); - iter = this.db.iterator({ + const iter = this.db.iterator({ gte: Buffer.from([0x00]), lte: Buffer.from([0xff]) }); + const batch = this.db.batch(); + let total = 0; + for (;;) { - let item = await iter.next(); + const item = await iter.next(); if (!item) break; @@ -647,8 +644,6 @@ WalletDB.prototype.wipe = async function wipe() { */ WalletDB.prototype.getDepth = async function getDepth() { - let iter, item, depth; - // This may seem like a strange way to do // this, but updating a global state when // creating a new wallet is actually pretty @@ -658,21 +653,21 @@ WalletDB.prototype.getDepth = async function getDepth() { // nonsense of adding a global lock to // walletdb.create by simply seeking to the // highest wallet wid. - iter = this.db.iterator({ + const iter = this.db.iterator({ gte: layout.w(0x00000000), lte: layout.w(0xffffffff), reverse: true, limit: 1 }); - item = await iter.next(); + const item = await iter.next(); if (!item) return 1; await iter.end(); - depth = layout.ww(item.key); + const depth = layout.ww(item.key); return depth + 1; }; @@ -698,7 +693,7 @@ WalletDB.prototype.start = function start(wallet) { */ WalletDB.prototype.drop = function drop(wallet) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); wallet.current = null; wallet.accountCache.drop(); wallet.pathCache.drop(); @@ -712,7 +707,7 @@ WalletDB.prototype.drop = function drop(wallet) { */ WalletDB.prototype.clear = function clear(wallet) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); wallet.accountCache.clear(); wallet.pathCache.clear(); batch.clear(); @@ -738,7 +733,7 @@ WalletDB.prototype.batch = function batch(wallet) { */ WalletDB.prototype.commit = async function commit(wallet) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); try { await batch.write(); @@ -784,7 +779,7 @@ WalletDB.prototype.addHash = function addHash(hash) { */ WalletDB.prototype.addOutpoint = function addOutpoint(hash, index) { - let outpoint = new Outpoint(hash, index); + const outpoint = new Outpoint(hash, index); this.filter.add(outpoint.toRaw()); }; @@ -825,25 +820,23 @@ WalletDB.prototype.unregister = function unregister(wallet) { */ WalletDB.prototype.getWalletID = async function getWalletID(id) { - let wid, data; - if (!id) - return; + return null; if (typeof id === 'number') return id; - wid = this.widCache.get(id); + const cache = this.widCache.get(id); - if (wid) - return wid; + if (cache) + return cache; - data = await this.db.get(layout.l(id)); + const data = await this.db.get(layout.l(id)); if (!data) - return; + return null; - wid = data.readUInt32LE(0, true); + const wid = data.readUInt32LE(0, true); this.widCache.set(id, wid); @@ -857,13 +850,12 @@ WalletDB.prototype.getWalletID = async function getWalletID(id) { */ WalletDB.prototype.get = async function get(id) { - let wid = await this.getWalletID(id); - let unlock; + const wid = await this.getWalletID(id); if (!wid) - return; + return null; - unlock = await this.readLock.lock(wid); + const unlock = await this.readLock.lock(wid); try { return await this._get(wid); @@ -879,19 +871,18 @@ WalletDB.prototype.get = async function get(id) { * @returns {Promise} - Returns {@link Wallet}. */ -WalletDB.prototype._get = async function get(wid) { - let wallet = this.wallets.get(wid); - let data; +WalletDB.prototype._get = async function _get(wid) { + const cache = this.wallets.get(wid); - if (wallet) - return wallet; + if (cache) + return cache; - data = await this.db.get(layout.w(wid)); + const data = await this.db.get(layout.w(wid)); if (!data) - return; + return null; - wallet = Wallet.fromRaw(this, data); + const wallet = Wallet.fromRaw(this, data); await wallet.open(); @@ -906,9 +897,9 @@ WalletDB.prototype._get = async function get(wid) { */ WalletDB.prototype.save = function save(wallet) { - let wid = wallet.wid; - let id = wallet.id; - let batch = this.batch(wallet); + const wid = wallet.wid; + const id = wallet.id; + const batch = this.batch(wallet); this.widCache.set(id, wid); @@ -924,7 +915,7 @@ WalletDB.prototype.save = function save(wallet) { */ WalletDB.prototype.rename = async function rename(wallet, id) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); try { return await this._rename(wallet, id); } finally { @@ -941,8 +932,7 @@ WalletDB.prototype.rename = async function rename(wallet, id) { */ WalletDB.prototype._rename = async function _rename(wallet, id) { - let old = wallet.id; - let paths, batch; + const old = wallet.id; if (!common.isName(id)) throw new Error('WDB: Bad wallet ID.'); @@ -950,7 +940,7 @@ WalletDB.prototype._rename = async function _rename(wallet, id) { if (await this.has(id)) throw new Error('WDB: ID not available.'); - batch = this.start(wallet); + const batch = this.start(wallet); batch.del(layout.l(old)); wallet.id = id; @@ -961,9 +951,9 @@ WalletDB.prototype._rename = async function _rename(wallet, id) { this.widCache.remove(old); - paths = wallet.pathCache.values(); + const paths = wallet.pathCache.values(); - for (let path of paths) + for (const path of paths) path.id = id; }; @@ -974,8 +964,8 @@ WalletDB.prototype._rename = async function _rename(wallet, id) { */ WalletDB.prototype.renameAccount = function renameAccount(account, name) { - let wallet = account.wallet; - let batch = this.batch(wallet); + const wallet = account.wallet; + const batch = this.batch(wallet); // Remove old wid/name->account index. batch.del(layout.i(account.wid, account.name)); @@ -993,10 +983,10 @@ WalletDB.prototype.renameAccount = function renameAccount(account, name) { */ WalletDB.prototype.auth = async function auth(wid, token) { - let wallet = await this.get(wid); + const wallet = await this.get(wid); if (!wallet) - return; + return null; if (typeof token === 'string') { if (!util.isHex256(token)) @@ -1018,7 +1008,7 @@ WalletDB.prototype.auth = async function auth(wid, token) { */ WalletDB.prototype.create = async function create(options) { - let unlock = await this.writeLock.lock(); + const unlock = await this.writeLock.lock(); if (!options) options = {}; @@ -1037,14 +1027,13 @@ WalletDB.prototype.create = async function create(options) { * @returns {Promise} - Returns {@link Wallet}. */ -WalletDB.prototype._create = async function create(options) { - let exists = await this.has(options.id); - let wallet; +WalletDB.prototype._create = async function _create(options) { + const exists = await this.has(options.id); if (exists) throw new Error('WDB: Wallet already exists.'); - wallet = Wallet.fromOptions(this, options); + const wallet = Wallet.fromOptions(this, options); wallet.wid = this.depth++; await wallet.init(options); @@ -1063,7 +1052,7 @@ WalletDB.prototype._create = async function create(options) { */ WalletDB.prototype.has = async function has(id) { - let wid = await this.getWalletID(id); + const wid = await this.getWalletID(id); return wid != null; }; @@ -1074,9 +1063,11 @@ WalletDB.prototype.has = async function has(id) { */ WalletDB.prototype.ensure = async function ensure(options) { - let wallet = await this.get(options.id); + const wallet = await this.get(options.id); + if (wallet) return wallet; + return await this.create(options); }; @@ -1089,10 +1080,10 @@ WalletDB.prototype.ensure = async function ensure(options) { */ WalletDB.prototype.getAccount = async function getAccount(wid, index) { - let data = await this.db.get(layout.a(wid, index)); + const data = await this.db.get(layout.a(wid, index)); if (!data) - return; + return null; return Account.fromRaw(this, data); }; @@ -1119,7 +1110,7 @@ WalletDB.prototype.getAccounts = function getAccounts(wid) { */ WalletDB.prototype.getAccountIndex = async function getAccountIndex(wid, name) { - let index = await this.db.get(layout.i(wid, name)); + const index = await this.db.get(layout.i(wid, name)); if (!index) return -1; @@ -1135,10 +1126,10 @@ WalletDB.prototype.getAccountIndex = async function getAccountIndex(wid, name) { */ WalletDB.prototype.getAccountName = async function getAccountName(wid, index) { - let name = await this.db.get(layout.n(wid, index)); + const name = await this.db.get(layout.n(wid, index)); if (!name) - return; + return null; return name.toString('ascii'); }; @@ -1150,11 +1141,11 @@ WalletDB.prototype.getAccountName = async function getAccountName(wid, index) { */ WalletDB.prototype.saveAccount = function saveAccount(account) { - let wid = account.wid; - let wallet = account.wallet; - let index = account.accountIndex; - let name = account.name; - let batch = this.batch(wallet); + const wid = account.wid; + const wallet = account.wallet; + const index = account.accountIndex; + const name = account.name; + const batch = this.batch(wallet); // Account data batch.put(layout.a(wid, index), account.toRaw()); @@ -1187,18 +1178,17 @@ WalletDB.prototype.hasAccount = function hasAccount(wid, index) { */ WalletDB.prototype.getPathMap = async function getPathMap(hash) { - let map = this.pathMapCache.get(hash); - let data; + const cache = this.pathMapCache.get(hash); - if (map) - return map; + if (cache) + return cache; - data = await this.db.get(layout.p(hash)); + const data = await this.db.get(layout.p(hash)); if (!data) - return; + return null; - map = PathMapRecord.fromRaw(hash, data); + const map = PathMapRecord.fromRaw(hash, data); this.pathMapCache.set(hash, map); @@ -1230,14 +1220,13 @@ WalletDB.prototype.saveKey = function saveKey(wallet, ring) { */ WalletDB.prototype.savePath = async function savePath(wallet, path) { - let wid = wallet.wid; - let hash = path.hash; - let batch = this.batch(wallet); - let map; + const wid = wallet.wid; + const hash = path.hash; + const batch = this.batch(wallet); await this.addHash(hash); - map = await this.getPathMap(hash); + let map = await this.getPathMap(hash); if (!map) map = new PathMapRecord(hash); @@ -1266,13 +1255,12 @@ WalletDB.prototype.savePath = async function savePath(wallet, path) { */ WalletDB.prototype.getPath = async function getPath(wid, hash) { - let data = await this.db.get(layout.P(wid, hash)); - let path; + const data = await this.db.get(layout.P(wid, hash)); if (!data) - return; + return null; - path = Path.fromRaw(data); + const path = Path.fromRaw(data); path.wid = wid; path.hash = hash; @@ -1313,7 +1301,7 @@ WalletDB.prototype.getOutpoints = function getOutpoints() { gte: layout.o(encoding.NULL_HASH, 0), lte: layout.o(encoding.HIGH_HASH, 0xffffffff), parse: (key) => { - let [hash, index] = layout.oo(key); + const [hash, index] = layout.oo(key); return new Outpoint(hash, index); } }); @@ -1355,16 +1343,16 @@ WalletDB.prototype.getAccountHashes = function getAccountHashes(wid, account) { */ WalletDB.prototype.getWalletPaths = async function getWalletPaths(wid) { - let paths = []; - - let items = await this.db.range({ + const items = await this.db.range({ gte: layout.P(wid, encoding.NULL_HASH), lte: layout.P(wid, encoding.HIGH_HASH) }); - for (let item of items) { - let hash = layout.Pp(item.key); - let path = Path.fromRaw(item.value); + const paths = []; + + for (const item of items) { + const hash = layout.Pp(item.key); + const path = Path.fromRaw(item.value); path.hash = hash; path.wid = wid; @@ -1396,20 +1384,18 @@ WalletDB.prototype.getWallets = function getWallets() { */ WalletDB.prototype.encryptKeys = async function encryptKeys(wallet, key) { - let wid = wallet.wid; - let paths = await wallet.getPaths(); - let batch = this.batch(wallet); + const wid = wallet.wid; + const paths = await wallet.getPaths(); + const batch = this.batch(wallet); for (let path of paths) { - let iv; - if (!path.data) continue; assert(!path.encrypted); - iv = Buffer.from(path.hash, 'hex'); - iv = iv.slice(0, 16); + const hash = Buffer.from(path.hash, 'hex'); + const iv = hash.slice(0, 16); path = path.clone(); path.data = aes.encipher(path.data, key, iv); @@ -1429,20 +1415,18 @@ WalletDB.prototype.encryptKeys = async function encryptKeys(wallet, key) { */ WalletDB.prototype.decryptKeys = async function decryptKeys(wallet, key) { - let wid = wallet.wid; - let paths = await wallet.getPaths(); - let batch = this.batch(wallet); + const wid = wallet.wid; + const paths = await wallet.getPaths(); + const batch = this.batch(wallet); for (let path of paths) { - let iv; - if (!path.data) continue; assert(path.encrypted); - iv = Buffer.from(path.hash, 'hex'); - iv = iv.slice(0, 16); + const hash = Buffer.from(path.hash, 'hex'); + const iv = hash.slice(0, 16); path = path.clone(); path.data = aes.decipher(path.data, key, iv); @@ -1460,15 +1444,13 @@ WalletDB.prototype.decryptKeys = async function decryptKeys(wallet, key) { */ WalletDB.prototype.resend = async function resend() { - let keys, key, wid; - - keys = await this.db.keys({ + const keys = await this.db.keys({ gte: layout.w(0x00000000), lte: layout.w(0xffffffff) }); - for (key of keys) { - wid = layout.ww(key); + for (const key of keys) { + const wid = layout.ww(key); await this.resendPending(wid); } }; @@ -1481,11 +1463,9 @@ WalletDB.prototype.resend = async function resend() { */ WalletDB.prototype.resendPending = async function resendPending(wid) { - let layout = layouts.txdb; - let txs = []; - let keys; + const layout = layouts.txdb; - keys = await this.db.keys({ + const keys = await this.db.keys({ gte: layout.prefix(wid, layout.p(encoding.NULL_HASH)), lte: layout.prefix(wid, layout.p(encoding.HIGH_HASH)) }); @@ -1498,16 +1478,17 @@ WalletDB.prototype.resendPending = async function resendPending(wid) { keys.length, wid); - for (let key of keys) { - let hash = layout.pp(key); - let tkey = layout.prefix(wid, layout.t(hash)); - let data = await this.db.get(tkey); - let wtx; + const txs = []; + + for (const key of keys) { + const hash = layout.pp(key); + const tkey = layout.prefix(wid, layout.t(hash)); + const data = await this.db.get(tkey); if (!data) continue; - wtx = TXRecord.fromRaw(data); + const wtx = TXRecord.fromRaw(data); if (wtx.tx.isCoinbase()) continue; @@ -1515,9 +1496,9 @@ WalletDB.prototype.resendPending = async function resendPending(wid) { txs.push(wtx.tx); } - txs = common.sortDeps(txs); + const sorted = common.sortDeps(txs); - for (let tx of txs) + for (const tx of sorted) await this.send(tx); }; @@ -1528,44 +1509,41 @@ WalletDB.prototype.resendPending = async function resendPending(wid) { */ WalletDB.prototype.getWalletsByTX = async function getWalletsByTX(tx) { - let hashes = tx.getOutputHashes('hex'); - let result = []; + const hashes = tx.getOutputHashes('hex'); + const result = new Set(); if (!tx.isCoinbase()) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let map; + for (const input of tx.inputs) { + const prevout = input.prevout; if (!this.testFilter(prevout.toRaw())) continue; - map = await this.getOutpointMap(prevout.hash, prevout.index); + const map = await this.getOutpointMap(prevout.hash, prevout.index); if (!map) continue; - for (let wid of map.wids) - util.binaryInsert(result, wid, cmp, true); + for (const wid of map.wids) + result.add(wid); } } - for (let hash of hashes) { - let map; - + for (const hash of hashes) { if (!this.testFilter(hash)) continue; - map = await this.getPathMap(hash); + const map = await this.getPathMap(hash); if (!map) continue; - for (let wid of map.wids) - util.binaryInsert(result, wid, cmp, true); + for (const wid of map.wids) + result.add(wid); } - if (result.length === 0) - return; + if (result.size === 0) + return null; return result; }; @@ -1576,10 +1554,10 @@ WalletDB.prototype.getWalletsByTX = async function getWalletsByTX(tx) { */ WalletDB.prototype.getState = async function getState() { - let data = await this.db.get(layout.R); + const data = await this.db.get(layout.R); if (!data) - return; + return null; return ChainState.fromRaw(data); }; @@ -1591,18 +1569,17 @@ WalletDB.prototype.getState = async function getState() { */ WalletDB.prototype.resetState = async function resetState(tip, marked) { - let batch = this.db.batch(); - let state = this.state.clone(); - let iter; + const batch = this.db.batch(); + const state = this.state.clone(); - iter = this.db.iterator({ + const iter = this.db.iterator({ gte: layout.h(0), lte: layout.h(0xffffffff), values: false }); for (;;) { - let item = await iter.next(); + const item = await iter.next(); if (!item) break; @@ -1635,8 +1612,8 @@ WalletDB.prototype.resetState = async function resetState(tip, marked) { */ WalletDB.prototype.syncState = async function syncState(tip) { - let batch = this.db.batch(); - let state = this.state.clone(); + const batch = this.db.batch(); + const state = this.state.clone(); if (tip.height < state.height) { // Hashes ahead of our new tip @@ -1653,7 +1630,7 @@ WalletDB.prototype.syncState = async function syncState(tip) { } } else if (tip.height > state.height) { // Prune old hashes. - let height = tip.height - this.options.keepBlocks; + const height = tip.height - this.options.keepBlocks; assert(tip.height === state.height + 1, 'Bad chain sync.'); @@ -1695,10 +1672,10 @@ WalletDB.prototype.maybeMark = async function maybeMark(tip) { */ WalletDB.prototype.getBlockMap = async function getBlockMap(height) { - let data = await this.db.get(layout.b(height)); + const data = await this.db.get(layout.b(height)); if (!data) - return; + return null; return BlockMapRecord.fromRaw(height, data); }; @@ -1711,7 +1688,7 @@ WalletDB.prototype.getBlockMap = async function getBlockMap(height) { */ WalletDB.prototype.writeBlockMap = function writeBlockMap(wallet, height, block) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); batch.put(layout.b(height), block.toRaw()); }; @@ -1722,7 +1699,7 @@ WalletDB.prototype.writeBlockMap = function writeBlockMap(wallet, height, block) */ WalletDB.prototype.unwriteBlockMap = function unwriteBlockMap(wallet, height) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); batch.del(layout.b(height)); }; @@ -1734,10 +1711,10 @@ WalletDB.prototype.unwriteBlockMap = function unwriteBlockMap(wallet, height) { */ WalletDB.prototype.getOutpointMap = async function getOutpointMap(hash, index) { - let data = await this.db.get(layout.o(hash, index)); + const data = await this.db.get(layout.o(hash, index)); if (!data) - return; + return null; return OutpointMapRecord.fromRaw(hash, index, data); }; @@ -1751,7 +1728,7 @@ WalletDB.prototype.getOutpointMap = async function getOutpointMap(hash, index) { */ WalletDB.prototype.writeOutpointMap = function writeOutpointMap(wallet, hash, index, map) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); this.addOutpoint(hash, index); @@ -1766,7 +1743,7 @@ WalletDB.prototype.writeOutpointMap = function writeOutpointMap(wallet, hash, in */ WalletDB.prototype.unwriteOutpointMap = function unwriteOutpointMap(wallet, hash, index) { - let batch = this.batch(wallet); + const batch = this.batch(wallet); batch.del(layout.o(hash, index)); }; @@ -1777,13 +1754,12 @@ WalletDB.prototype.unwriteOutpointMap = function unwriteOutpointMap(wallet, hash */ WalletDB.prototype.getBlock = async function getBlock(height) { - let data = await this.db.get(layout.h(height)); - let block; + const data = await this.db.get(layout.h(height)); if (!data) - return; + return null; - block = new BlockMeta(); + const block = new BlockMeta(); block.hash = data.toString('hex'); block.height = height; @@ -1797,7 +1773,7 @@ WalletDB.prototype.getBlock = async function getBlock(height) { */ WalletDB.prototype.getTip = async function getTip() { - let tip = await this.getBlock(this.state.height); + const tip = await this.getBlock(this.state.height); if (!tip) throw new Error('WDB: Tip not found!'); @@ -1812,8 +1788,6 @@ WalletDB.prototype.getTip = async function getTip() { */ WalletDB.prototype.rollback = async function rollback(height) { - let tip, marked; - if (height > this.state.height) throw new Error('WDB: Cannot rollback to the future.'); @@ -1826,7 +1800,8 @@ WalletDB.prototype.rollback = async function rollback(height) { 'Rolling back %d WalletDB blocks to height %d.', this.state.height - height, height); - tip = await this.getBlock(height); + let tip = await this.getBlock(height); + let marked = false; if (tip) { await this.revert(tip.height); @@ -1865,30 +1840,30 @@ WalletDB.prototype.rollback = async function rollback(height) { */ WalletDB.prototype.revert = async function revert(target) { - let total = 0; - let iter; - - iter = this.db.iterator({ + const iter = this.db.iterator({ gte: layout.b(target + 1), lte: layout.b(0xffffffff), reverse: true, values: true }); + let total = 0; + for (;;) { - let item = await iter.next(); + const item = await iter.next(); if (!item) break; try { - let height = layout.bb(item.key); - let block = BlockMapRecord.fromRaw(height, item.value); + const height = layout.bb(item.key); + const block = BlockMapRecord.fromRaw(height, item.value); + const txs = block.toArray(); - total += block.txs.length; + total += txs.length; - for (let i = block.txs.length - 1; i >= 0; i--) { - let tx = block.txs[i]; + for (let i = txs.length - 1; i >= 0; i--) { + const tx = txs[i]; await this._unconfirm(tx); } } catch (e) { @@ -1907,7 +1882,7 @@ WalletDB.prototype.revert = async function revert(target) { */ WalletDB.prototype.addBlock = async function addBlock(entry, txs) { - let unlock = await this.txLock.lock(); + const unlock = await this.txLock.lock(); try { return await this._addBlock(entry, txs); } finally { @@ -1923,10 +1898,9 @@ WalletDB.prototype.addBlock = async function addBlock(entry, txs) { * @returns {Promise} */ -WalletDB.prototype._addBlock = async function addBlock(entry, txs) { - let tip = BlockMeta.fromEntry(entry); +WalletDB.prototype._addBlock = async function _addBlock(entry, txs) { + const tip = BlockMeta.fromEntry(entry); let total = 0; - let tx; if (tip.height < this.state.height) { this.logger.warning( @@ -1955,7 +1929,7 @@ WalletDB.prototype._addBlock = async function addBlock(entry, txs) { return total; } - for (tx of txs) { + for (const tx of txs) { if (await this._insert(tx, tip)) total++; } @@ -1976,7 +1950,7 @@ WalletDB.prototype._addBlock = async function addBlock(entry, txs) { */ WalletDB.prototype.removeBlock = async function removeBlock(entry) { - let unlock = await this.txLock.lock(); + const unlock = await this.txLock.lock(); try { return await this._removeBlock(entry); } finally { @@ -1991,9 +1965,8 @@ WalletDB.prototype.removeBlock = async function removeBlock(entry) { * @returns {Promise} */ -WalletDB.prototype._removeBlock = async function removeBlock(entry) { - let tip = BlockMeta.fromEntry(entry); - let prev, block; +WalletDB.prototype._removeBlock = async function _removeBlock(entry) { + const tip = BlockMeta.fromEntry(entry); if (tip.height > this.state.height) { this.logger.warning( @@ -2005,21 +1978,23 @@ WalletDB.prototype._removeBlock = async function removeBlock(entry) { if (tip.height !== this.state.height) throw new Error('WDB: Bad disconnection (height mismatch).'); - prev = await this.getBlock(tip.height - 1); + const prev = await this.getBlock(tip.height - 1); if (!prev) throw new Error('WDB: Bad disconnection (no previous block).'); // Get the map of txids->wids. - block = await this.getBlockMap(tip.height); + const block = await this.getBlockMap(tip.height); if (!block) { await this.syncState(prev); return 0; } - for (let i = block.txs.length - 1; i >= 0; i--) { - let tx = block.txs[i]; + const txs = block.toArray(); + + for (let i = txs.length - 1; i >= 0; i--) { + const tx = txs[i]; await this._unconfirm(tx); } @@ -2027,9 +2002,9 @@ WalletDB.prototype._removeBlock = async function removeBlock(entry) { await this.syncState(prev); this.logger.warning('Disconnected wallet block %s (tx=%d).', - util.revHex(tip.hash), block.txs.length); + util.revHex(tip.hash), block.txs.size); - return block.txs.length; + return block.txs.size; }; /** @@ -2063,7 +2038,7 @@ WalletDB.prototype.rescanBlock = async function rescanBlock(entry, txs) { */ WalletDB.prototype.addTX = async function addTX(tx) { - let unlock = await this.txLock.lock(); + const unlock = await this.txLock.lock(); try { return await this._insert(tx); @@ -2080,18 +2055,18 @@ WalletDB.prototype.addTX = async function addTX(tx) { * @returns {Promise} */ -WalletDB.prototype._insert = async function insert(tx, block) { - let wids = await this.getWalletsByTX(tx); +WalletDB.prototype._insert = async function _insert(tx, block) { + const wids = await this.getWalletsByTX(tx); let result = false; assert(!tx.mutable, 'WDB: Cannot add mutable TX.'); if (!wids) - return; + return null; this.logger.info( 'Incoming transaction for %d wallets in WalletDB (%s).', - wids.length, tx.txid()); + wids.size, tx.txid()); // If this is our first transaction // in a block, set the start block here. @@ -2100,8 +2075,8 @@ WalletDB.prototype._insert = async function insert(tx, block) { // Insert the transaction // into every matching wallet. - for (let wid of wids) { - let wallet = await this.get(wid); + for (const wid of wids) { + const wallet = await this.get(wid); assert(wallet); @@ -2114,7 +2089,7 @@ WalletDB.prototype._insert = async function insert(tx, block) { } if (!result) - return; + return null; return wids; }; @@ -2127,9 +2102,9 @@ WalletDB.prototype._insert = async function insert(tx, block) { * @returns {Promise} */ -WalletDB.prototype._unconfirm = async function unconfirm(tx) { - for (let wid of tx.wids) { - let wallet = await this.get(wid); +WalletDB.prototype._unconfirm = async function _unconfirm(tx) { + for (const wid of tx.wids) { + const wallet = await this.get(wid); assert(wallet); await wallet.unconfirm(tx.hash); } @@ -2142,7 +2117,7 @@ WalletDB.prototype._unconfirm = async function unconfirm(tx) { */ WalletDB.prototype.resetChain = async function resetChain(entry) { - let unlock = await this.txLock.lock(); + const unlock = await this.txLock.lock(); try { return await this._resetChain(entry); } finally { @@ -2157,7 +2132,7 @@ WalletDB.prototype.resetChain = async function resetChain(entry) { * @returns {Promise} */ -WalletDB.prototype._resetChain = async function resetChain(entry) { +WalletDB.prototype._resetChain = async function _resetChain(entry) { if (entry.height > this.state.height) throw new Error('WDB: Bad reset height.'); @@ -2183,7 +2158,9 @@ function WalletOptions(options) { this.network = Network.primary; this.logger = Logger.global; + this.workers = null; this.client = null; + this.feeRate = 0; this.prefix = null; this.location = null; @@ -2230,11 +2207,21 @@ WalletOptions.prototype.fromOptions = function fromOptions(options) { this.logger = options.logger; } + if (options.workers != null) { + assert(typeof options.workers === 'object'); + this.workers = options.workers; + } + if (options.client != null) { assert(typeof options.client === 'object'); this.client = options.client; } + if (options.feeRate != null) { + assert(util.isU64(options.feeRate)); + this.feeRate = options.feeRate; + } + if (options.prefix != null) { assert(typeof options.prefix === 'string'); this.prefix = options.prefix; @@ -2252,12 +2239,12 @@ WalletOptions.prototype.fromOptions = function fromOptions(options) { } if (options.maxFiles != null) { - assert(util.isNumber(options.maxFiles)); + assert(util.isU32(options.maxFiles)); this.maxFiles = options.maxFiles; } if (options.cacheSize != null) { - assert(util.isNumber(options.cacheSize)); + assert(util.isU64(options.cacheSize)); this.cacheSize = options.cacheSize; } @@ -2340,14 +2327,6 @@ WalletOptions.fromOptions = function fromOptions(options) { return new WalletOptions().fromOptions(options); }; -/* - * Helpers - */ - -function cmp(a, b) { - return a - b; -} - /* * Expose */ diff --git a/lib/wallet/walletkey.js b/lib/wallet/walletkey.js index 215692c64..921523393 100644 --- a/lib/wallet/walletkey.js +++ b/lib/wallet/walletkey.js @@ -7,7 +7,6 @@ 'use strict'; -const util = require('../utils/util'); const Address = require('../primitives/address'); const KeyRing = require('../primitives/keyring'); const Path = require('./path'); @@ -35,7 +34,7 @@ function WalletKey(options, network) { this.index = -1; } -util.inherits(WalletKey, KeyRing); +Object.setPrototypeOf(WalletKey.prototype, KeyRing.prototype); /** * Instantiate key ring from options. @@ -262,7 +261,7 @@ WalletKey.fromRing = function fromRing(account, ring) { */ WalletKey.prototype.toPath = function toPath() { - let path = new Path(); + const path = new Path(); path.id = this.id; path.wid = this.wid; diff --git a/lib/workers/child-browser.js b/lib/workers/child-browser.js index aac029c12..8e10f85d2 100644 --- a/lib/workers/child-browser.js +++ b/lib/workers/child-browser.js @@ -8,7 +8,6 @@ const assert = require('assert'); const EventEmitter = require('events'); -const util = require('../utils/util'); /** * Represents a child process. @@ -27,7 +26,7 @@ function Child(file) { this.init(file); } -util.inherits(Child, EventEmitter); +Object.setPrototypeOf(Child.prototype, EventEmitter.prototype); /** * Test whether child process support is available. diff --git a/lib/workers/child.js b/lib/workers/child.js index 67dcf9ba8..f6df990d2 100644 --- a/lib/workers/child.js +++ b/lib/workers/child.js @@ -9,7 +9,6 @@ const EventEmitter = require('events'); const path = require('path'); const cp = require('child_process'); -const util = require('../utils/util'); const children = new Set(); let exitBound = false; @@ -33,7 +32,7 @@ function Child(file) { this.init(file); } -util.inherits(Child, EventEmitter); +Object.setPrototypeOf(Child.prototype, EventEmitter.prototype); /** * Test whether child process support is available. @@ -51,9 +50,9 @@ Child.hasSupport = function hasSupport() { */ Child.prototype.init = function init(file) { - let bin = process.argv[0]; - let filename = path.resolve(__dirname, file); - let options = { stdio: 'pipe', env: process.env }; + const bin = process.argv[0]; + const filename = path.resolve(__dirname, file); + const options = { stdio: 'pipe', env: process.env }; this.child = cp.spawn(bin, [filename], options); @@ -66,16 +65,11 @@ Child.prototype.init = function init(file) { this.emit('error', err); }); - this.child.on('exit', (code, signal) => { + this.child.once('exit', (code, signal) => { children.delete(this); this.emit('exit', code == null ? -1 : code, signal); }); - this.child.on('close', () => { - children.delete(this); - this.emit('exit', -1, null); - }); - this.child.stdin.on('error', (err) => { this.emit('error', err); }); @@ -123,7 +117,7 @@ function bindExit() { exitBound = true; listenExit(() => { - for (let child of children) + for (const child of children) child.destroy(); }); } @@ -135,23 +129,23 @@ function bindExit() { */ function listenExit(handler) { - let onSighup = () => { + const onSighup = () => { process.exit(1 | 0x80); }; - let onSigint = () => { + const onSigint = () => { process.exit(2 | 0x80); }; - let onSigterm = () => { + const onSigterm = () => { process.exit(15 | 0x80); }; - let onError = (err) => { + const onError = (err) => { if (err && err.stack) - console.error(err.stack + ''); + console.error(String(err.stack)); else - console.error(err + ''); + console.error(String(err)); process.exit(1); }; diff --git a/lib/workers/framer.js b/lib/workers/framer.js index d4b7303e5..720375b22 100644 --- a/lib/workers/framer.js +++ b/lib/workers/framer.js @@ -20,23 +20,22 @@ function Framer() { return new Framer(); } -Framer.prototype.packet = function _packet(packet) { - let size = 10 + packet.getSize(); - let bw = new StaticWriter(size); - let data; +Framer.prototype.packet = function packet(payload) { + const size = 10 + payload.getSize(); + const bw = new StaticWriter(size); - bw.writeU32(packet.id); - bw.writeU8(packet.cmd); + bw.writeU32(payload.id); + bw.writeU8(payload.cmd); bw.seek(4); - packet.toWriter(bw); + payload.toWriter(bw); bw.writeU8(0x0a); - data = bw.render(); - data.writeUInt32LE(data.length - 10, 5, true); + const msg = bw.render(); + msg.writeUInt32LE(msg.length - 10, 5, true); - return data; + return msg; }; /* diff --git a/lib/workers/jobs.js b/lib/workers/jobs.js index ff39037ce..5da2aec48 100644 --- a/lib/workers/jobs.js +++ b/lib/workers/jobs.js @@ -7,8 +7,8 @@ 'use strict'; const secp256k1 = require('../crypto/secp256k1'); -const scrypt = require('../crypto/scrypt'); -const mine = require('../mining/mine'); +const {derive} = require('../crypto/scrypt'); +const hashcash = require('../mining/mine'); const packets = require('./packets'); /** @@ -114,7 +114,7 @@ jobs.checkInput = function checkInput(tx, index, coin, flags) { */ jobs.sign = function sign(tx, ring, type) { - let total = tx.sign(ring, type); + const total = tx.sign(ring, type); return packets.SignResultPacket.fromTX(tx, total); }; @@ -129,7 +129,7 @@ jobs.sign = function sign(tx, ring, type) { */ jobs.signInput = function signInput(tx, index, coin, ring, type) { - let result = tx.signInput(tx, index, coin, ring, type); + const result = tx.signInput(tx, index, coin, ring, type); return packets.SignInputResultPacket.fromTX(tx, index, result); }; @@ -142,7 +142,7 @@ jobs.signInput = function signInput(tx, index, coin, ring, type) { */ jobs.ecVerify = function ecVerify(msg, sig, key) { - let result = secp256k1.verify(msg, sig, key); + const result = secp256k1.verify(msg, sig, key); return new packets.ECVerifyResultPacket(result); }; @@ -156,7 +156,7 @@ jobs.ecVerify = function ecVerify(msg, sig, key) { */ jobs.ecSign = function ecSign(msg, key) { - let sig = secp256k1.sign(msg, key); + const sig = secp256k1.sign(msg, key); return new packets.ECSignResultPacket(sig); }; @@ -169,8 +169,8 @@ jobs.ecSign = function ecSign(msg, key) { * @returns {Number} */ -jobs.mine = function _mine(data, target, min, max) { - let nonce = mine(data, target, min, max); +jobs.mine = function mine(data, target, min, max) { + const nonce = hashcash(data, target, min, max); return new packets.MineResultPacket(nonce); }; @@ -186,7 +186,7 @@ jobs.mine = function _mine(data, target, min, max) { * @returns {Buffer} */ -jobs.scrypt = function _scrypt(passwd, salt, N, r, p, len) { - let key = scrypt.derive(passwd, salt, N, r, p, len); +jobs.scrypt = function scrypt(passwd, salt, N, r, p, len) { + const key = derive(passwd, salt, N, r, p, len); return new packets.ScryptResultPacket(key); }; diff --git a/lib/workers/master.js b/lib/workers/master.js index b48c5174a..9cc109f60 100644 --- a/lib/workers/master.js +++ b/lib/workers/master.js @@ -38,7 +38,7 @@ function Master() { this.init(); } -util.inherits(Master, EventEmitter); +Object.setPrototypeOf(Master.prototype, EventEmitter.prototype); /** * Initialize master. Bind events. @@ -133,7 +133,7 @@ Master.prototype.destroy = function destroy() { */ Master.prototype.log = function log(...items) { - let text = util.format(items, this.color); + const text = util.format(items, this.color); this.send(new packets.LogPacket(text)); }; diff --git a/lib/workers/packets.js b/lib/workers/packets.js index 6721667c8..814663e50 100644 --- a/lib/workers/packets.js +++ b/lib/workers/packets.js @@ -11,7 +11,6 @@ */ const assert = require('assert'); -const util = require('../utils/util'); const BufferReader = require('../utils/reader'); const encoding = require('../utils/encoding'); const Script = require('../script/script'); @@ -21,7 +20,7 @@ const MTX = require('../primitives/mtx'); const TX = require('../primitives/tx'); const KeyRing = require('../primitives/keyring'); const CoinView = require('../coins/coinview'); -const {ScriptError} = require('../script/common'); +const ScriptError = require('../script/scripterror'); /* * Constants @@ -79,7 +78,7 @@ function EnvPacket(env) { this.json = JSON.stringify(this.env); } -util.inherits(EnvPacket, Packet); +Object.setPrototypeOf(EnvPacket.prototype, Packet.prototype); EnvPacket.prototype.cmd = packetTypes.ENV; @@ -92,8 +91,8 @@ EnvPacket.prototype.toWriter = function toWriter(bw) { }; EnvPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new EnvPacket(); + const br = new BufferReader(data, true); + const packet = new EnvPacket(); packet.json = br.readVarString('utf8'); packet.env = JSON.parse(packet.json); return packet; @@ -110,7 +109,7 @@ function EventPacket(items) { this.json = JSON.stringify(this.items); } -util.inherits(EventPacket, Packet); +Object.setPrototypeOf(EventPacket.prototype, Packet.prototype); EventPacket.prototype.cmd = packetTypes.EVENT; @@ -123,8 +122,8 @@ EventPacket.prototype.toWriter = function toWriter(bw) { }; EventPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new EventPacket(); + const br = new BufferReader(data, true); + const packet = new EventPacket(); packet.json = br.readVarString('utf8'); packet.items = JSON.parse(packet.json); return packet; @@ -140,7 +139,7 @@ function LogPacket(text) { this.text = text || ''; } -util.inherits(LogPacket, Packet); +Object.setPrototypeOf(LogPacket.prototype, Packet.prototype); LogPacket.prototype.cmd = packetTypes.LOG; @@ -153,8 +152,8 @@ LogPacket.prototype.toWriter = function toWriter(bw) { }; LogPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new LogPacket(); + const br = new BufferReader(data, true); + const packet = new LogPacket(); packet.text = br.readVarString('utf8'); return packet; }; @@ -169,15 +168,15 @@ function ErrorPacket(error) { this.error = error || new Error(); } -util.inherits(ErrorPacket, Packet); +Object.setPrototypeOf(ErrorPacket.prototype, Packet.prototype); ErrorPacket.prototype.cmd = packetTypes.ERROR; ErrorPacket.prototype.getSize = function getSize() { let size = 0; - size += encoding.sizeVarString(this.error.message + '', 'utf8'); - size += encoding.sizeVarString(this.error.stack + '', 'utf8'); + size += encoding.sizeVarString(String(this.error.message), 'utf8'); + size += encoding.sizeVarString(String(this.error.stack), 'utf8'); size += encoding.sizeVarString(this.error.type || '', 'utf8'); switch (typeof this.error.code) { @@ -198,14 +197,14 @@ ErrorPacket.prototype.getSize = function getSize() { }; ErrorPacket.prototype.toWriter = function toWriter(bw) { - bw.writeVarString(this.error.message + '', 'utf8'); - bw.writeVarString(this.error.stack + '', 'utf8'); + bw.writeVarString(String(this.error.message), 'utf8'); + bw.writeVarString(String(this.error.stack), 'utf8'); bw.writeVarString(this.error.type || '', 'utf8'); switch (typeof this.error.code) { case 'number': bw.writeU8(2); - bw.write32(this.error.code); + bw.writeI32(this.error.code); break; case 'string': bw.writeU8(1); @@ -218,8 +217,8 @@ ErrorPacket.prototype.toWriter = function toWriter(bw) { }; ErrorPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ErrorPacket(); + const br = new BufferReader(data, true); + const packet = new ErrorPacket(); packet.error.message = br.readVarString('utf8'); packet.error.stack = br.readVarString('utf8'); @@ -227,7 +226,7 @@ ErrorPacket.fromRaw = function fromRaw(data) { switch (br.readU8()) { case 2: - packet.error.code = br.read32(); + packet.error.code = br.readI32(); break; case 1: packet.error.code = br.readVarString('utf8'); @@ -249,10 +248,17 @@ function ErrorResultPacket(error) { ErrorPacket.call(this, error); } -util.inherits(ErrorResultPacket, ErrorPacket); +Object.setPrototypeOf(ErrorResultPacket.prototype, ErrorPacket.prototype); ErrorResultPacket.prototype.cmd = packetTypes.ERRORRESULT; +ErrorResultPacket.fromRaw = function fromRaw(data) { + const packet = new ErrorResultPacket(); + const p = ErrorPacket.fromRaw(data); + packet.error = p.error; + return packet; +}; + /** * CheckPacket * @constructor @@ -265,7 +271,7 @@ function CheckPacket(tx, view, flags) { this.flags = flags != null ? flags : null; } -util.inherits(CheckPacket, Packet); +Object.setPrototypeOf(CheckPacket.prototype, Packet.prototype); CheckPacket.prototype.cmd = packetTypes.CHECK; @@ -276,16 +282,16 @@ CheckPacket.prototype.getSize = function getSize() { CheckPacket.prototype.toWriter = function toWriter(bw) { this.tx.toWriter(bw); this.view.toWriter(bw, this.tx); - bw.write32(this.flags != null ? this.flags : -1); + bw.writeI32(this.flags != null ? this.flags : -1); }; CheckPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new CheckPacket(); + const br = new BufferReader(data, true); + const packet = new CheckPacket(); packet.tx = TX.fromReader(br); packet.view = CoinView.fromReader(br, packet.tx); - packet.flags = br.read32(); + packet.flags = br.readI32(); if (packet.flags === -1) packet.flags = null; @@ -303,12 +309,12 @@ function CheckResultPacket(error) { this.error = error || null; } -util.inherits(CheckResultPacket, Packet); +Object.setPrototypeOf(CheckResultPacket.prototype, Packet.prototype); CheckResultPacket.prototype.cmd = packetTypes.CHECKRESULT; CheckResultPacket.prototype.getSize = function getSize() { - let err = this.error; + const err = this.error; let size = 0; if (!err) { @@ -319,7 +325,7 @@ CheckResultPacket.prototype.getSize = function getSize() { size += 1; size += encoding.sizeVarString(err.code, 'utf8'); size += encoding.sizeVarString(err.message, 'utf8'); - size += encoding.sizeVarString(err.stack + '', 'utf8'); + size += encoding.sizeVarString(String(err.stack), 'utf8'); size += 1; size += 4; @@ -327,7 +333,7 @@ CheckResultPacket.prototype.getSize = function getSize() { }; CheckResultPacket.prototype.toWriter = function toWriter(bw) { - let err = this.error; + const err = this.error; if (!err) { bw.writeU8(0); @@ -337,20 +343,19 @@ CheckResultPacket.prototype.toWriter = function toWriter(bw) { bw.writeU8(1); bw.writeVarString(err.code, 'utf8'); bw.writeVarString(err.message, 'utf8'); - bw.writeVarString(err.stack + '', 'utf8'); + bw.writeVarString(String(err.stack), 'utf8'); bw.writeU8(err.op === -1 ? 0xff : err.op); bw.writeU32(err.ip === -1 ? 0xffffffff : err.ip); }; CheckResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new CheckResultPacket(); - let err; + const br = new BufferReader(data, true); + const packet = new CheckResultPacket(); if (br.readU8() === 0) return packet; - err = new ScriptError(''); + const err = new ScriptError(''); err.code = br.readVarString('utf8'); err.message = br.readVarString('utf8'); err.stack = br.readVarString('utf8'); @@ -380,7 +385,7 @@ function SignPacket(tx, rings, type) { this.type = type != null ? type : 1; } -util.inherits(SignPacket, Packet); +Object.setPrototypeOf(SignPacket.prototype, Packet.prototype); SignPacket.prototype.cmd = packetTypes.SIGN; @@ -391,7 +396,7 @@ SignPacket.prototype.getSize = function getSize() { size += this.tx.view.getSize(this.tx); size += encoding.sizeVarint(this.rings.length); - for (let ring of this.rings) + for (const ring of this.rings) size += ring.getSize(); size += 1; @@ -405,24 +410,23 @@ SignPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarint(this.rings.length); - for (let ring of this.rings) + for (const ring of this.rings) ring.toWriter(bw); bw.writeU8(this.type); }; SignPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new SignPacket(); - let count; + const br = new BufferReader(data, true); + const packet = new SignPacket(); packet.tx = MTX.fromReader(br); packet.tx.view.fromReader(br, packet.tx); - count = br.readVarint(); + const count = br.readVarint(); for (let i = 0; i < count; i++) { - let ring = KeyRing.fromReader(br); + const ring = KeyRing.fromReader(br); packet.rings.push(ring); } @@ -443,14 +447,14 @@ function SignResultPacket(total, witness, script) { this.witness = witness || []; } -util.inherits(SignResultPacket, Packet); +Object.setPrototypeOf(SignResultPacket.prototype, Packet.prototype); SignResultPacket.prototype.cmd = packetTypes.SIGNRESULT; SignResultPacket.fromTX = function fromTX(tx, total) { - let packet = new SignResultPacket(total); + const packet = new SignResultPacket(total); - for (let input of tx.inputs) { + for (const input of tx.inputs) { packet.script.push(input.script); packet.witness.push(input.witness); } @@ -465,8 +469,8 @@ SignResultPacket.prototype.getSize = function getSize() { size += encoding.sizeVarint(this.script.length); for (let i = 0; i < this.script.length; i++) { - let script = this.script[i]; - let witness = this.witness[i]; + const script = this.script[i]; + const witness = this.witness[i]; size += script.getVarSize(); size += witness.getVarSize(); } @@ -491,20 +495,19 @@ SignResultPacket.prototype.inject = function inject(tx) { assert(this.witness.length === tx.inputs.length); for (let i = 0; i < tx.inputs.length; i++) { - let input = tx.inputs[i]; + const input = tx.inputs[i]; input.script = this.script[i]; input.witness = this.witness[i]; } }; SignResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new SignResultPacket(); - let count; + const br = new BufferReader(data, true); + const packet = new SignResultPacket(); packet.total = br.readVarint(); - count = br.readVarint(); + const count = br.readVarint(); for (let i = 0; i < count; i++) { packet.script.push(Script.fromReader(br)); @@ -527,7 +530,7 @@ function CheckInputPacket(tx, index, coin, flags) { this.flags = flags != null ? flags : null; } -util.inherits(CheckInputPacket, Packet); +Object.setPrototypeOf(CheckInputPacket.prototype, Packet.prototype); CheckInputPacket.prototype.cmd = packetTypes.CHECKINPUT; @@ -546,12 +549,12 @@ CheckInputPacket.prototype.toWriter = function toWriter(bw) { bw.writeVarint(this.index); bw.writeVarint(this.coin.value); this.coin.script.toWriter(bw); - bw.write32(this.flags != null ? this.flags : -1); + bw.writeI32(this.flags != null ? this.flags : -1); }; CheckInputPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new CheckInputPacket(); + const br = new BufferReader(data, true); + const packet = new CheckInputPacket(); packet.tx = TX.fromReader(br); packet.index = br.readVarint(); @@ -560,7 +563,7 @@ CheckInputPacket.fromRaw = function fromRaw(data) { packet.coin.value = br.readVarint(); packet.coin.script.fromReader(br); - packet.flags = br.read32(); + packet.flags = br.readI32(); if (packet.flags === -1) packet.flags = null; @@ -577,13 +580,15 @@ function CheckInputResultPacket(error) { CheckResultPacket.call(this, error); } -util.inherits(CheckInputResultPacket, CheckResultPacket); +Object.setPrototypeOf( + CheckInputResultPacket.prototype, + CheckResultPacket.prototype); CheckInputResultPacket.prototype.cmd = packetTypes.CHECKINPUTRESULT; CheckInputResultPacket.fromRaw = function fromRaw(data) { - let p = CheckResultPacket.fromRaw(data); - let packet = new CheckInputResultPacket(); + const p = CheckResultPacket.fromRaw(data); + const packet = new CheckInputResultPacket(); packet.error = p.error; return packet; }; @@ -602,7 +607,7 @@ function SignInputPacket(tx, index, coin, ring, type) { this.type = type != null ? type : 1; } -util.inherits(SignInputPacket, Packet); +Object.setPrototypeOf(SignInputPacket.prototype, Packet.prototype); SignInputPacket.prototype.cmd = packetTypes.SIGNINPUT; @@ -627,8 +632,8 @@ SignInputPacket.prototype.toWriter = function toWriter(bw) { }; SignInputPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new SignInputPacket(); + const br = new BufferReader(data, true); + const packet = new SignInputPacket(); packet.tx = MTX.fromReader(br); packet.index = br.readVarint(); @@ -655,13 +660,13 @@ function SignInputResultPacket(value, witness, script) { this.witness = witness || null; } -util.inherits(SignInputResultPacket, Packet); +Object.setPrototypeOf(SignInputResultPacket.prototype, Packet.prototype); SignInputResultPacket.prototype.cmd = packetTypes.SIGNINPUTRESULT; SignInputResultPacket.fromTX = function fromTX(tx, i, value) { - let packet = new SignInputResultPacket(value); - let input = tx.inputs[i]; + const packet = new SignInputResultPacket(value); + const input = tx.inputs[i]; assert(input); @@ -682,22 +687,21 @@ SignInputResultPacket.prototype.toWriter = function toWriter(bw) { }; SignInputResultPacket.prototype.inject = function inject(tx, i) { - let input = tx.inputs[i]; + const input = tx.inputs[i]; assert(input); input.script = this.script; input.witness = this.witness; }; SignInputResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new SignInputResultPacket(); + const br = new BufferReader(data, true); + const packet = new SignInputResultPacket(); packet.value = br.readU8() === 1; packet.script = Script.fromReader(br); packet.witness = Witness.fromReader(br); return packet; }; - /** * ECVerifyPacket * @constructor @@ -710,7 +714,7 @@ function ECVerifyPacket(msg, sig, key) { this.key = key || null; } -util.inherits(ECVerifyPacket, Packet); +Object.setPrototypeOf(ECVerifyPacket.prototype, Packet.prototype); ECVerifyPacket.prototype.cmd = packetTypes.ECVERIFY; @@ -729,8 +733,8 @@ ECVerifyPacket.prototype.toWriter = function toWriter(bw) { }; ECVerifyPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ECVerifyPacket(); + const br = new BufferReader(data, true); + const packet = new ECVerifyPacket(); packet.msg = br.readVarBytes(); packet.sig = br.readVarBytes(); packet.key = br.readVarBytes(); @@ -747,7 +751,7 @@ function ECVerifyResultPacket(value) { this.value = value; } -util.inherits(ECVerifyResultPacket, Packet); +Object.setPrototypeOf(ECVerifyResultPacket.prototype, Packet.prototype); ECVerifyResultPacket.prototype.cmd = packetTypes.ECVERIFYRESULT; @@ -760,8 +764,8 @@ ECVerifyResultPacket.prototype.toWriter = function toWriter(bw) { }; ECVerifyResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ECVerifyResultPacket(); + const br = new BufferReader(data, true); + const packet = new ECVerifyResultPacket(); packet.value = br.readU8() === 1; return packet; }; @@ -777,7 +781,7 @@ function ECSignPacket(msg, key) { this.key = key || null; } -util.inherits(ECSignPacket, Packet); +Object.setPrototypeOf(ECSignPacket.prototype, Packet.prototype); ECSignPacket.prototype.cmd = packetTypes.ECSIGN; @@ -794,8 +798,8 @@ ECSignPacket.prototype.toWriter = function toWriter(bw) { }; ECSignPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ECSignPacket(); + const br = new BufferReader(data, true); + const packet = new ECSignPacket(); packet.msg = br.readVarBytes(); packet.key = br.readVarBytes(); return packet; @@ -811,7 +815,7 @@ function ECSignResultPacket(sig) { this.sig = sig; } -util.inherits(ECSignResultPacket, Packet); +Object.setPrototypeOf(ECSignResultPacket.prototype, Packet.prototype); ECSignResultPacket.prototype.cmd = packetTypes.ECSIGNRESULT; @@ -824,8 +828,8 @@ ECSignResultPacket.prototype.toWriter = function toWriter(bw) { }; ECSignResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ECSignResultPacket(); + const br = new BufferReader(data, true); + const packet = new ECSignResultPacket(); packet.sig = br.readVarBytes(); return packet; }; @@ -843,7 +847,7 @@ function MinePacket(data, target, min, max) { this.max = max != null ? max : -1; } -util.inherits(MinePacket, Packet); +Object.setPrototypeOf(MinePacket.prototype, Packet.prototype); MinePacket.prototype.cmd = packetTypes.MINE; @@ -859,8 +863,8 @@ MinePacket.prototype.toWriter = function toWriter(bw) { }; MinePacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new MinePacket(); + const br = new BufferReader(data, true); + const packet = new MinePacket(); packet.data = br.readBytes(80); packet.target = br.readBytes(32); packet.min = br.readU32(); @@ -878,7 +882,7 @@ function MineResultPacket(nonce) { this.nonce = nonce != null ? nonce : -1; } -util.inherits(MineResultPacket, Packet); +Object.setPrototypeOf(MineResultPacket.prototype, Packet.prototype); MineResultPacket.prototype.cmd = packetTypes.MINERESULT; @@ -891,8 +895,8 @@ MineResultPacket.prototype.toWriter = function toWriter(bw) { }; MineResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new MineResultPacket(); + const br = new BufferReader(data, true); + const packet = new MineResultPacket(); packet.nonce = br.readU32(); if ((packet.nonce >> 0) === -1) packet.nonce = -1; @@ -914,7 +918,7 @@ function ScryptPacket(passwd, salt, N, r, p, len) { this.len = len != null ? len : -1; } -util.inherits(ScryptPacket, Packet); +Object.setPrototypeOf(ScryptPacket.prototype, Packet.prototype); ScryptPacket.prototype.cmd = packetTypes.SCRYPT; @@ -936,8 +940,8 @@ ScryptPacket.prototype.toWriter = function toWriter(bw) { }; ScryptPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ScryptPacket(); + const br = new BufferReader(data, true); + const packet = new ScryptPacket(); packet.passwd = br.readVarBytes(); packet.salt = br.readVarBytes(); packet.N = br.readU32(); @@ -957,7 +961,7 @@ function ScryptResultPacket(key) { this.key = key || null; } -util.inherits(ScryptResultPacket, Packet); +Object.setPrototypeOf(ScryptResultPacket.prototype, Packet.prototype); ScryptResultPacket.prototype.cmd = packetTypes.SCRYPTRESULT; @@ -970,8 +974,8 @@ ScryptResultPacket.prototype.toWriter = function toWriter(bw) { }; ScryptResultPacket.fromRaw = function fromRaw(data) { - let br = new BufferReader(data, true); - let packet = new ScryptResultPacket(); + const br = new BufferReader(data, true); + const packet = new ScryptResultPacket(); packet.key = br.readVarBytes(); return packet; }; diff --git a/lib/workers/parent-browser.js b/lib/workers/parent-browser.js index 5c811135d..2eb865e72 100644 --- a/lib/workers/parent-browser.js +++ b/lib/workers/parent-browser.js @@ -8,7 +8,6 @@ const assert = require('assert'); const EventEmitter = require('events'); -const util = require('../utils/util'); /** * Represents the parent process. @@ -26,7 +25,7 @@ function Parent() { this.init(); } -util.inherits(Parent, EventEmitter); +Object.setPrototypeOf(Parent.prototype, EventEmitter.prototype); /** * Initialize master (web workers). diff --git a/lib/workers/parent.js b/lib/workers/parent.js index 77dc6ed83..c08686809 100644 --- a/lib/workers/parent.js +++ b/lib/workers/parent.js @@ -7,7 +7,6 @@ 'use strict'; const EventEmitter = require('events'); -const util = require('../utils/util'); /** * Represents the parent process. @@ -24,7 +23,7 @@ function Parent() { this.init(); } -util.inherits(Parent, EventEmitter); +Object.setPrototypeOf(Parent.prototype, EventEmitter.prototype); /** * Initialize master (node.js). diff --git a/lib/workers/parser.js b/lib/workers/parser.js index 13cbb0129..26c21788c 100644 --- a/lib/workers/parser.js +++ b/lib/workers/parser.js @@ -9,7 +9,6 @@ const assert = require('assert'); const EventEmitter = require('events'); -const util = require('../utils/util'); const packets = require('./packets'); /** @@ -30,48 +29,45 @@ function Parser() { this.total = 0; } -util.inherits(Parser, EventEmitter); +Object.setPrototypeOf(Parser.prototype, EventEmitter.prototype); Parser.prototype.feed = function feed(data) { this.total += data.length; this.pending.push(data); while (this.total >= this.waiting) { - let chunk = this.read(this.waiting); + const chunk = this.read(this.waiting); this.parse(chunk); } }; Parser.prototype.read = function read(size) { - let pending, chunk, off, len; - assert(this.total >= size, 'Reading too much.'); if (size === 0) return Buffer.alloc(0); - pending = this.pending[0]; + const pending = this.pending[0]; if (pending.length > size) { - chunk = pending.slice(0, size); + const chunk = pending.slice(0, size); this.pending[0] = pending.slice(size); this.total -= chunk.length; return chunk; } if (pending.length === size) { - chunk = this.pending.shift(); + const chunk = this.pending.shift(); this.total -= chunk.length; return chunk; } - chunk = Buffer.allocUnsafe(size); - off = 0; - len = 0; + const chunk = Buffer.allocUnsafe(size); + let off = 0; while (off < chunk.length) { - pending = this.pending[0]; - len = pending.copy(chunk, off); + const pending = this.pending[0]; + const len = pending.copy(chunk, off); if (len === pending.length) this.pending.shift(); else @@ -79,7 +75,7 @@ Parser.prototype.read = function read(size) { off += len; } - assert.equal(off, chunk.length); + assert.strictEqual(off, chunk.length); this.total -= chunk.length; @@ -88,7 +84,6 @@ Parser.prototype.read = function read(size) { Parser.prototype.parse = function parse(data) { let header = this.header; - let packet; if (!header) { try { @@ -107,6 +102,7 @@ Parser.prototype.parse = function parse(data) { this.waiting = 9; this.header = null; + let packet; try { packet = this.parsePacket(header, data); } catch (e) { @@ -125,9 +121,9 @@ Parser.prototype.parse = function parse(data) { }; Parser.prototype.parseHeader = function parseHeader(data) { - let id = data.readUInt32LE(0, true); - let cmd = data.readUInt8(4, true); - let size = data.readUInt32LE(5, true); + const id = data.readUInt32LE(0, true); + const cmd = data.readUInt8(4, true); + const size = data.readUInt32LE(5, true); return new Header(id, cmd, size); }; diff --git a/lib/workers/workerpool.js b/lib/workers/workerpool.js index b289aa797..05ce36d8c 100644 --- a/lib/workers/workerpool.js +++ b/lib/workers/workerpool.js @@ -5,6 +5,8 @@ * https://github.com/bcoin-org/bcoin */ +/* eslint no-nested-ternary: "off" */ + 'use strict'; const assert = require('assert'); @@ -49,7 +51,7 @@ function WorkerPool(options) { this.set(options); } -util.inherits(WorkerPool, EventEmitter); +Object.setPrototypeOf(WorkerPool.prototype, EventEmitter.prototype); /** * Set worker pool options. @@ -66,14 +68,14 @@ WorkerPool.prototype.set = function set(options) { } if (options.size != null) { - assert(util.isNumber(options.size)); + assert(util.isU32(options.size)); assert(options.size > 0); this.size = options.size; } if (options.timeout != null) { - assert(util.isNumber(options.timeout)); - assert(options.timeout > 0); + assert(util.isInt(options.timeout)); + assert(options.timeout >= -1); this.timeout = options.timeout; } @@ -108,7 +110,7 @@ WorkerPool.prototype.close = async function close() { */ WorkerPool.prototype.spawn = function spawn(id) { - let child = new Worker(this.file); + const child = new Worker(this.file); child.id = id; @@ -144,7 +146,7 @@ WorkerPool.prototype.spawn = function spawn(id) { */ WorkerPool.prototype.alloc = function alloc() { - let id = this.uid++ % this.size; + const id = this.uid++ % this.size; if (!this.children.has(id)) this.children.set(id, this.spawn(id)); @@ -162,7 +164,7 @@ WorkerPool.prototype.alloc = function alloc() { WorkerPool.prototype.sendEvent = function sendEvent() { let result = true; - for (let child of this.children.values()) { + for (const child of this.children.values()) { if (!child.sendEvent.apply(child, arguments)) result = false; } @@ -175,7 +177,7 @@ WorkerPool.prototype.sendEvent = function sendEvent() { */ WorkerPool.prototype.destroy = function destroy() { - for (let child of this.children.values()) + for (const child of this.children.values()) child.destroy(); }; @@ -187,8 +189,6 @@ WorkerPool.prototype.destroy = function destroy() { */ WorkerPool.prototype.execute = function execute(packet, timeout) { - let child; - if (!this.enabled || !Child.hasSupport()) { return new Promise((resolve, reject) => { setImmediate(() => { @@ -207,7 +207,7 @@ WorkerPool.prototype.execute = function execute(packet, timeout) { if (!timeout) timeout = this.timeout; - child = this.alloc(); + const child = this.alloc(); return child.execute(packet, timeout); }; @@ -222,8 +222,8 @@ WorkerPool.prototype.execute = function execute(packet, timeout) { */ WorkerPool.prototype.check = async function check(tx, view, flags) { - let packet = new packets.CheckPacket(tx, view, flags); - let result = await this.execute(packet, -1); + const packet = new packets.CheckPacket(tx, view, flags); + const result = await this.execute(packet, -1); if (result.error) throw result.error; @@ -242,13 +242,12 @@ WorkerPool.prototype.check = async function check(tx, view, flags) { WorkerPool.prototype.sign = async function sign(tx, ring, type) { let rings = ring; - let packet, result; if (!Array.isArray(rings)) rings = [rings]; - packet = new packets.SignPacket(tx, rings, type); - result = await this.execute(packet, -1); + const packet = new packets.SignPacket(tx, rings, type); + const result = await this.execute(packet, -1); result.inject(tx); @@ -266,8 +265,8 @@ WorkerPool.prototype.sign = async function sign(tx, ring, type) { */ WorkerPool.prototype.checkInput = async function checkInput(tx, index, coin, flags) { - let packet = new packets.CheckInputPacket(tx, index, coin, flags); - let result = await this.execute(packet, -1); + const packet = new packets.CheckInputPacket(tx, index, coin, flags); + const result = await this.execute(packet, -1); if (result.error) throw result.error; @@ -287,8 +286,8 @@ WorkerPool.prototype.checkInput = async function checkInput(tx, index, coin, fla */ WorkerPool.prototype.signInput = async function signInput(tx, index, coin, ring, type) { - let packet = new packets.SignInputPacket(tx, index, coin, ring, type); - let result = await this.execute(packet, -1); + const packet = new packets.SignInputPacket(tx, index, coin, ring, type); + const result = await this.execute(packet, -1); result.inject(tx); return result.value; }; @@ -303,8 +302,8 @@ WorkerPool.prototype.signInput = async function signInput(tx, index, coin, ring, */ WorkerPool.prototype.ecVerify = async function ecVerify(msg, sig, key) { - let packet = new packets.ECVerifyPacket(msg, sig, key); - let result = await this.execute(packet, -1); + const packet = new packets.ECVerifyPacket(msg, sig, key); + const result = await this.execute(packet, -1); return result.value; }; @@ -317,8 +316,8 @@ WorkerPool.prototype.ecVerify = async function ecVerify(msg, sig, key) { */ WorkerPool.prototype.ecSign = async function ecSign(msg, key) { - let packet = new packets.ECSignPacket(msg, key); - let result = await this.execute(packet, -1); + const packet = new packets.ECSignPacket(msg, key); + const result = await this.execute(packet, -1); return result.sig; }; @@ -333,8 +332,8 @@ WorkerPool.prototype.ecSign = async function ecSign(msg, key) { */ WorkerPool.prototype.mine = async function mine(data, target, min, max) { - let packet = new packets.MinePacket(data, target, min, max); - let result = await this.execute(packet, -1); + const packet = new packets.MinePacket(data, target, min, max); + const result = await this.execute(packet, -1); return result.nonce; }; @@ -351,8 +350,8 @@ WorkerPool.prototype.mine = async function mine(data, target, min, max) { */ WorkerPool.prototype.scrypt = async function scrypt(passwd, salt, N, r, p, len) { - let packet = new packets.ScryptPacket(passwd, salt, N, r, p, len); - let result = await this.execute(packet, -1); + const packet = new packets.ScryptPacket(passwd, salt, N, r, p, len); + const result = await this.execute(packet, -1); return result.key; }; @@ -379,7 +378,7 @@ function Worker(file) { this.init(); } -util.inherits(Worker, EventEmitter); +Object.setPrototypeOf(Worker.prototype, EventEmitter.prototype); /** * Initialize worker. Bind to events. @@ -540,7 +539,7 @@ Worker.prototype.execute = function execute(packet, timeout) { */ Worker.prototype._execute = function _execute(packet, timeout, resolve, reject) { - let job = new PendingJob(this, packet.id, resolve, reject); + const job = new PendingJob(this, packet.id, resolve, reject); assert(!this.pending.has(packet.id), 'ID overflow.'); @@ -558,7 +557,7 @@ Worker.prototype._execute = function _execute(packet, timeout, resolve, reject) */ Worker.prototype.resolveJob = function resolveJob(id, result) { - let job = this.pending.get(id); + const job = this.pending.get(id); if (!job) throw new Error(`Job ${id} is not in progress.`); @@ -573,7 +572,7 @@ Worker.prototype.resolveJob = function resolveJob(id, result) { */ Worker.prototype.rejectJob = function rejectJob(id, err) { - let job = this.pending.get(id); + const job = this.pending.get(id); if (!job) throw new Error(`Job ${id} is not in progress.`); @@ -586,7 +585,7 @@ Worker.prototype.rejectJob = function rejectJob(id, err) { */ Worker.prototype.killJobs = function killJobs() { - for (let job of this.pending.values()) + for (const job of this.pending.values()) job.destroy(); }; @@ -635,7 +634,7 @@ PendingJob.prototype.destroy = function destroy() { */ PendingJob.prototype.cleanup = function cleanup() { - let job = this.job; + const job = this.job; assert(job, 'Already finished.'); @@ -658,7 +657,7 @@ PendingJob.prototype.cleanup = function cleanup() { */ PendingJob.prototype.resolve = function resolve(result) { - let job = this.cleanup(); + const job = this.cleanup(); job.resolve(result); }; @@ -668,7 +667,7 @@ PendingJob.prototype.resolve = function resolve(result) { */ PendingJob.prototype.reject = function reject(err) { - let job = this.cleanup(); + const job = this.cleanup(); job.reject(err); }; diff --git a/migrate/chaindb0to1.js b/migrate/chaindb0to1.js index 86db9e011..375363c69 100644 --- a/migrate/chaindb0to1.js +++ b/migrate/chaindb0to1.js @@ -19,53 +19,49 @@ const db = bcoin.ldb({ }); function makeKey(data) { - let height = data.readUInt32LE(1, true); - let key = Buffer.allocUnsafe(5); + const height = data.readUInt32LE(1, true); + const key = Buffer.allocUnsafe(5); key[0] = 0x48; key.writeUInt32BE(height, 1, true); return key; } async function checkVersion() { - let data, ver; - console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); if (!data) return; - ver = data.readUInt32LE(0, true); + const ver = data.readUInt32LE(0, true); if (ver !== 0) throw Error(`DB is version ${ver}.`); } async function updateState() { - let data, hash, batch, ver, p; - console.log('Updating chain state.'); - data = await db.get('R'); + const data = await db.get('R'); if (!data || data.length < 32) throw new Error('No chain state.'); - hash = data.slice(0, 32); + const hash = data.slice(0, 32); - p = new BufferWriter(); + let p = new BufferWriter(); p.writeHash(hash); p.writeU64(0); p.writeU64(0); p.writeU64(0); p = p.render(); - batch = db.batch(); + const batch = db.batch(); batch.put('R', p); - ver = Buffer.allocUnsafe(4); + const ver = Buffer.allocUnsafe(4); ver.writeUInt32LE(1, 0, true); batch.put('V', ver); @@ -75,21 +71,20 @@ async function updateState() { } async function updateEndian() { - let batch = db.batch(); + const batch = db.batch(); let total = 0; - let iter, item; console.log('Updating endianness.'); console.log('Iterating...'); - iter = db.iterator({ + const iter = db.iterator({ gte: Buffer.from('4800000000', 'hex'), lte: Buffer.from('48ffffffff', 'hex'), values: true }); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; diff --git a/migrate/chaindb1to2.js b/migrate/chaindb1to2.js index 3792837e2..57babdd71 100644 --- a/migrate/chaindb1to2.js +++ b/migrate/chaindb1to2.js @@ -13,14 +13,13 @@ const Coin = require('../lib/primitives/coin'); const Output = require('../lib/primitives/output'); const LDB = require('../lib/db/ldb'); let file = process.argv[2]; -let options = {}; -let db, batch, index; +let batch; assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -db = LDB({ +const db = LDB({ location: file, db: 'leveldb', compression: true, @@ -29,14 +28,14 @@ db = LDB({ bufferKeys: true }); -options = {}; +const options = {}; options.spv = process.argv.indexOf('--spv') !== -1; options.prune = process.argv.indexOf('--prune') !== -1; options.indexTX = process.argv.indexOf('--index-tx') !== -1; options.indexAddress = process.argv.indexOf('--index-address') !== -1; options.network = networks.main; -index = process.argv.indexOf('--network'); +const index = process.argv.indexOf('--network'); if (index !== -1) { options.network = networks[process.argv[index + 1]]; @@ -44,16 +43,14 @@ if (index !== -1) { } async function updateVersion() { - let data, ver; - console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); if (!data) throw new Error('No DB version found!'); - ver = data.readUInt32LE(0, true); + let ver = data.readUInt32LE(0, true); if (ver !== 1) throw Error(`DB is version ${ver}.`); @@ -64,7 +61,7 @@ async function updateVersion() { } async function checkTipIndex() { - let keys = await db.keys({ + const keys = await db.keys({ gte: pair('p', encoding.ZERO_HASH), lte: pair('p', encoding.MAX_HASH) }); @@ -116,38 +113,37 @@ async function updateDeployments() { async function reserializeCoins() { let total = 0; - let i, iter, item, hash, old, coins, coin, output; - iter = db.iterator({ + const iter = db.iterator({ gte: pair('c', encoding.ZERO_HASH), lte: pair('c', encoding.MAX_HASH), values: true }); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; - hash = item.key.toString('hex', 1, 33); - old = OldCoins.fromRaw(item.value, hash); + const hash = item.key.toString('hex', 1, 33); + const old = OldCoins.fromRaw(item.value, hash); - coins = new Coins(); + const coins = new Coins(); coins.version = old.version; coins.hash = old.hash; coins.height = old.height; coins.coinbase = old.coinbase; - for (i = 0; i < old.outputs.length; i++) { - coin = old.get(i); + for (let i = 0; i < old.outputs.length; i++) { + const coin = old.get(i); if (!coin) { coins.outputs.push(null); continue; } - output = new Output(); + const output = new Output(); output.script = coin.script; output.value = coin.value; @@ -168,22 +164,21 @@ async function reserializeCoins() { async function reserializeUndo() { let total = 0; - let iter, item, br, undo; - iter = db.iterator({ + const iter = db.iterator({ gte: pair('u', encoding.ZERO_HASH), lte: pair('u', encoding.MAX_HASH), values: true }); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; - br = new BufferReader(item.value); - undo = new UndoCoins(); + const br = new BufferReader(item.value); + const undo = new UndoCoins(); while (br.left()) { undo.push(null); @@ -202,11 +197,11 @@ async function reserializeUndo() { function write(data, str, off) { if (Buffer.isBuffer(str)) return str.copy(data, off); - data.write(str, off, 'hex'); + return data.write(str, off, 'hex'); } function pair(prefix, hash) { - let key = Buffer.allocUnsafe(33); + const key = Buffer.allocUnsafe(33); if (typeof prefix === 'string') prefix = prefix.charCodeAt(0); key[0] = prefix; @@ -215,7 +210,7 @@ function pair(prefix, hash) { } function injectCoin(undo, coin) { - let output = new Output(); + const output = new Output(); output.value = coin.value; output.script = coin.script; @@ -227,7 +222,7 @@ function injectCoin(undo, coin) { } function defaultOptions() { - let bw = new BufferWriter(); + const bw = new BufferWriter(); let flags = 0; if (options.spv) @@ -252,13 +247,12 @@ function defaultOptions() { } function defaultDeployments() { - let bw = new BufferWriter(); - let i, deployment; + const bw = new BufferWriter(); bw.writeU8(options.network.deploys.length); - for (i = 0; i < options.network.deploys.length; i++) { - deployment = options.network.deploys[i]; + for (let i = 0; i < options.network.deploys.length; i++) { + const deployment = options.network.deploys[i]; bw.writeU8(deployment.bit); bw.writeU32(deployment.startTime); bw.writeU32(deployment.timeout); diff --git a/migrate/chaindb2to3.js b/migrate/chaindb2to3.js new file mode 100644 index 000000000..0600cdc89 --- /dev/null +++ b/migrate/chaindb2to3.js @@ -0,0 +1,706 @@ +'use strict'; + +if (process.argv.indexOf('-h') !== -1 + || process.argv.indexOf('--help') !== -1 + || process.argv.length < 3) { + console.error('Bcoin database migration (chaindb v2->v3).'); + console.error(''); + console.error('Usage:'); + console.error(' $ node migrate/chaindb2to3.js [database-path] [--prune]'); + console.error(''); + console.error('Note: use --prune to convert your database to a pruned DB'); + console.error('in the process. This results in a faster migration, but'); + console.error('a pruning of the chain.'); + process.exit(1); + throw new Error('Exit failed.'); +} + +const assert = require('assert'); +const encoding = require('../lib/utils/encoding'); +const co = require('../lib/utils/co'); +const util = require('../lib/utils/util'); +const digest = require('../lib/crypto/digest'); +const BN = require('../lib/crypto/bn'); +const StaticWriter = require('../lib/utils/staticwriter'); +const BufferReader = require('../lib/utils/reader'); +const OldCoins = require('./coins/coins'); +const OldUndoCoins = require('./coins/undocoins'); +const CoinEntry = require('../lib/coins/coinentry'); +const UndoCoins = require('../lib/coins/undocoins'); +const Block = require('../lib/primitives/block'); +const LDB = require('../lib/db/ldb'); +const LRU = require('../lib/utils/lru'); + +const file = process.argv[2].replace(/\.ldb\/?$/, ''); +const shouldPrune = process.argv.indexOf('--prune') !== -1; +let hasIndex = false; +let hasPruned = false; +let hasSPV = false; + +const db = LDB({ + location: file, + db: 'leveldb', + compression: true, + cacheSize: 32 << 20, + createIfMissing: false, + bufferKeys: true +}); + +// \0\0migrate +const JOURNAL_KEY = Buffer.from('00006d696772617465', 'hex'); +const MIGRATION_ID = 0; +const STATE_VERSION = -1; +const STATE_UNDO = 0; +const STATE_CLEANUP = 1; +const STATE_COINS = 2; +const STATE_ENTRY = 3; +const STATE_FINAL = 4; +const STATE_DONE = 5; + +const metaCache = new Map(); +const lruCache = new LRU(200000); + +function writeJournal(batch, state, hash) { + const data = Buffer.allocUnsafe(34); + + if (!hash) + hash = encoding.NULL_HASH; + + data[0] = MIGRATION_ID; + data[1] = state; + data.write(hash, 2, 'hex'); + + batch.put(JOURNAL_KEY, data); +} + +async function readJournal() { + const data = await db.get(JOURNAL_KEY); + + if (!data) + return [STATE_VERSION, encoding.NULL_HASH]; + + if (data[0] !== MIGRATION_ID) + throw new Error('Bad migration id.'); + + if (data.length !== 34) + throw new Error('Bad migration length.'); + + const state = data.readUInt8(1, true); + const hash = data.toString('hex', 2, 34); + + console.log('Reading journal.'); + console.log('Recovering from state %d.', state); + + return [state, hash]; +} + +async function updateVersion() { + const batch = db.batch(); + + console.log('Checking version.'); + + const verRaw = await db.get('V'); + + if (!verRaw) + throw new Error('No DB version found!'); + + const version = verRaw.readUInt32LE(0, true); + + if (version !== 2) + throw Error(`DB is version ${version}.`); + + // Set to uint32_max temporarily. + // This is to prevent bcoin from + // trying to access this chain. + const data = Buffer.allocUnsafe(4); + data.writeUInt32LE(-1 >>> 0, 0, true); + batch.put('V', data); + + writeJournal(batch, STATE_UNDO); + + console.log('Updating version.'); + + await batch.write(); + + return [STATE_UNDO, encoding.NULL_HASH]; +} + +async function reserializeUndo(hash) { + let tip = await getTip(); + const height = tip.height; + + if (hash !== encoding.NULL_HASH) + tip = await getEntry(hash); + + console.log('Reserializing undo coins from tip %s.', util.revHex(tip.hash)); + + let batch = db.batch(); + let pruning = false; + let total = 0; + let totalCoins = 0; + + while (tip.height !== 0 && !hasSPV) { + if (shouldPrune) { + if (tip.height < height - 288) { + console.log('Pruning block %s (%d).', + util.revHex(tip.hash), tip.height); + + batch.del(pair('u', tip.hash)); + batch.del(pair('b', tip.hash)); + + if (!pruning) { + console.log( + 'Reserialized %d undo records (%d coins).', + total, totalCoins); + writeJournal(batch, STATE_UNDO, tip.prevBlock); + await batch.write(); + metaCache.clear(); + batch = db.batch(); + pruning = true; + } + + tip = await getEntry(tip.prevBlock); + assert(tip); + continue; + } + } + + const undoData = await db.get(pair('u', tip.hash)); + const blockData = await db.get(pair('b', tip.hash)); + + if (!undoData) { + tip = await getEntry(tip.prevBlock); + assert(tip); + continue; + } + + if (!blockData) { + if (!hasPruned) + throw new Error(`Block not found: ${tip.hash}.`); + break; + } + + const block = Block.fromRaw(blockData); + const old = OldUndoCoins.fromRaw(undoData); + const undo = new UndoCoins(); + + console.log( + 'Reserializing coins for block %s (%d).', + util.revHex(tip.hash), tip.height); + + for (let i = block.txs.length - 1; i >= 1; i--) { + const tx = block.txs[i]; + for (let j = tx.inputs.length - 1; j >= 0; j--) { + const {prevout} = tx.inputs[j]; + const coin = old.items.pop(); + const output = coin.toOutput(); + + assert(coin); + + const [version, height, write] = await getMeta(coin, prevout); + + const item = new CoinEntry(); + item.version = version; + item.height = height; + item.coinbase = coin.coinbase; + item.output.script = output.script; + item.output.value = output.value; + item.spent = true; + item.raw = null; + + // Store an index of heights and versions for later. + const meta = [version, height]; + + if (write) { + const data = Buffer.allocUnsafe(8); + data.writeUInt32LE(version, 0, true); + data.writeUInt32LE(height, 4, true); + batch.put(pair(0x01, prevout.hash), data); + metaCache.set(prevout.hash, meta); + } + + if (!lruCache.has(prevout.hash)) + lruCache.set(prevout.hash, meta); + + undo.items.push(item); + } + } + + // We need to reverse everything. + undo.items.reverse(); + + totalCoins += undo.items.length; + + batch.put(pair('u', tip.hash), undo.toRaw()); + + if (++total % 100 === 0) { + console.log( + 'Reserialized %d undo records (%d coins).', + total, totalCoins); + writeJournal(batch, STATE_UNDO, tip.prevBlock); + await batch.write(); + metaCache.clear(); + batch = db.batch(); + } + + tip = await getEntry(tip.prevBlock); + } + + writeJournal(batch, STATE_CLEANUP); + await batch.write(); + + metaCache.clear(); + lruCache.reset(); + + console.log( + 'Reserialized %d undo records (%d coins).', + total, totalCoins); + + return [STATE_CLEANUP, encoding.NULL_HASH]; +} + +async function cleanupIndex() { + if (hasSPV) + return [STATE_COINS, encoding.NULL_HASH]; + + const iter = db.iterator({ + gte: pair(0x01, encoding.ZERO_HASH), + lte: pair(0x01, encoding.MAX_HASH), + keys: true + }); + + console.log('Removing txid->height undo index.'); + + let batch = db.batch(); + let total = 0; + + for (;;) { + const item = await iter.next(); + + if (!item) + break; + + batch.del(item.key); + + if (++total % 10000 === 0) { + console.log('Cleaned up %d undo records.', total); + writeJournal(batch, STATE_CLEANUP); + await batch.write(); + batch = db.batch(); + } + } + + writeJournal(batch, STATE_COINS); + await batch.write(); + + console.log('Cleaned up %d undo records.', total); + + return [STATE_COINS, encoding.NULL_HASH]; +} + +async function reserializeCoins(hash) { + if (hasSPV) + return [STATE_ENTRY, encoding.NULL_HASH]; + + const iter = db.iterator({ + gte: pair('c', hash), + lte: pair('c', encoding.MAX_HASH), + keys: true, + values: true + }); + + let start = true; + + if (hash !== encoding.NULL_HASH) { + const item = await iter.next(); + if (!item) + start = false; + } + + console.log('Reserializing coins from %s.', util.revHex(hash)); + + let batch = db.batch(); + let total = 0; + + while (start) { + const item = await iter.next(); + + if (!item) + break; + + if (item.key.length !== 33) + continue; + + const hash = item.key.toString('hex', 1, 33); + const old = OldCoins.fromRaw(item.value, hash); + + let update = false; + + for (let i = 0; i < old.outputs.length; i++) { + const coin = old.getCoin(i); + + if (!coin) + continue; + + const item = new CoinEntry(); + item.version = coin.version; + item.height = coin.height; + item.coinbase = coin.coinbase; + item.output.script = coin.script; + item.output.value = coin.value; + item.spent = false; + item.raw = null; + + batch.put(bpair('c', hash, i), item.toRaw()); + + if (++total % 10000 === 0) + update = true; + } + + batch.del(item.key); + + if (update) { + console.log('Reserialized %d coins.', total); + writeJournal(batch, STATE_COINS, hash); + await batch.write(); + batch = db.batch(); + } + } + + writeJournal(batch, STATE_ENTRY); + await batch.write(); + + console.log('Reserialized %d coins.', total); + + return [STATE_ENTRY, encoding.NULL_HASH]; +} + +async function reserializeEntries(hash) { + const iter = db.iterator({ + gte: pair('e', hash), + lte: pair('e', encoding.MAX_HASH), + values: true + }); + + let start = true; + + if (hash !== encoding.NULL_HASH) { + const item = await iter.next(); + if (!item) + start = false; + else + assert(item.key.equals(pair('e', hash))); + } + + console.log('Reserializing entries from %s.', util.revHex(hash)); + + const tip = await getTipHash(); + + let total = 0; + let batch = db.batch(); + + while (start) { + const item = await iter.next(); + + if (!item) + break; + + const entry = entryFromRaw(item.value); + const main = await isMainChain(entry, tip); + + batch.put(item.key, entryToRaw(entry, main)); + + if (++total % 100000 === 0) { + console.log('Reserialized %d entries.', total); + writeJournal(batch, STATE_ENTRY, entry.hash); + await batch.write(); + batch = db.batch(); + } + } + + writeJournal(batch, STATE_FINAL); + await batch.write(); + + console.log('Reserialized %d entries.', total); + + return [STATE_FINAL, encoding.NULL_HASH]; +} + +async function finalize() { + const batch = db.batch(); + const data = Buffer.allocUnsafe(4); + + data.writeUInt32LE(3, 0, true); + + batch.del(JOURNAL_KEY); + batch.put('V', data); + + // This has bugged me for a while. + batch.del(pair('n', encoding.ZERO_HASH)); + + if (shouldPrune) { + const data = await db.get('O'); + + assert(data); + + let flags = data.readUInt32LE(4, true); + flags |= 1 << 2; + + data.writeUInt32LE(flags, 4, true); + + batch.put('O', data); + } + + console.log('Finalizing database.'); + + await batch.write(); + + console.log('Compacting database...'); + + await db.compactRange(); + + return [STATE_DONE, encoding.NULL_HASH]; +} + +async function getMeta(coin, prevout) { + // Case 1: Undo coin is the last spend. + if (coin.height !== -1) { + assert(coin.version !== -1, 'Database corruption.'); + return [coin.version, coin.height, hasIndex ? false : true]; + } + + // Case 2: The item is still in the LRU cache. + const lruItem = lruCache.get(prevout.hash); + + if (lruItem) { + const [version, height] = lruItem; + return [version, height, false]; + } + + // Case 3: The database has a tx-index. We + // can just hit that instead of reindexing. + if (hasIndex) { + const txRaw = await db.get(pair('t', prevout.hash)); + assert(txRaw, 'Database corruption.'); + assert(txRaw[txRaw.length - 45] === 1); + const version = txRaw.readUInt32LE(0, true); + const height = txRaw.readUInt32LE(txRaw.length - 12, true); + return [version, height, false]; + } + + // Case 4: We have previously cached + // this coin's metadata, but it's not + // written yet. + const metaItem = metaCache.get(prevout.hash); + + if (metaItem) { + const [version, height] = metaItem; + return [version, height, false]; + } + + // Case 5: We have previously cached + // this coin's metadata, and it is + // written. + const metaRaw = await db.get(pair(0x01, prevout.hash)); + + if (metaRaw) { + const version = metaRaw.readUInt32LE(0, true); + const height = metaRaw.readUInt32LE(4, true); + return [version, height, false]; + } + + // Case 6: The coin's metadata is + // still in the top-level UTXO set. + const coinsRaw = await db.get(pair('c', prevout.hash)); + + // Case 7: We're pruned and are + // under the keepBlocks threshold. + // We don't have access to this + // data. Luckily, it appears that + // all historical transactions + // under height 182 are version 1, + // which means height is not + // necessary to determine CSV + // anyway. Just store the height + // as `1`. + if (!coinsRaw) { + assert(hasPruned, 'Database corruption.'); + return [1, 1, false]; + } + + const br = new BufferReader(coinsRaw); + const version = br.readVarint(); + const height = br.readU32(); + + return [version, height, true]; +} + +async function getTip() { + const tip = await getTipHash(); + return await getEntry(tip); +} + +async function getTipHash() { + const state = await db.get('R'); + assert(state); + return state.toString('hex', 0, 32); +} + +async function getEntry(hash) { + const data = await db.get(pair('e', hash)); + assert(data); + return entryFromRaw(data); +} + +async function isPruned() { + const data = await db.get('O'); + assert(data); + return (data.readUInt32LE(4) & 4) !== 0; +} + +async function isSPV() { + const data = await db.get('O'); + assert(data); + return (data.readUInt32LE(4) & 1) !== 0; +} + +async function isIndexed() { + const data = await db.get('O'); + assert(data); + return (data.readUInt32LE(4) & 8) !== 0; +} + +async function isMainChain(entry, tip) { + if (entry.hash === tip) + return true; + + if (await db.get(pair('n', entry.hash))) + return true; + + return false; +} + +function entryFromRaw(data) { + const br = new BufferReader(data, true); + const hash = digest.hash256(br.readBytes(80)); + + br.seek(-80); + + const entry = {}; + entry.hash = hash.toString('hex'); + entry.version = br.readU32(); + entry.prevBlock = br.readHash('hex'); + entry.merkleRoot = br.readHash('hex'); + entry.ts = br.readU32(); + entry.bits = br.readU32(); + entry.nonce = br.readU32(); + entry.height = br.readU32(); + entry.chainwork = new BN(br.readBytes(32), 'le'); + + return entry; +} + +function entryToRaw(entry, main) { + const bw = new StaticWriter(116 + 1); + + bw.writeU32(entry.version); + bw.writeHash(entry.prevBlock); + bw.writeHash(entry.merkleRoot); + bw.writeU32(entry.ts); + bw.writeU32(entry.bits); + bw.writeU32(entry.nonce); + bw.writeU32(entry.height); + bw.writeBytes(entry.chainwork.toArrayLike(Buffer, 'le', 32)); + bw.writeU8(main ? 1 : 0); + + return bw.render(); +} + +function write(data, str, off) { + if (Buffer.isBuffer(str)) + return str.copy(data, off); + return data.write(str, off, 'hex'); +} + +function pair(prefix, hash) { + const key = Buffer.allocUnsafe(33); + if (typeof prefix === 'string') + prefix = prefix.charCodeAt(0); + key[0] = prefix; + write(key, hash, 1); + return key; +} + +function bpair(prefix, hash, index) { + const key = Buffer.allocUnsafe(37); + if (typeof prefix === 'string') + prefix = prefix.charCodeAt(0); + key[0] = prefix; + write(key, hash, 1); + key.writeUInt32BE(index, 33, true); + return key; +} + +// Make eslint happy. +reserializeEntries; + +(async () => { + await db.open(); + + console.log('Opened %s.', file); + + if (await isSPV()) + hasSPV = true; + + if (await isPruned()) + hasPruned = true; + + if (await isIndexed()) + hasIndex = true; + + if (shouldPrune && hasPruned) + throw new Error('Database is already pruned.'); + + if (shouldPrune && hasSPV) + throw new Error('Database cannot be pruned due to SPV.'); + + console.log('Starting migration in 3 seconds...'); + console.log('If you crash you can start over.'); + + await co.timeout(3000); + + let [state, hash] = await readJournal(); + + if (state === STATE_VERSION) + [state, hash] = await updateVersion(); + + if (state === STATE_UNDO) + [state, hash] = await reserializeUndo(hash); + + if (state === STATE_CLEANUP) + [state, hash] = await cleanupIndex(); + + if (state === STATE_COINS) + [state, hash] = await reserializeCoins(hash); + + // if (state === STATE_ENTRY) + // [state, hash] = await reserializeEntries(hash); + + if (state === STATE_ENTRY) + [state, hash] = [STATE_FINAL, encoding.NULL_HASH]; + + if (state === STATE_FINAL) + [state, hash] = await finalize(); + + assert(state === STATE_DONE); + + console.log('Closing %s.', file); + + await db.close(); + + console.log('Migration complete.'); + process.exit(0); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/migrate/coins-old.js b/migrate/coins-old.js index 45582b48b..6eda01198 100644 --- a/migrate/coins-old.js +++ b/migrate/coins-old.js @@ -4,6 +4,8 @@ * https://github.com/bcoin-org/bcoin */ +/* eslint-disable */ + 'use strict'; const assert = require('assert'); @@ -50,7 +52,7 @@ function Coins(options) { Coins.prototype.fromOptions = function fromOptions(options) { if (options.version != null) { - assert(util.isNumber(options.version)); + assert(util.isU32(options.version)); this.version = options.version; } @@ -60,7 +62,7 @@ Coins.prototype.fromOptions = function fromOptions(options) { } if (options.height != null) { - assert(util.isNumber(options.height)); + assert(util.isInt(options.height)); this.height = options.height; } @@ -131,12 +133,10 @@ Coins.prototype.has = function has(index) { */ Coins.prototype.get = function get(index) { - let coin; - if (index >= this.outputs.length) return; - coin = this.outputs[index]; + const coin = this.outputs[index]; if (!coin) return; @@ -151,7 +151,7 @@ Coins.prototype.get = function get(index) { */ Coins.prototype.spend = function spend(index) { - let coin = this.get(index); + const coin = this.get(index); if (!coin) return; @@ -168,10 +168,9 @@ Coins.prototype.spend = function spend(index) { Coins.prototype.size = function size() { let index = -1; - let i, output; - for (i = this.outputs.length - 1; i >= 0; i--) { - output = this.outputs[i]; + for (let i = this.outputs.length - 1; i >= 0; i--) { + const output = this.outputs[i]; if (output) { index = i; break; @@ -221,10 +220,9 @@ Coins.prototype.isEmpty = function isEmpty() { */ Coins.prototype.toRaw = function toRaw() { - let bw = new BufferWriter(); - let length = this.size(); - let len = Math.ceil(length / 8); - let i, output, bits, start, bit, oct, data; + const bw = new BufferWriter(); + const length = this.size(); + const len = Math.ceil(length / 8); // Return nothing if we're fully spent. if (length === 0) @@ -236,7 +234,7 @@ Coins.prototype.toRaw = function toRaw() { // Create the `bits` value: // (height | coinbase-flag). - bits = this.height << 1; + let bits = this.height << 1; // Append the coinbase bit. if (this.coinbase) @@ -259,12 +257,12 @@ Coins.prototype.toRaw = function toRaw() { // allocating a buffer. We mark the spents // after rendering the final buffer. bw.writeVarint(len); - start = bw.written; + const start = bw.offset; bw.fill(0, len); // Write the compressed outputs. - for (i = 0; i < length; i++) { - output = this.outputs[i]; + for (let i = 0; i < length; i++) { + const output = this.outputs[i]; if (!output) continue; @@ -274,18 +272,18 @@ Coins.prototype.toRaw = function toRaw() { // Render the buffer with all // zeroes in the spent field. - data = bw.render(); + const data = bw.render(); // Mark the spents in the spent field. // This is essentially a NOP for new coins. - for (i = 0; i < length; i++) { - output = this.outputs[i]; + for (let i = 0; i < length; i++) { + const output = this.outputs[i]; if (output) continue; - bit = i % 8; - oct = (i - bit) / 8; + const bit = i % 8; + let oct = (i - bit) / 8; oct += start; data[oct] |= 1 << (7 - bit); @@ -302,13 +300,12 @@ Coins.prototype.toRaw = function toRaw() { */ Coins.prototype.fromRaw = function fromRaw(data, hash, index) { - let br = new BufferReader(data); + const br = new BufferReader(data); let pos = 0; - let bits, len, start, bit, oct, spent, coin; this.version = br.readVarint(); - bits = br.readU32(); + const bits = br.readU32(); this.height = bits >>> 1; this.hash = hash; @@ -316,17 +313,17 @@ Coins.prototype.fromRaw = function fromRaw(data, hash, index) { // Mark the start of the spent field and // seek past it to avoid reading a buffer. - len = br.readVarint(); - start = br.offset; + const len = br.readVarint(); + const start = br.offset; br.seek(len); while (br.left()) { - bit = pos % 8; - oct = (pos - bit) / 8; + const bit = pos % 8; + let oct = (pos - bit) / 8; oct += start; // Read a single bit out of the spent field. - spent = data[oct] >>> (7 - bit); + let spent = data[oct] >>> (7 - bit); spent &= 1; // Already spent. @@ -338,7 +335,7 @@ Coins.prototype.fromRaw = function fromRaw(data, hash, index) { // Store the offset and size // in the compressed coin object. - coin = CoinEntry.fromReader(br); + const coin = CoinEntry.fromReader(br); this.outputs.push(coin); pos++; @@ -356,14 +353,13 @@ Coins.prototype.fromRaw = function fromRaw(data, hash, index) { */ Coins.parseCoin = function parseCoin(data, hash, index) { - let br = new BufferReader(data); - let coin = new Coin(); + const br = new BufferReader(data); + const coin = new Coin(); let pos = 0; - let bits, len, start, bit, oct, spent; coin.version = br.readVarint(); - bits = br.readU32(); + const bits = br.readU32(); coin.hash = hash; coin.index = index; @@ -373,17 +369,17 @@ Coins.parseCoin = function parseCoin(data, hash, index) { // Mark the start of the spent field and // seek past it to avoid reading a buffer. - len = br.readVarint(); - start = br.offset; + const len = br.readVarint(); + const start = br.offset; br.seek(len); while (br.left()) { - bit = pos % 8; - oct = (pos - bit) / 8; + const bit = pos % 8; + let oct = (pos - bit) / 8; oct += start; // Read a single bit out of the spent field. - spent = data[oct] >>> (7 - bit); + let spent = data[oct] >>> (7 - bit); spent &= 1; // We found our coin. @@ -425,15 +421,13 @@ Coins.fromRaw = function fromRaw(data, hash) { */ Coins.prototype.fromTX = function fromTX(tx) { - let i, output; - this.version = tx.version; this.hash = tx.hash('hex'); this.height = tx.height; this.coinbase = tx.isCoinbase(); - for (i = 0; i < tx.outputs.length; i++) { - output = tx.outputs[i]; + for (let i = 0; i < tx.outputs.length; i++) { + const output = tx.outputs[i]; if (output.script.isUnspendable()) { this.outputs.push(null); @@ -490,8 +484,7 @@ function CoinEntry() { */ CoinEntry.prototype.toCoin = function toCoin(coins, index) { - let coin = new Coin(); - let br; + const coin = new Coin(); // Load in all necessary properties // from the parent Coins object. @@ -507,7 +500,7 @@ CoinEntry.prototype.toCoin = function toCoin(coins, index) { return coin; } - br = new BufferReader(this.raw); + const br = new BufferReader(this.raw); // Seek to the coin's offset. br.seek(this.offset); @@ -525,8 +518,6 @@ CoinEntry.prototype.toCoin = function toCoin(coins, index) { */ CoinEntry.prototype.toWriter = function toWriter(bw) { - let raw; - if (this.output) { compress.script(this.output.script, bw); bw.writeVarint(this.output.value); @@ -539,7 +530,7 @@ CoinEntry.prototype.toWriter = function toWriter(bw) { // didn't use it, it's still in its // compressed form. Just write it back // as a buffer for speed. - raw = this.raw.slice(this.offset, this.offset + this.size); + const raw = this.raw.slice(this.offset, this.offset + this.size); bw.writeBytes(raw); }; @@ -551,7 +542,7 @@ CoinEntry.prototype.toWriter = function toWriter(bw) { */ CoinEntry.fromReader = function fromReader(br) { - let entry = new CoinEntry(); + const entry = new CoinEntry(); entry.offset = br.offset; entry.size = skipCoin(br); entry.raw = br.data; @@ -566,7 +557,7 @@ CoinEntry.fromReader = function fromReader(br) { */ CoinEntry.fromTX = function fromTX(tx, index) { - let entry = new CoinEntry(); + const entry = new CoinEntry(); entry.output = tx.outputs[index]; return entry; }; @@ -578,7 +569,7 @@ CoinEntry.fromTX = function fromTX(tx, index) { */ CoinEntry.fromCoin = function fromCoin(coin) { - let entry = new CoinEntry(); + const entry = new CoinEntry(); entry.output = new Output(); entry.output.script = coin.script; entry.output.value = coin.value; @@ -590,7 +581,7 @@ CoinEntry.fromCoin = function fromCoin(coin) { */ function skipCoin(br) { - let start = br.offset; + const start = br.offset; // Skip past the compressed scripts. switch (br.readU8()) { diff --git a/migrate/coins/coins.js b/migrate/coins/coins.js new file mode 100644 index 000000000..9aaf1c9b8 --- /dev/null +++ b/migrate/coins/coins.js @@ -0,0 +1,756 @@ +/*! + * coins.js - coins object for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +/* eslint-disable */ + +'use strict'; + +const assert = require('assert'); +const util = require('../../lib/utils/util'); +const Coin = require('../../lib/primitives/coin'); +const Output = require('../../lib/primitives/output'); +const BufferReader = require('../../lib/utils/reader'); +const StaticWriter = require('../../lib/utils/staticwriter'); +const encoding = require('../../lib/utils/encoding'); +const compressor = require('./compress'); +const compress = compressor.compress; +const decompress = compressor.decompress; + +/** + * Represents the outputs for a single transaction. + * @alias module:coins.Coins + * @constructor + * @param {Object?} options - Options object. + * @property {Hash} hash - Transaction hash. + * @property {Number} version - Transaction version. + * @property {Number} height - Transaction height (-1 if unconfirmed). + * @property {Boolean} coinbase - Whether the containing + * transaction is a coinbase. + * @property {CoinEntry[]} outputs - Coins. + */ + +function Coins(options) { + if (!(this instanceof Coins)) + return new Coins(options); + + this.version = 1; + this.hash = encoding.NULL_HASH; + this.height = -1; + this.coinbase = true; + this.outputs = []; + + if (options) + this.fromOptions(options); +} + +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + +Coins.prototype.fromOptions = function fromOptions(options) { + if (options.version != null) { + assert(util.isU32(options.version)); + this.version = options.version; + } + + if (options.hash) { + assert(typeof options.hash === 'string'); + this.hash = options.hash; + } + + if (options.height != null) { + assert(util.isInt(options.height)); + this.height = options.height; + } + + if (options.coinbase != null) { + assert(typeof options.coinbase === 'boolean'); + this.coinbase = options.coinbase; + } + + if (options.outputs) { + assert(Array.isArray(options.outputs)); + this.outputs = options.outputs; + this.cleanup(); + } + + return this; +}; + +/** + * Instantiate coins from options object. + * @param {Object} options + * @returns {Coins} + */ + +Coins.fromOptions = function fromOptions(options) { + return new Coins().fromOptions(options); +}; + +/** + * Add a single entry to the collection. + * @param {Number} index + * @param {CoinEntry} entry + */ + +Coins.prototype.add = function add(index, entry) { + assert(index >= 0); + + while (this.outputs.length <= index) + this.outputs.push(null); + + assert(!this.outputs[index]); + + this.outputs[index] = entry; +}; + +/** + * Add a single output to the collection. + * @param {Number} index + * @param {Output} output + */ + +Coins.prototype.addOutput = function addOutput(index, output) { + assert(!output.script.isUnspendable()); + this.add(index, CoinEntry.fromOutput(output)); +}; + +/** + * Add a single coin to the collection. + * @param {Coin} coin + */ + +Coins.prototype.addCoin = function addCoin(coin) { + assert(!coin.script.isUnspendable()); + this.add(coin.index, CoinEntry.fromCoin(coin)); +}; + +/** + * Test whether the collection has a coin. + * @param {Number} index + * @returns {Boolean} + */ + +Coins.prototype.has = function has(index) { + if (index >= this.outputs.length) + return false; + + return this.outputs[index] != null; +}; + +/** + * Test whether the collection + * has an unspent coin. + * @param {Number} index + * @returns {Boolean} + */ + +Coins.prototype.isUnspent = function isUnspent(index) { + if (index >= this.outputs.length) + return false; + + const output = this.outputs[index]; + + if (!output || output.spent) + return false; + + return true; +}; + +/** + * Get a coin entry. + * @param {Number} index + * @returns {CoinEntry} + */ + +Coins.prototype.get = function get(index) { + if (index >= this.outputs.length) + return; + + return this.outputs[index]; +}; + +/** + * Get an output. + * @param {Number} index + * @returns {Output} + */ + +Coins.prototype.getOutput = function getOutput(index) { + const entry = this.get(index); + + if (!entry) + return; + + return entry.toOutput(); +}; + +/** + * Get a coin. + * @param {Number} index + * @returns {Coin} + */ + +Coins.prototype.getCoin = function getCoin(index) { + const entry = this.get(index); + + if (!entry) + return; + + return entry.toCoin(this, index); +}; + +/** + * Spend a coin entry and return it. + * @param {Number} index + * @returns {CoinEntry} + */ + +Coins.prototype.spend = function spend(index) { + const entry = this.get(index); + + if (!entry || entry.spent) + return; + + entry.spent = true; + + return entry; +}; + +/** + * Remove a coin entry and return it. + * @param {Number} index + * @returns {CoinEntry} + */ + +Coins.prototype.remove = function remove(index) { + const entry = this.get(index); + + if (!entry) + return false; + + this.outputs[index] = null; + this.cleanup(); + + return entry; +}; + +/** + * Calculate unspent length of coins. + * @returns {Number} + */ + +Coins.prototype.length = function length() { + let len = this.outputs.length; + + while (len > 0 && !this.isUnspent(len - 1)) + len--; + + return len; +}; + +/** + * Cleanup spent outputs (remove pruned). + */ + +Coins.prototype.cleanup = function cleanup() { + let len = this.outputs.length; + + while (len > 0 && !this.outputs[len - 1]) + len--; + + this.outputs.length = len; +}; + +/** + * Test whether the coins are fully spent. + * @returns {Boolean} + */ + +Coins.prototype.isEmpty = function isEmpty() { + return this.length() === 0; +}; + +/* + * Coins serialization: + * version: varint + * height: uint32 + * header-code: varint + * bit 1: coinbase + * bit 2: first output unspent + * bit 3: second output unspent + * bit 4-32: spent-field size + * spent-field: bitfield (0=spent, 1=unspent) + * outputs (repeated): + * value: varint + * compressed-script: + * prefix: 0x00 = 20 byte pubkey hash + * 0x01 = 20 byte script hash + * 0x02-0x05 = 32 byte ec-key x-value + * 0x06-0x09 = reserved + * >=0x10 = varint-size + 10 | raw script + * data: script data, dictated by the prefix + * + * The compression below sacrifices some cpu in exchange + * for reduced size, but in some cases the use of varints + * actually increases speed (varint versions and values + * for example). We do as much compression as possible + * without sacrificing too much cpu. Value compression + * is intentionally excluded for now as it seems to be + * too much of a perf hit. Maybe when v8 optimizes + * non-smi arithmetic better we can enable it. + */ + +/** + * Calculate header code. + * @param {Number} len + * @param {Number} size + * @returns {Number} + */ + +Coins.prototype.header = function header(len, size) { + const first = this.isUnspent(0); + const second = this.isUnspent(1); + let offset = 0; + + // Throw if we're fully spent. + assert(len !== 0, 'Cannot serialize fully-spent coins.'); + + // First and second bits + // have a double meaning. + if (!first && !second) { + assert(size !== 0); + offset = 1; + } + + // Calculate header code. + let code = 8 * (size - offset); + + if (this.coinbase) + code += 1; + + if (first) + code += 2; + + if (second) + code += 4; + + return code; +}; + +/** + * Serialize the coins object. + * @returns {Buffer} + */ + +Coins.prototype.toRaw = function toRaw() { + const len = this.length(); + const size = Math.floor((len + 5) / 8); + const code = this.header(len, size); + const total = this.getSize(len, size, code); + const bw = new StaticWriter(total); + + // Write headers. + bw.writeVarint(this.version); + bw.writeU32(this.height); + bw.writeVarint(code); + + // Write the spent field. + for (let i = 0; i < size; i++) { + let ch = 0; + for (let j = 0; j < 8 && 2 + i * 8 + j < len; j++) { + if (this.isUnspent(2 + i * 8 + j)) + ch |= 1 << j; + } + bw.writeU8(ch); + } + + // Write the compressed outputs. + for (let i = 0; i < len; i++) { + const output = this.outputs[i]; + + if (!output || output.spent) + continue; + + output.toWriter(bw); + } + + return bw.render(); +}; + +/** + * Calculate coins size. + * @param {Number} code + * @param {Number} size + * @param {Number} len + * @returns {Number} + */ + +Coins.prototype.getSize = function getSize(len, size, code) { + let total = 0; + + total += encoding.sizeVarint(this.version); + total += 4; + total += encoding.sizeVarint(code); + total += size; + + // Write the compressed outputs. + for (let i = 0; i < len; i++) { + const output = this.outputs[i]; + + if (!output || output.spent) + continue; + + total += output.getSize(); + } + + return total; +}; + +/** + * Inject data from serialized coins. + * @private + * @param {Buffer} data + * @param {Hash} hash + * @returns {Coins} + */ + +Coins.prototype.fromRaw = function fromRaw(data, hash) { + const br = new BufferReader(data); + let first = null; + let second = null; + + // Inject hash (passed by caller). + this.hash = hash; + + // Read headers. + this.version = br.readVarint(); + this.height = br.readU32(); + const code = br.readVarint(); + this.coinbase = (code & 1) !== 0; + + // Recalculate size. + let size = code / 8 | 0; + + if ((code & 6) === 0) + size += 1; + + // Setup spent field. + let offset = br.offset; + br.seek(size); + + // Read first two outputs. + if ((code & 2) !== 0) + first = CoinEntry.fromReader(br); + + if ((code & 4) !== 0) + second = CoinEntry.fromReader(br); + + this.outputs.push(first); + this.outputs.push(second); + + // Read outputs. + for (let i = 0; i < size; i++) { + const ch = br.data[offset++]; + for (let j = 0; j < 8; j++) { + if ((ch & (1 << j)) === 0) { + this.outputs.push(null); + continue; + } + this.outputs.push(CoinEntry.fromReader(br)); + } + } + + this.cleanup(); + + return this; +}; + +/** + * Parse a single serialized coin. + * @param {Buffer} data + * @param {Hash} hash + * @param {Number} index + * @returns {Coin} + */ + +Coins.parseCoin = function parseCoin(data, hash, index) { + const br = new BufferReader(data); + const coin = new Coin(); + + // Inject outpoint (passed by caller). + coin.hash = hash; + coin.index = index; + + // Read headers. + coin.version = br.readVarint(); + coin.height = br.readU32(); + const code = br.readVarint(); + coin.coinbase = (code & 1) !== 0; + + // Recalculate size. + let size = code / 8 | 0; + + if ((code & 6) === 0) + size += 1; + + if (index >= 2 + size * 8) + return; + + // Setup spent field. + let offset = br.offset; + br.seek(size); + + // Read first two outputs. + for (let i = 0; i < 2; i++) { + if ((code & (2 << i)) !== 0) { + if (index === 0) { + decompress.coin(coin, br); + return coin; + } + decompress.skip(br); + } else { + if (index === 0) + return; + } + index -= 1; + } + + // Read outputs. + for (let i = 0; i < size; i++) { + const ch = br.data[offset++]; + for (let j = 0; j < 8; j++) { + if ((ch & (1 << j)) !== 0) { + if (index === 0) { + decompress.coin(coin, br); + return coin; + } + decompress.skip(br); + } else { + if (index === 0) + return; + } + index -= 1; + } + } +}; + +/** + * Instantiate coins from a buffer. + * @param {Buffer} data + * @param {Hash} hash - Transaction hash. + * @returns {Coins} + */ + +Coins.fromRaw = function fromRaw(data, hash) { + return new Coins().fromRaw(data, hash); +}; + +/** + * Inject properties from tx. + * @private + * @param {TX} tx + * @param {Number} height + */ + +Coins.prototype.fromTX = function fromTX(tx, height) { + assert(typeof height === 'number'); + + this.version = tx.version; + this.hash = tx.hash('hex'); + this.height = height; + this.coinbase = tx.isCoinbase(); + + for (const output of tx.outputs) { + if (output.script.isUnspendable()) { + this.outputs.push(null); + continue; + } + this.outputs.push(CoinEntry.fromOutput(output)); + } + + this.cleanup(); + + return this; +}; + +/** + * Instantiate a coins object from a transaction. + * @param {TX} tx + * @param {Number} height + * @returns {Coins} + */ + +Coins.fromTX = function fromTX(tx, height) { + return new Coins().fromTX(tx, height); +}; + +/** + * A coin entry is an object which defers + * parsing of a coin. Say there is a transaction + * with 100 outputs. When a block comes in, + * there may only be _one_ input in that entire + * block which redeems an output from that + * transaction. When parsing the Coins, there + * is no sense to get _all_ of them into their + * abstract form. A coin entry is just a + * pointer to that coin in the Coins buffer, as + * well as a size. Parsing and decompression + * is done only if that coin is being redeemed. + * @alias module:coins.CoinEntry + * @constructor + * @property {Number} offset + * @property {Number} size + * @property {Buffer} raw + * @property {Output|null} output + * @property {Boolean} spent + */ + +function CoinEntry() { + this.offset = 0; + this.size = 0; + this.raw = null; + this.output = null; + this.spent = false; +} + +/** + * Instantiate a reader at the correct offset. + * @private + * @returns {BufferReader} + */ + +CoinEntry.prototype.reader = function reader() { + assert(this.raw); + + const br = new BufferReader(this.raw); + br.offset = this.offset; + + return br; +}; + +/** + * Parse the deferred data and return a coin. + * @param {Coins} coins + * @param {Number} index + * @returns {Coin} + */ + +CoinEntry.prototype.toCoin = function toCoin(coins, index) { + const coin = new Coin(); + const output = this.toOutput(); + + // Load in all necessary properties + // from the parent Coins object. + coin.version = coins.version; + coin.coinbase = coins.coinbase; + coin.height = coins.height; + coin.hash = coins.hash; + coin.index = index; + coin.script = output.script; + coin.value = output.value; + + return coin; +}; + +/** + * Parse the deferred data and return an output. + * @returns {Output} + */ + +CoinEntry.prototype.toOutput = function toOutput() { + if (!this.output) { + this.output = new Output(); + decompress.output(this.output, this.reader()); + } + return this.output; +}; + +/** + * Calculate coin entry size. + * @returns {Number} + */ + +CoinEntry.prototype.getSize = function getSize() { + if (!this.raw) + return compress.size(this.output); + + return this.size; +}; + +/** + * Slice off the part of the buffer + * relevant to this particular coin. + */ + +CoinEntry.prototype.toWriter = function toWriter(bw) { + if (!this.raw) { + assert(this.output); + compress.output(this.output, bw); + return bw; + } + + // If we read this coin from the db and + // didn't use it, it's still in its + // compressed form. Just write it back + // as a buffer for speed. + bw.copy(this.raw, this.offset, this.offset + this.size); + + return bw; +}; + +/** + * Instantiate coin entry from reader. + * @param {BufferReader} br + * @returns {CoinEntry} + */ + +CoinEntry.fromReader = function fromReader(br) { + const entry = new CoinEntry(); + entry.offset = br.offset; + entry.size = decompress.skip(br); + entry.raw = br.data; + return entry; +}; + +/** + * Instantiate coin entry from output. + * @param {Output} output + * @returns {CoinEntry} + */ + +CoinEntry.fromOutput = function fromOutput(output) { + const entry = new CoinEntry(); + entry.output = output; + return entry; +}; + +/** + * Instantiate coin entry from coin. + * @param {Coin} coin + * @returns {CoinEntry} + */ + +CoinEntry.fromCoin = function fromCoin(coin) { + const entry = new CoinEntry(); + const output = new Output(); + output.value = coin.value; + output.script = coin.script; + entry.output = output; + return entry; +}; + +/* + * Expose + */ + +exports = Coins; +exports.Coins = Coins; +exports.CoinEntry = CoinEntry; + +module.exports = exports; diff --git a/migrate/coins/coinview.js b/migrate/coins/coinview.js new file mode 100644 index 000000000..91b9e4257 --- /dev/null +++ b/migrate/coins/coinview.js @@ -0,0 +1,476 @@ +/*! + * coinview.js - coin viewpoint object for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +/* eslint-disable */ + +'use strict'; + +const assert = require('assert'); +const Coins = require('./coins'); +const UndoCoins = require('./undocoins'); +const CoinEntry = Coins.CoinEntry; + +/** + * Represents a coin viewpoint: + * a snapshot of {@link Coins} objects. + * @alias module:coins.CoinView + * @constructor + * @property {Object} map + * @property {UndoCoins} undo + */ + +function CoinView() { + if (!(this instanceof CoinView)) + return new CoinView(); + + this.map = new Map(); + this.undo = new UndoCoins(); +} + +/** + * Get coins. + * @param {Hash} hash + * @returns {Coins} coins + */ + +CoinView.prototype.get = function get(hash) { + return this.map.get(hash); +}; + +/** + * Test whether the view has an entry. + * @param {Hash} hash + * @returns {Boolean} + */ + +CoinView.prototype.has = function has(hash) { + return this.map.has(hash); +}; + +/** + * Add coins to the collection. + * @param {Coins} coins + */ + +CoinView.prototype.add = function add(coins) { + this.map.set(coins.hash, coins); + return coins; +}; + +/** + * Remove coins from the collection. + * @param {Coins} coins + * @returns {Boolean} + */ + +CoinView.prototype.remove = function remove(hash) { + if (!this.map.has(hash)) + return false; + + this.map.delete(hash); + + return true; +}; + +/** + * Add a tx to the collection. + * @param {TX} tx + * @param {Number} height + */ + +CoinView.prototype.addTX = function addTX(tx, height) { + const coins = Coins.fromTX(tx, height); + return this.add(coins); +}; + +/** + * Remove a tx from the collection. + * @param {TX} tx + * @param {Number} height + */ + +CoinView.prototype.removeTX = function removeTX(tx, height) { + const coins = Coins.fromTX(tx, height); + coins.outputs.length = 0; + return this.add(coins); +}; + +/** + * Add a coin to the collection. + * @param {Coin} coin + */ + +CoinView.prototype.addCoin = function addCoin(coin) { + let coins = this.get(coin.hash); + + if (!coins) { + coins = new Coins(); + coins.hash = coin.hash; + coins.height = coin.height; + coins.coinbase = coin.coinbase; + this.add(coins); + } + + if (coin.script.isUnspendable()) + return; + + if (!coins.has(coin.index)) + coins.addCoin(coin); +}; + +/** + * Add an output to the collection. + * @param {Hash} hash + * @param {Number} index + * @param {Output} output + */ + +CoinView.prototype.addOutput = function addOutput(hash, index, output) { + let coins = this.get(hash); + + if (!coins) { + coins = new Coins(); + coins.hash = hash; + coins.height = -1; + coins.coinbase = false; + this.add(coins); + } + + if (output.script.isUnspendable()) + return; + + if (!coins.has(index)) + coins.addOutput(index, output); +}; + +/** + * Spend an output. + * @param {Hash} hash + * @param {Number} index + * @returns {Boolean} + */ + +CoinView.prototype.spendOutput = function spendOutput(hash, index) { + const coins = this.get(hash); + + if (!coins) + return false; + + return this.spendFrom(coins, index); +}; + +/** + * Remove an output. + * @param {Hash} hash + * @param {Number} index + * @returns {Boolean} + */ + +CoinView.prototype.removeOutput = function removeOutput(hash, index) { + const coins = this.get(hash); + + if (!coins) + return false; + + return coins.remove(index); +}; + +/** + * Spend a coin from coins object. + * @param {Coins} coins + * @param {Number} index + * @returns {Boolean} + */ + +CoinView.prototype.spendFrom = function spendFrom(coins, index) { + const entry = coins.spend(index); + + if (!entry) + return false; + + this.undo.push(entry); + + if (coins.isEmpty()) { + const undo = this.undo.top(); + undo.height = coins.height; + undo.coinbase = coins.coinbase; + undo.version = coins.version; + assert(undo.height !== -1); + } + + return true; +}; + +/** + * Get a single coin by input. + * @param {Input} input + * @returns {Coin} + */ + +CoinView.prototype.getCoin = function getCoin(input) { + const coins = this.get(input.prevout.hash); + + if (!coins) + return; + + return coins.getCoin(input.prevout.index); +}; + +/** + * Get a single output by input. + * @param {Input} input + * @returns {Output} + */ + +CoinView.prototype.getOutput = function getOutput(input) { + const coins = this.get(input.prevout.hash); + + if (!coins) + return; + + return coins.getOutput(input.prevout.index); +}; + +/** + * Get a single entry by input. + * @param {Input} input + * @returns {CoinEntry} + */ + +CoinView.prototype.getEntry = function getEntry(input) { + const coins = this.get(input.prevout.hash); + + if (!coins) + return; + + return coins.get(input.prevout.index); +}; + +/** + * Test whether the view has an entry by input. + * @param {Input} input + * @returns {Boolean} + */ + +CoinView.prototype.hasEntry = function hasEntry(input) { + const coins = this.get(input.prevout.hash); + + if (!coins) + return false; + + return coins.has(input.prevout.index); +}; + +/** + * Get coins height by input. + * @param {Input} input + * @returns {Number} + */ + +CoinView.prototype.getHeight = function getHeight(input) { + const coins = this.get(input.prevout.hash); + + if (!coins) + return -1; + + return coins.height; +}; + +/** + * Get coins coinbase flag by input. + * @param {Input} input + * @returns {Boolean} + */ + +CoinView.prototype.isCoinbase = function isCoinbase(input) { + const coins = this.get(input.prevout.hash); + + if (!coins) + return false; + + return coins.coinbase; +}; + +/** + * Retrieve coins from database. + * @method + * @param {ChainDB} db + * @param {TX} tx + * @returns {Promise} - Returns {@link Coins}. + */ + +CoinView.prototype.readCoins = async function readCoins(db, hash) { + let coins = this.map.get(hash); + + if (!coins) { + coins = await db.getCoins(hash); + + if (!coins) + return; + + this.map.set(hash, coins); + } + + return coins; +}; + +/** + * Read all input coins into unspent map. + * @method + * @param {ChainDB} db + * @param {TX} tx + * @returns {Promise} - Returns {Boolean}. + */ + +CoinView.prototype.ensureInputs = async function ensureInputs(db, tx) { + let found = true; + + for (const input of tx.inputs) { + if (!await this.readCoins(db, input.prevout.hash)) + found = false; + } + + return found; +}; + +/** + * Spend coins for transaction. + * @method + * @param {ChainDB} db + * @param {TX} tx + * @returns {Promise} - Returns {Boolean}. + */ + +CoinView.prototype.spendInputs = async function spendInputs(db, tx) { + for (const input of tx.inputs) { + const prevout = input.prevout; + const coins = await this.readCoins(db, prevout.hash); + + if (!coins) + return false; + + if (!this.spendFrom(coins, prevout.index)) + return false; + } + + return true; +}; + +/** + * Convert collection to an array. + * @returns {Coins[]} + */ + +CoinView.prototype.toArray = function toArray() { + const out = []; + + for (const coins of this.map.values()) + out.push(coins); + + return out; +}; + +/** + * Calculate serialization size. + * @returns {Number} + */ + +CoinView.prototype.getSize = function getSize(tx) { + let size = 0; + + size += tx.inputs.length; + + for (const input of tx.inputs) { + const entry = this.getEntry(input); + + if (!entry) + continue; + + size += entry.getSize(); + } + + return size; +}; + +/** + * Write coin data to buffer writer + * as it pertains to a transaction. + * @param {BufferWriter} bw + * @param {TX} tx + */ + +CoinView.prototype.toWriter = function toWriter(bw, tx) { + for (const input of tx.inputs) { + const prevout = input.prevout; + const coins = this.get(prevout.hash); + + if (!coins) { + bw.writeU8(0); + continue; + } + + const entry = coins.get(prevout.index); + + if (!entry) { + bw.writeU8(0); + continue; + } + + bw.writeU8(1); + entry.toWriter(bw); + } + + return bw; +}; + +/** + * Read serialized view data from a buffer + * reader as it pertains to a transaction. + * @private + * @param {BufferReader} br + * @param {TX} tx + */ + +CoinView.prototype.fromReader = function fromReader(br, tx) { + for (const input of tx.inputs) { + const prevout = input.prevout; + + if (br.readU8() === 0) + continue; + + let coins = this.get(prevout.hash); + + if (!coins) { + coins = new Coins(); + coins.hash = prevout.hash; + coins.coinbase = false; + this.add(coins); + } + + const entry = CoinEntry.fromReader(br); + coins.add(prevout.index, entry); + } + + return this; +}; + +/** + * Read serialized view data from a buffer + * reader as it pertains to a transaction. + * @param {BufferReader} br + * @param {TX} tx + * @returns {CoinView} + */ + +CoinView.fromReader = function fromReader(br, tx) { + return new CoinView().fromReader(br, tx); +}; + +/* + * Expose + */ + +module.exports = CoinView; diff --git a/migrate/coins/compress.js b/migrate/coins/compress.js new file mode 100644 index 000000000..455780c1e --- /dev/null +++ b/migrate/coins/compress.js @@ -0,0 +1,413 @@ +/*! + * compress.js - coin compressor for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +/* eslint-disable */ + +'use strict'; + +/** + * @module coins/compress + * @ignore + */ + +const assert = require('assert'); +const secp256k1 = require('../../lib/crypto/secp256k1'); +const encoding = require('../../lib/utils/encoding'); +const consensus = require('../../lib/protocol/consensus'); + +/* + * Constants + */ + +const COMPRESS_TYPES = 10; // Space for 4 extra. +const EMPTY_BUFFER = Buffer.alloc(0); + +/** + * Compress a script, write directly to the buffer. + * @param {Script} script + * @param {BufferWriter} bw + */ + +function compressScript(script, bw) { + // Attempt to compress the output scripts. + // We can _only_ ever compress them if + // they are serialized as minimaldata, as + // we need to recreate them when we read + // them. + + // P2PKH -> 0 | key-hash + // Saves 5 bytes. + if (script.isPubkeyhash(true)) { + const data = script.code[2].data; + bw.writeU8(0); + bw.writeBytes(data); + return bw; + } + + // P2SH -> 1 | script-hash + // Saves 3 bytes. + if (script.isScripthash()) { + const data = script.code[1].data; + bw.writeU8(1); + bw.writeBytes(data); + return bw; + } + + // P2PK -> 2-5 | compressed-key + // Only works if the key is valid. + // Saves up to 35 bytes. + if (script.isPubkey(true)) { + let data = script.code[0].data; + if (publicKeyVerify(data)) { + data = compressKey(data); + bw.writeBytes(data); + return bw; + } + } + + // Raw -> varlen + 10 | script + bw.writeVarint(script.raw.length + COMPRESS_TYPES); + bw.writeBytes(script.raw); + + return bw; +} + +/** + * Decompress a script from buffer reader. + * @param {Script} script + * @param {BufferReader} br + */ + +function decompressScript(script, br) { + let size, data; + + // Decompress the script. + switch (br.readU8()) { + case 0: + data = br.readBytes(20, true); + script.fromPubkeyhash(data); + break; + case 1: + data = br.readBytes(20, true); + script.fromScripthash(data); + break; + case 2: + case 3: + case 4: + case 5: + br.offset -= 1; + data = br.readBytes(33, true); + // Decompress the key. If this fails, + // we have database corruption! + data = decompressKey(data); + script.fromPubkey(data); + break; + default: + br.offset -= 1; + size = br.readVarint() - COMPRESS_TYPES; + if (size > consensus.MAX_SCRIPT_SIZE) { + // This violates consensus rules. + // We don't need to read it. + script.fromNulldata(EMPTY_BUFFER); + br.seek(size); + } else { + data = br.readBytes(size); + script.fromRaw(data); + } + break; + } + + return script; +} + +/** + * Calculate script size. + * @returns {Number} + */ + +function sizeScript(script) { + if (script.isPubkeyhash(true)) + return 21; + + if (script.isScripthash()) + return 21; + + if (script.isPubkey(true)) { + const data = script.code[0].data; + if (publicKeyVerify(data)) + return 33; + } + + let size = 0; + size += encoding.sizeVarint(script.raw.length + COMPRESS_TYPES); + size += script.raw.length; + + return size; +} + +/** + * Compress an output. + * @param {Output} output + * @param {BufferWriter} bw + */ + +function compressOutput(output, bw) { + bw.writeVarint(output.value); + compressScript(output.script, bw); + return bw; +} + +/** + * Decompress a script from buffer reader. + * @param {Output} output + * @param {BufferReader} br + */ + +function decompressOutput(output, br) { + output.value = br.readVarint(); + decompressScript(output.script, br); + return output; +} + +/** + * Calculate output size. + * @returns {Number} + */ + +function sizeOutput(output) { + let size = 0; + size += encoding.sizeVarint(output.value); + size += sizeScript(output.script); + return size; +} + +/** + * Compress an output. + * @param {Coin} coin + * @param {BufferWriter} bw + */ + +function compressCoin(coin, bw) { + bw.writeVarint(coin.value); + compressScript(coin.script, bw); + return bw; +} + +/** + * Decompress a script from buffer reader. + * @param {Coin} coin + * @param {BufferReader} br + */ + +function decompressCoin(coin, br) { + coin.value = br.readVarint(); + decompressScript(coin.script, br); + return coin; +} + +/** + * Skip past a compressed output. + * @param {BufferWriter} bw + * @returns {Number} + */ + +function skipOutput(br) { + const start = br.offset; + + // Skip past the value. + br.skipVarint(); + + // Skip past the compressed scripts. + switch (br.readU8()) { + case 0: + case 1: + br.seek(20); + break; + case 2: + case 3: + case 4: + case 5: + br.seek(32); + break; + default: + br.offset -= 1; + br.seek(br.readVarint() - COMPRESS_TYPES); + break; + } + + return br.offset - start; +} + +/** + * Compress value using an exponent. Takes advantage of + * the fact that many bitcoin values are divisible by 10. + * @see https://github.com/btcsuite/btcd/blob/master/blockchain/compress.go + * @param {Amount} value + * @returns {Number} + */ + +function compressValue(value) { + if (value === 0) + return 0; + + let exp = 0; + while (value % 10 === 0 && exp < 9) { + value /= 10; + exp++; + } + + if (exp < 9) { + const last = value % 10; + value = (value - last) / 10; + return 1 + 10 * (9 * value + last - 1) + exp; + } + + return 10 + 10 * (value - 1); +} + +/** + * Decompress value. + * @param {Number} value - Compressed value. + * @returns {Amount} value + */ + +function decompressValue(value) { + if (value === 0) + return 0; + + value--; + + let exp = value % 10; + value = (value - exp) / 10; + + let n; + if (exp < 9) { + const last = value % 9; + value = (value - last) / 9; + n = value * 10 + last + 1; + } else { + n = value + 1; + } + + while (exp > 0) { + n *= 10; + exp--; + } + + return n; +} + +/** + * Verify a public key (no hybrid keys allowed). + * @param {Buffer} key + * @returns {Boolean} + */ + +function publicKeyVerify(key) { + if (key.length === 0) + return false; + + switch (key[0]) { + case 0x02: + case 0x03: + return key.length === 33; + case 0x04: + if (key.length !== 65) + return false; + + return secp256k1.publicKeyVerify(key); + default: + return false; + } +} + +/** + * Compress a public key to coins compression format. + * @param {Buffer} key + * @returns {Buffer} + */ + +function compressKey(key) { + let out; + + switch (key[0]) { + case 0x02: + case 0x03: + // Key is already compressed. + out = key; + break; + case 0x04: + // Compress the key normally. + out = secp256k1.publicKeyConvert(key, true); + // Store the oddness. + // Pseudo-hybrid format. + out[0] = 0x04 | (key[64] & 0x01); + break; + default: + throw new Error('Bad point format.'); + } + + assert(out.length === 33); + + return out; +} + +/** + * Decompress a public key from the coins compression format. + * @param {Buffer} key + * @returns {Buffer} + */ + +function decompressKey(key) { + const format = key[0]; + + assert(key.length === 33); + + switch (format) { + case 0x02: + case 0x03: + return key; + case 0x04: + key[0] = 0x02; + break; + case 0x05: + key[0] = 0x03; + break; + default: + throw new Error('Bad point format.'); + } + + // Decompress the key. + const out = secp256k1.publicKeyConvert(key, false); + + // Reset the first byte so as not to + // mutate the original buffer. + key[0] = format; + + return out; +} + +/* + * Expose + */ + +exports.compress = { + output: compressOutput, + coin: compressCoin, + size: sizeOutput, + script: compressScript, + value: compressValue, + key: compressKey +}; + +exports.decompress = { + output: decompressOutput, + coin: decompressCoin, + skip: skipOutput, + script: decompressScript, + value: decompressValue, + key: decompressKey +}; diff --git a/migrate/coins/index.js b/migrate/coins/index.js new file mode 100644 index 000000000..514c09db5 --- /dev/null +++ b/migrate/coins/index.js @@ -0,0 +1,16 @@ +/*! + * coins/index.js - utxo management for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module coins + */ + +exports.Coins = require('../../lib/coins/coins'); +exports.CoinView = require('../../lib/coins/coinview'); +exports.compress = require('../../lib/coins/compress'); +exports.UndoCoins = require('../../lib/coins/undocoins'); diff --git a/migrate/coins/undocoins.js b/migrate/coins/undocoins.js new file mode 100644 index 000000000..0e9acedde --- /dev/null +++ b/migrate/coins/undocoins.js @@ -0,0 +1,338 @@ +/*! + * undocoins.js - undocoins object for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +/* eslint-disable */ + +'use strict'; + +const assert = require('assert'); +const BufferReader = require('../../lib/utils/reader'); +const StaticWriter = require('../../lib/utils/staticwriter'); +const encoding = require('../../lib/utils/encoding'); +const Output = require('../../lib/primitives/output'); +const Coins = require('./coins'); +const compressor = require('./compress'); +const compress = compressor.compress; +const decompress = compressor.decompress; + +/** + * UndoCoins + * Coins need to be resurrected from somewhere + * during a reorg. The undo coins store all + * spent coins in a single record per block + * (in a compressed format). + * @alias module:coins.UndoCoins + * @constructor + * @property {UndoCoin[]} items + */ + +function UndoCoins() { + if (!(this instanceof UndoCoins)) + return new UndoCoins(); + + this.items = []; +} + +/** + * Push coin entry onto undo coin array. + * @param {CoinEntry} + */ + +UndoCoins.prototype.push = function push(entry) { + const undo = new UndoCoin(); + undo.entry = entry; + this.items.push(undo); +}; + +/** + * Calculate undo coins size. + * @returns {Number} + */ + +UndoCoins.prototype.getSize = function getSize() { + let size = 0; + + size += 4; + + for (const coin of this.items) + size += coin.getSize(); + + return size; +}; + +/** + * Serialize all undo coins. + * @returns {Buffer} + */ + +UndoCoins.prototype.toRaw = function toRaw() { + const size = this.getSize(); + const bw = new StaticWriter(size); + + bw.writeU32(this.items.length); + + for (const coin of this.items) + coin.toWriter(bw); + + return bw.render(); +}; + +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + * @returns {UndoCoins} + */ + +UndoCoins.prototype.fromRaw = function fromRaw(data) { + const br = new BufferReader(data); + const count = br.readU32(); + + for (let i = 0; i < count; i++) + this.items.push(UndoCoin.fromReader(br)); + + return this; +}; + +/** + * Instantiate undo coins from serialized data. + * @param {Buffer} data + * @returns {UndoCoins} + */ + +UndoCoins.fromRaw = function fromRaw(data) { + return new UndoCoins().fromRaw(data); +}; + +/** + * Test whether the undo coins have any members. + * @returns {Boolean} + */ + +UndoCoins.prototype.isEmpty = function isEmpty() { + return this.items.length === 0; +}; + +/** + * Render the undo coins. + * @returns {Buffer} + */ + +UndoCoins.prototype.commit = function commit() { + const raw = this.toRaw(); + this.items.length = 0; + return raw; +}; + +/** + * Retrieve the last undo coin. + * @returns {UndoCoin} + */ + +UndoCoins.prototype.top = function top() { + return this.items[this.items.length - 1]; +}; + +/** + * Re-apply undo coins to a view, effectively unspending them. + * @param {CoinView} view + * @param {Outpoint} outpoint + */ + +UndoCoins.prototype.apply = function apply(view, outpoint) { + const undo = this.items.pop(); + const hash = outpoint.hash; + const index = outpoint.index; + let coins; + + assert(undo); + + if (undo.height !== -1) { + coins = new Coins(); + + assert(!view.map.has(hash)); + view.map.set(hash, coins); + + coins.hash = hash; + coins.coinbase = undo.coinbase; + coins.height = undo.height; + coins.version = undo.version; + } else { + coins = view.map.get(hash); + assert(coins); + } + + coins.addOutput(index, undo.toOutput()); + + assert(coins.has(index)); +}; + +/** + * UndoCoin + * @alias module:coins.UndoCoin + * @constructor + * @property {CoinEntry|null} entry + * @property {Output|null} output + * @property {Number} version + * @property {Number} height + * @property {Boolean} coinbase + */ + +function UndoCoin() { + this.entry = null; + this.output = null; + this.version = -1; + this.height = -1; + this.coinbase = false; +} + +/** + * Convert undo coin to an output. + * @returns {Output} + */ + +UndoCoin.prototype.toOutput = function toOutput() { + if (!this.output) { + assert(this.entry); + return this.entry.toOutput(); + } + return this.output; +}; + +/** + * Calculate undo coin size. + * @returns {Number} + */ + +UndoCoin.prototype.getSize = function getSize() { + let height = this.height; + let size = 0; + + if (height === -1) + height = 0; + + size += encoding.sizeVarint(height * 2 + (this.coinbase ? 1 : 0)); + + if (this.height !== -1) + size += encoding.sizeVarint(this.version); + + if (this.entry) { + // Cached from spend. + size += this.entry.getSize(); + } else { + size += compress.size(this.output); + } + + return size; +}; + +/** + * Write the undo coin to a buffer writer. + * @param {BufferWriter} bw + */ + +UndoCoin.prototype.toWriter = function toWriter(bw) { + let height = this.height; + + assert(height !== 0); + + if (height === -1) + height = 0; + + bw.writeVarint(height * 2 + (this.coinbase ? 1 : 0)); + + if (this.height !== -1) { + assert(this.version !== -1); + bw.writeVarint(this.version); + } + + if (this.entry) { + // Cached from spend. + this.entry.toWriter(bw); + } else { + compress.output(this.output, bw); + } + + return bw; +}; + +/** + * Serialize the undo coin. + * @returns {Buffer} + */ + +UndoCoin.prototype.toRaw = function toRaw() { + const size = this.getSize(); + return this.toWriter(new StaticWriter(size)).render(); +}; + +/** + * Inject properties from buffer reader. + * @private + * @param {BufferReader} br + * @returns {UndoCoin} + */ + +UndoCoin.prototype.fromReader = function fromReader(br) { + const code = br.readVarint(); + + this.output = new Output(); + + this.height = code / 2 | 0; + + if (this.height === 0) + this.height = -1; + + this.coinbase = (code & 1) !== 0; + + if (this.height !== -1) + this.version = br.readVarint(); + + decompress.output(this.output, br); + + return this; +}; + +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + * @returns {UndoCoin} + */ + +UndoCoin.prototype.fromRaw = function fromRaw(data) { + return this.fromReader(new BufferReader(data)); +}; + +/** + * Instantiate undo coin from serialized data. + * @param {Buffer} data + * @returns {UndoCoin} + */ + +UndoCoin.fromReader = function fromReader(br) { + return new UndoCoin().fromReader(br); +}; + +/** + * Instantiate undo coin from serialized data. + * @param {Buffer} data + * @returns {UndoCoin} + */ + +UndoCoin.fromRaw = function fromRaw(data) { + return new UndoCoin().fromRaw(data); +}; + +/* + * Expose + */ + +exports = UndoCoins; +exports.UndoCoins = UndoCoins; +exports.UndoCoin = UndoCoin; + +module.exports = exports; diff --git a/migrate/coinview-old.js b/migrate/coinview-old.js index 87624a540..4d3639217 100644 --- a/migrate/coinview-old.js +++ b/migrate/coinview-old.js @@ -4,6 +4,8 @@ * https://github.com/bcoin-org/bcoin */ +/* eslint-disable */ + 'use strict'; const assert = require('assert'); @@ -62,7 +64,7 @@ CoinView.prototype.addTX = function addTX(tx) { */ CoinView.prototype.get = function get(hash, index) { - let coins = this.coins[hash]; + const coins = this.coins[hash]; if (!coins) return; @@ -78,7 +80,7 @@ CoinView.prototype.get = function get(hash, index) { */ CoinView.prototype.has = function has(hash, index) { - let coins = this.coins[hash]; + const coins = this.coins[hash]; if (!coins) return false; @@ -94,7 +96,7 @@ CoinView.prototype.has = function has(hash, index) { */ CoinView.prototype.spend = function spend(hash, index) { - let coins = this.coins[hash]; + const coins = this.coins[hash]; if (!coins) return; @@ -128,8 +130,8 @@ CoinView.prototype.fillCoins = function fillCoins(tx) { */ CoinView.prototype.toArray = function toArray() { - let keys = Object.keys(this.coins); - let out = []; + const keys = Object.keys(this.coins); + const out = []; let i, hash; for (i = 0; i < keys.length; i++) { diff --git a/migrate/compress-old.js b/migrate/compress-old.js index d32023f4b..bceac2f1d 100644 --- a/migrate/compress-old.js +++ b/migrate/compress-old.js @@ -20,8 +20,6 @@ const secp256k1 = require('../lib/crypto/secp256k1'); */ function compressScript(script, bw) { - let data; - // Attempt to compress the output scripts. // We can _only_ ever compress them if // they are serialized as minimaldata, as @@ -31,7 +29,7 @@ function compressScript(script, bw) { // P2PKH -> 1 | key-hash // Saves 5 bytes. if (script.isPubkeyhash(true)) { - data = script.code[2].data; + const data = script.code[2].data; bw.writeU8(1); bw.writeBytes(data); return bw; @@ -40,7 +38,7 @@ function compressScript(script, bw) { // P2SH -> 2 | script-hash // Saves 3 bytes. if (script.isScripthash()) { - data = script.code[1].data; + const data = script.code[1].data; bw.writeU8(2); bw.writeBytes(data); return bw; @@ -50,7 +48,7 @@ function compressScript(script, bw) { // Only works if the key is valid. // Saves up to 34 bytes. if (script.isPubkey(true)) { - data = script.code[0].data; + let data = script.code[0].data; if (secp256k1.publicKeyVerify(data)) { data = compressKey(data); bw.writeU8(3); @@ -112,19 +110,17 @@ function decompressScript(script, br) { */ function compressValue(value) { - let exp, last; - if (value === 0) return 0; - exp = 0; + let exp = 0; while (value % 10 === 0 && exp < 9) { value /= 10; exp++; } if (exp < 9) { - last = value % 10; + const last = value % 10; value = (value - last) / 10; return 1 + 10 * (9 * value + last - 1) + exp; } @@ -139,18 +135,17 @@ function compressValue(value) { */ function decompressValue(value) { - let exp, n, last; - if (value === 0) return 0; value--; - exp = value % 10; + let exp = value % 10; value = (value - exp) / 10; + let n; if (exp < 9) { - last = value % 9; + const last = value % 9; value = (value - last) / 9; n = value * 10 + last + 1; } else { @@ -209,8 +204,7 @@ function compressKey(key) { */ function decompressKey(key) { - let format = key[0] >>> 2; - let out; + const format = key[0] >>> 2; assert(key.length === 33); @@ -223,7 +217,7 @@ function decompressKey(key) { // low bits so publicKeyConvert // actually understands it. key[0] &= 0x03; - out = secp256k1.publicKeyConvert(key, false); + const out = secp256k1.publicKeyConvert(key, false); // Reset the hi bits so as not to // mutate the original buffer. diff --git a/migrate/ensure-tip-index.js b/migrate/ensure-tip-index.js index 084637c87..200322dc1 100644 --- a/migrate/ensure-tip-index.js +++ b/migrate/ensure-tip-index.js @@ -9,13 +9,13 @@ const LDB = require('../lib/db/ldb'); const BN = require('../lib/crypto/bn'); const DUMMY = Buffer.from([0]); let file = process.argv[2]; -let db, batch; +let batch; assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -db = LDB({ +const db = LDB({ location: file, db: 'leveldb', compression: true, @@ -25,25 +25,23 @@ db = LDB({ }); async function checkVersion() { - let data, ver; - console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); if (!data) return; - ver = data.readUInt32LE(0, true); + const ver = data.readUInt32LE(0, true); if (ver !== 1) throw Error(`DB is version ${ver}.`); } function entryFromRaw(data) { - let p = new BufferReader(data, true); - let hash = digest.hash256(p.readBytes(80)); - let entry = {}; + const p = new BufferReader(data, true); + const hash = digest.hash256(p.readBytes(80)); + const entry = {}; p.seek(-80); @@ -51,7 +49,7 @@ function entryFromRaw(data) { entry.version = p.readU32(); // Technically signed entry.prevBlock = p.readHash('hex'); entry.merkleRoot = p.readHash('hex'); - entry.ts = p.readU32(); + entry.time = p.readU32(); entry.bits = p.readU32(); entry.nonce = p.readU32(); entry.height = p.readU32(); @@ -69,10 +67,10 @@ function getEntries() { } async function getTip(entry) { - let state = await db.get('R'); + const state = await db.get('R'); assert(state); - let tip = state.toString('hex', 0, 32); - let data = await db.get(pair('e', tip)); + const tip = state.toString('hex', 0, 32); + const data = await db.get(pair('e', tip)); assert(data); return entryFromRaw(data); } @@ -90,32 +88,31 @@ async function isMainChain(entry, tip) { // And this insane function is why we should // be indexing tips in the first place! async function indexTips() { - let entries = await getEntries(); - let tip = await getTip(); - let tips = []; - let orphans = []; - let prevs = {}; - let i, orphan, entry, main; - - for (i = 0; i < entries.length; i++) { - entry = entries[i]; - main = await isMainChain(entry, tip.hash); + const entries = await getEntries(); + const tip = await getTip(); + const tips = []; + const orphans = []; + const prevs = {}; + + for (let i = 0; i < entries.length; i++) { + const entry = entries[i]; + const main = await isMainChain(entry, tip.hash); if (!main) { orphans.push(entry); prevs[entry.prevBlock] = true; } } - for (i = 0; i < orphans.length; i++) { - orphan = orphans[i]; + for (let i = 0; i < orphans.length; i++) { + const orphan = orphans[i]; if (!prevs[orphan.hash]) tips.push(orphan.hash); } tips.push(tip.hash); - for (i = 0; i < tips.length; i++) { - tip = tips[i]; + for (let i = 0; i < tips.length; i++) { + const tip = tips[i]; console.log('Indexing chain tip: %s.', util.revHex(tip)); batch.put(pair('p', tip), DUMMY); } @@ -124,11 +121,11 @@ async function indexTips() { function write(data, str, off) { if (Buffer.isBuffer(str)) return str.copy(data, off); - data.write(str, off, 'hex'); + return data.write(str, off, 'hex'); } function pair(prefix, hash) { - let key = Buffer.allocUnsafe(33); + const key = Buffer.allocUnsafe(33); if (typeof prefix === 'string') prefix = prefix.charCodeAt(0); key[0] = prefix; diff --git a/migrate/walletdb2to3.js b/migrate/walletdb2to3.js index b7c22a63e..988685ac7 100644 --- a/migrate/walletdb2to3.js +++ b/migrate/walletdb2to3.js @@ -8,17 +8,18 @@ const Path = require('../lib/wallet/path'); const MasterKey = require('../lib/wallet/masterkey'); const Account = require('../lib/wallet/account'); const Wallet = require('../lib/wallet/wallet'); +const KeyRing = require('../lib/primitives/keyring'); const BufferReader = require('../lib/utils/reader'); const BufferWriter = require('../lib/utils/writer'); -let layout = walletdb.layout; +const layout = walletdb.layout; let file = process.argv[2]; -let db, batch; +let batch; assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -db = bcoin.ldb({ +const db = bcoin.ldb({ location: file, db: 'leveldb', compression: true, @@ -28,15 +29,14 @@ db = bcoin.ldb({ }); async function updateVersion() { - let bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; - let data, ver; + const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); assert(data, 'No version.'); - ver = data.readUInt32LE(0, true); + let ver = data.readUInt32LE(0, true); if (ver !== 2) throw Error(`DB is version ${ver}.`); @@ -52,10 +52,8 @@ async function updateVersion() { async function updatePathMap() { let total = 0; - let i, iter, item, oldPaths, oldPath; - let hash, path, keys, key, ring; - iter = db.iterator({ + const iter = db.iterator({ gte: layout.p(encoding.NULL_HASH), lte: layout.p(encoding.HIGH_HASH), values: true @@ -64,21 +62,21 @@ async function updatePathMap() { console.log('Migrating path map.'); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; total++; - hash = layout.pp(item.key); - oldPaths = parsePaths(item.value, hash); - keys = Object.keys(oldPaths); - - for (i = 0; i < keys.length; i++) { - keys[i] = +keys[i]; - key = keys[i]; - oldPath = oldPaths[key]; - path = new Path(oldPath); + const hash = layout.pp(item.key); + const oldPaths = parsePaths(item.value, hash); + const keys = Object.keys(oldPaths); + + for (let i = 0; i < keys.length; i++) { + keys[i] = Number(keys[i]); + const key = keys[i]; + const oldPath = oldPaths[key]; + const path = new Path(oldPath); if (path.data) { if (path.encrypted) { console.log( @@ -87,8 +85,8 @@ async function updatePathMap() { path.toAddress().toBase58()); continue; } - ring = keyFromRaw(path.data); - path.data = new bcoin.keyring(ring).toRaw(); + const ring = keyFromRaw(path.data); + path.data = new KeyRing(ring).toRaw(); } batch.put(layout.P(key, hash), path.toRaw()); } @@ -101,9 +99,8 @@ async function updatePathMap() { async function updateAccounts() { let total = 0; - let iter, item, account, buf; - iter = db.iterator({ + const iter = db.iterator({ gte: layout.a(0, 0), lte: layout.a(0xffffffff, 0xffffffff), values: true @@ -112,19 +109,19 @@ async function updateAccounts() { console.log('Migrating accounts.'); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; total++; - account = accountFromRaw(item.value, item.key); + let account = accountFromRaw(item.value, item.key); account = new Account({ network: account.network, options: {} }, account); batch.put(item.key, account.toRaw()); if (account._old) { batch.del(layout.i(account.wid, account._old)); - buf = Buffer.allocUnsafe(4); + const buf = Buffer.allocUnsafe(4); buf.writeUInt32LE(account.accountIndex, 0, true); batch.put(layout.i(account.wid, account.name), buf); } @@ -135,9 +132,8 @@ async function updateAccounts() { async function updateWallets() { let total = 0; - let iter, item, wallet, buf; - iter = db.iterator({ + const iter = db.iterator({ gte: layout.w(0), lte: layout.w(0xffffffff), values: true @@ -146,19 +142,19 @@ async function updateWallets() { console.log('Migrating wallets.'); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; total++; - wallet = walletFromRaw(item.value); + let wallet = walletFromRaw(item.value); wallet = new Wallet({ network: wallet.network }, wallet); batch.put(item.key, wallet.toRaw()); if (wallet._old) { batch.del(layout.l(wallet._old)); - buf = Buffer.allocUnsafe(4); + const buf = Buffer.allocUnsafe(4); buf.writeUInt32LE(wallet.wid, 0, true); batch.put(layout.l(wallet.id), buf); } @@ -169,9 +165,8 @@ async function updateWallets() { async function updateTXMap() { let total = 0; - let iter, item, wallets; - iter = db.iterator({ + const iter = db.iterator({ gte: layout.e(encoding.NULL_HASH), lte: layout.e(encoding.HIGH_HASH), values: true @@ -180,13 +175,13 @@ async function updateTXMap() { console.log('Migrating tx map.'); for (;;) { - item = await iter.next(); + const item = await iter.next(); if (!item) break; total++; - wallets = parseWallets(item.value); + const wallets = parseWallets(item.value); batch.put(item.key, serializeWallets(wallets.sort())); } @@ -194,8 +189,8 @@ async function updateTXMap() { } function pathFromRaw(data) { - let path = {}; - let p = new BufferReader(data); + const path = {}; + const p = new BufferReader(data); path.wid = p.readU32(); path.name = p.readVarString('utf8'); @@ -221,19 +216,18 @@ function pathFromRaw(data) { break; } - path.version = p.read8(); + path.version = p.readI8(); path.type = p.readU8(); return path; } function parsePaths(data, hash) { - let p = new BufferReader(data); - let out = {}; - let path; + const p = new BufferReader(data); + const out = {}; while (p.left()) { - path = pathFromRaw(p); + const path = pathFromRaw(p); out[path.wid] = path; if (hash) path.hash = hash; @@ -243,19 +237,18 @@ function parsePaths(data, hash) { } function parseWallets(data) { - let p = new BufferReader(data); - let wallets = []; + const p = new BufferReader(data); + const wallets = []; while (p.left()) wallets.push(p.readU32()); return wallets; } function serializeWallets(wallets) { - let p = new BufferWriter(); - let i, wid; + const p = new BufferWriter(); - for (i = 0; i < wallets.length; i++) { - wid = wallets[i]; + for (let i = 0; i < wallets.length; i++) { + const wid = wallets[i]; p.writeU32(wid); } @@ -270,9 +263,8 @@ function readAccountKey(key) { } function accountFromRaw(data, dbkey) { - let account = {}; - let p = new BufferReader(data); - let i, count, key, name; + const account = {}; + const p = new BufferReader(data); dbkey = readAccountKey(dbkey); account.wid = dbkey.wid; @@ -292,7 +284,7 @@ function accountFromRaw(data, dbkey) { account.watchOnly = false; account.nestedDepth = 0; - name = account.name.replace(/[^\-\._0-9A-Za-z]+/g, ''); + const name = account.name.replace(/[^\-\._0-9A-Za-z]+/g, ''); if (name !== account.name) { console.log('Account name changed: %s -> %s.', account.name, name); @@ -300,10 +292,10 @@ function accountFromRaw(data, dbkey) { account.name = name; } - count = p.readU8(); + const count = p.readU8(); - for (i = 0; i < count; i++) { - key = bcoin.hd.fromRaw(p.readBytes(82)); + for (let i = 0; i < count; i++) { + const key = bcoin.hd.fromRaw(p.readBytes(82)); account.keys.push(key); } @@ -311,9 +303,8 @@ function accountFromRaw(data, dbkey) { } function walletFromRaw(data) { - let wallet = {}; - let p = new BufferReader(data); - let id; + const wallet = {}; + const p = new BufferReader(data); wallet.network = bcoin.network.fromMagic(p.readU32()); wallet.wid = p.readU32(); @@ -325,7 +316,7 @@ function walletFromRaw(data) { wallet.master = MasterKey.fromRaw(p.readVarBytes()); wallet.watchOnly = false; - id = wallet.id.replace(/[^\-\._0-9A-Za-z]+/g, ''); + const id = wallet.id.replace(/[^\-\._0-9A-Za-z]+/g, ''); if (id !== wallet.id) { console.log('Wallet ID changed: %s -> %s.', wallet.id, id); @@ -337,14 +328,13 @@ function walletFromRaw(data) { } function keyFromRaw(data, network) { - let ring = {}; - let p = new BufferReader(data); - let key, script; + const ring = {}; + const p = new BufferReader(data); ring.network = bcoin.network.get(network); ring.witness = p.readU8() === 1; - key = p.readVarBytes(); + const key = p.readVarBytes(); if (key.length === 32) { ring.privateKey = key; @@ -353,7 +343,7 @@ function keyFromRaw(data, network) { ring.publicKey = key; } - script = p.readVarBytes(); + const script = p.readVarBytes(); if (script.length > 0) ring.script = bcoin.script.fromRaw(script); diff --git a/migrate/walletdb3to4.js b/migrate/walletdb3to4.js index 005db2c06..b00d84ada 100644 --- a/migrate/walletdb3to4.js +++ b/migrate/walletdb3to4.js @@ -7,15 +7,14 @@ const WalletDB = require('../lib/wallet/walletdb'); const BufferReader = require('../lib/utils/reader'); const TX = require('../lib/primitives/tx'); const Coin = require('../lib/primitives/coin'); -const util = require('../lib/utils/util'); let file = process.argv[2]; -let db, batch; +let batch; assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -db = bcoin.ldb({ +const db = bcoin.ldb({ location: file, db: 'leveldb', compression: true, @@ -25,15 +24,14 @@ db = bcoin.ldb({ }); async function updateVersion() { - let bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; - let data, ver; + const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); assert(data, 'No version.'); - ver = data.readUInt32LE(0, true); + let ver = data.readUInt32LE(0, true); if (ver !== 3) throw Error(`DB is version ${ver}.`); @@ -49,31 +47,30 @@ async function updateVersion() { async function updateTXDB() { let txs = {}; - let i, keys, key, hash, tx, walletdb; - keys = await db.keys({ + const keys = await db.keys({ gte: Buffer.from([0x00]), lte: Buffer.from([0xff]) }); - for (i = 0; i < keys.length; i++) { - key = keys[i]; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; if (key[0] === 0x74 && key[5] === 0x74) { - tx = await db.get(key); + let tx = await db.get(key); tx = fromExtended(tx); - hash = tx.hash('hex'); + const hash = tx.hash('hex'); txs[hash] = tx; } if (key[0] === 0x74) batch.del(key); } - txs = util.values(txs); + txs = getValues(txs); await batch.write(); await db.close(); - walletdb = new WalletDB({ + const walletdb = new WalletDB({ location: file, db: 'leveldb', resolution: true, @@ -83,8 +80,8 @@ async function updateTXDB() { await walletdb.open(); - for (i = 0; i < txs.length; i++) { - tx = txs[i]; + for (let i = 0; i < txs.length; i++) { + const tx = txs[i]; await walletdb.addTX(tx); } @@ -92,17 +89,16 @@ async function updateTXDB() { } function fromExtended(data, saveCoins) { - let tx = new TX(); - let p = BufferReader(data); - let i, coinCount, coin; + const tx = new TX(); + const p = BufferReader(data); tx.fromRaw(p); tx.height = p.readU32(); tx.block = p.readHash('hex'); tx.index = p.readU32(); - tx.ts = p.readU32(); - tx.ps = p.readU32(); + tx.time = p.readU32(); + tx.mtime = p.readU32(); if (tx.block === encoding.NULL_HASH) tx.block = null; @@ -114,9 +110,9 @@ function fromExtended(data, saveCoins) { tx.index = -1; if (saveCoins) { - coinCount = p.readVarint(); - for (i = 0; i < coinCount; i++) { - coin = p.readVarBytes(); + const coinCount = p.readVarint(); + for (let i = 0; i < coinCount; i++) { + let coin = p.readVarBytes(); if (coin.length === 0) continue; coin = Coin.fromRaw(coin); @@ -129,6 +125,15 @@ function fromExtended(data, saveCoins) { return tx; } +function getValues(map) { + const items = []; + + for (const key of Object.keys(map)) + items.push(map[key]); + + return items; +} + (async () => { await db.open(); batch = db.batch(); diff --git a/migrate/walletdb4to5.js b/migrate/walletdb4to5.js index 760ba34e7..9a767607b 100644 --- a/migrate/walletdb4to5.js +++ b/migrate/walletdb4to5.js @@ -3,13 +3,13 @@ const assert = require('assert'); const bcoin = require('../'); let file = process.argv[2]; -let db, batch; +let batch; assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -db = bcoin.ldb({ +const db = bcoin.ldb({ location: file, db: 'leveldb', compression: true, @@ -19,15 +19,14 @@ db = bcoin.ldb({ }); async function updateVersion() { - let bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; - let data, ver; + const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); assert(data, 'No version.'); - ver = data.readUInt32LE(0, true); + let ver = data.readUInt32LE(0, true); if (ver !== 4) throw Error(`DB is version ${ver}.`); @@ -42,15 +41,13 @@ async function updateVersion() { } async function updateTXDB() { - let i, keys, key; - - keys = await db.keys({ + const keys = await db.keys({ gte: Buffer.from([0x00]), lte: Buffer.from([0xff]) }); - for (i = 0; i < keys.length; i++) { - key = keys[i]; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; switch (key[0]) { case 0x62: // b case 0x63: // c diff --git a/migrate/walletdb5to6.js b/migrate/walletdb5to6.js index 371897ba9..353cf4a11 100644 --- a/migrate/walletdb5to6.js +++ b/migrate/walletdb5to6.js @@ -6,13 +6,13 @@ const encoding = require('../lib/utils/encoding'); const BufferWriter = require('../lib/utils/writer'); const BufferReader = require('../lib/utils/reader'); let file = process.argv[2]; -let db, batch; +let batch; assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -db = bcoin.ldb({ +const db = bcoin.ldb({ location: file, db: 'leveldb', compression: true, @@ -22,15 +22,14 @@ db = bcoin.ldb({ }); async function updateVersion() { - let bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; - let data, ver; + const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`; console.log('Checking version.'); - data = await db.get('V'); + const data = await db.get('V'); assert(data, 'No version.'); - ver = data.readUInt32LE(0, true); + let ver = data.readUInt32LE(0, true); if (ver !== 5) throw Error(`DB is version ${ver}.`); @@ -46,15 +45,14 @@ async function updateVersion() { async function wipeTXDB() { let total = 0; - let i, keys, key; - keys = await db.keys({ + const keys = await db.keys({ gte: Buffer.from([0x00]), lte: Buffer.from([0xff]) }); - for (i = 0; i < keys.length; i++) { - key = keys[i]; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; switch (key[0]) { case 0x62: // b case 0x63: // c @@ -74,18 +72,16 @@ async function wipeTXDB() { } async function patchAccounts() { - let i, items, item, wid, index, account; - - items = await db.range({ + const items = await db.range({ gte: Buffer.from('610000000000000000', 'hex'), // a lte: Buffer.from('61ffffffffffffffff', 'hex') // a }); - for (i = 0; i < items.length; i++) { - item = items[i]; - wid = item.key.readUInt32BE(1, true); - index = item.key.readUInt32BE(5, true); - account = accountFromRaw(item.value); + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const wid = item.key.readUInt32BE(1, true); + const index = item.key.readUInt32BE(5, true); + const account = accountFromRaw(item.value); console.log('a[%d][%d] -> lookahead=%d', wid, index, account.lookahead); batch.put(item.key, accountToRaw(account)); console.log('n[%d][%d] -> %s', wid, index, account.name); @@ -94,43 +90,39 @@ async function patchAccounts() { } async function indexPaths() { - let i, items, item, wid, index, hash; - - items = await db.range({ + const items = await db.range({ gte: Buffer.from('5000000000' + encoding.NULL_HASH, 'hex'), // P lte: Buffer.from('50ffffffff' + encoding.HIGH_HASH, 'hex') // P }); - for (i = 0; i < items.length; i++) { - item = items[i]; - wid = item.key.readUInt32BE(1, true); - hash = item.key.toString('hex', 5); - index = item.value.readUInt32LE(0, true); + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const wid = item.key.readUInt32BE(1, true); + const hash = item.key.toString('hex', 5); + const index = item.value.readUInt32LE(0, true); console.log('r[%d][%d][%s] -> NUL', wid, index, hash); batch.put(r(wid, index, hash), Buffer.from([0])); } } async function patchPathMaps() { - let i, items, item, hash, wids; - - items = await db.range({ + const items = await db.range({ gte: Buffer.from('70' + encoding.NULL_HASH, 'hex'), // p lte: Buffer.from('70' + encoding.HIGH_HASH, 'hex') // p }); - for (i = 0; i < items.length; i++) { - item = items[i]; - hash = item.key.toString('hex', 1); - wids = parseWallets(item.value); + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const hash = item.key.toString('hex', 1); + const wids = parseWallets(item.value); console.log('p[%s] -> u32(%d)', hash, wids.length); batch.put(item.key, serializeWallets(wids)); } } function parseWallets(data) { - let p = new BufferReader(data); - let wids = []; + const p = new BufferReader(data); + const wids = []; while (p.left()) wids.push(p.readU32()); @@ -139,13 +131,12 @@ function parseWallets(data) { } function serializeWallets(wids) { - let p = new BufferWriter(); - let i, wid; + const p = new BufferWriter(); p.writeU32(wids.length); - for (i = 0; i < wids.length; i++) { - wid = wids[i]; + for (let i = 0; i < wids.length; i++) { + const wid = wids[i]; p.writeU32(wid); } @@ -153,8 +144,7 @@ function serializeWallets(wids) { } function accountToRaw(account) { - let p = new BufferWriter(); - let i, key; + const p = new BufferWriter(); p.writeVarString(account.name, 'ascii'); p.writeU8(account.initialized ? 1 : 0); @@ -170,8 +160,8 @@ function accountToRaw(account) { p.writeBytes(account.accountKey); p.writeU8(account.keys.length); - for (i = 0; i < account.keys.length; i++) { - key = account.keys[i]; + for (let i = 0; i < account.keys.length; i++) { + const key = account.keys[i]; p.writeBytes(key); } @@ -179,9 +169,8 @@ function accountToRaw(account) { }; function accountFromRaw(data) { - let account = {}; - let p = new BufferReader(data); - let i, count, key; + const account = {}; + const p = new BufferReader(data); account.name = p.readVarString('ascii'); account.initialized = p.readU8() === 1; @@ -197,10 +186,10 @@ function accountFromRaw(data) { account.accountKey = p.readBytes(82); account.keys = []; - count = p.readU8(); + const count = p.readU8(); - for (i = 0; i < count; i++) { - key = p.readBytes(82); + for (let i = 0; i < count; i++) { + const key = p.readBytes(82); account.keys.push(key); } @@ -208,7 +197,7 @@ function accountFromRaw(data) { } function n(wid, index) { - let key = Buffer.allocUnsafe(9); + const key = Buffer.allocUnsafe(9); key[0] = 0x6e; key.writeUInt32BE(wid, 1, true); key.writeUInt32BE(index, 5, true); @@ -216,7 +205,7 @@ function n(wid, index) { } function r(wid, index, hash) { - let key = Buffer.allocUnsafe(1 + 4 + 4 + (hash.length / 2)); + const key = Buffer.allocUnsafe(1 + 4 + 4 + (hash.length / 2)); key[0] = 0x72; key.writeUInt32BE(wid, 1, true); key.writeUInt32BE(index, 5, true); @@ -225,10 +214,9 @@ function r(wid, index, hash) { } async function updateLookahead() { - let WalletDB = require('../lib/wallet/walletdb'); - let i, j, db, wallet; + const WalletDB = require('../lib/wallet/walletdb'); - db = new WalletDB({ + const db = new WalletDB({ network: process.argv[3], db: 'leveldb', location: file, @@ -241,11 +229,11 @@ async function updateLookahead() { await db.open(); - for (i = 1; i < db.depth; i++) { - wallet = await db.get(i); + for (let i = 1; i < db.depth; i++) { + const wallet = await db.get(i); assert(wallet); console.log('Updating wallet lookahead: %s', wallet.id); - for (j = 0; j < wallet.accountDepth; j++) + for (let j = 0; j < wallet.accountDepth; j++) await wallet.setLookahead(j, 20); } diff --git a/package.json b/package.json index f134187fe..5b588d835 100644 --- a/package.json +++ b/package.json @@ -23,49 +23,52 @@ "node": ">=7.6.0" }, "dependencies": { - "bn.js": "4.11.7", + "bn.js": "4.11.8", "elliptic": "6.4.0", - "n64": "0.0.12" + "n64": "0.0.18" }, "optionalDependencies": { "bcoin-native": "0.0.23", "leveldown": "1.7.2", - "secp256k1": "3.2.5", - "socket.io": "2.0.1", - "socket.io-client": "2.0.1" + "secp256k1": "3.3.0", + "socket.io": "2.0.3", + "socket.io-client": "2.0.3" }, "devDependencies": { "babel-core": "^6.25.0", - "babel-loader": "^7.1.0", + "babel-loader": "^7.1.1", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-es2015": "^6.24.1", "babel-preset-es2016": "^6.24.1", "babel-preset-es2017": "^6.24.1", - "eslint": "^4.1.0", - "hash.js": "^1.0.3", - "jsdoc": "^3.4.3", + "babel-preset-env": "^1.6.0", + "eslint": "^4.4.1", + "hash.js": "^1.1.3", + "jsdoc": "^3.5.4", "level-js": "^2.2.4", - "mocha": "^3.4.1", + "mocha": "^3.5.0", "node-loader": "^0.6.0", - "uglifyjs-webpack-plugin": "^1.0.0-beta.1", - "webpack": "^3.0.0" + "uglifyjs-webpack-plugin": "^1.0.0-beta.2", + "webpack": "^3.5.4" }, "main": "./lib/bcoin.js", "bin": { - "bcoin-node": "./bin/node", - "bcoin-spvnode": "./bin/spvnode", + "bcoin": "./bin/bcoin", "bcoin-cli": "./bin/cli", - "bcoin": "./bin/bcoin" + "bcoin-node": "./bin/node", + "bcoin-spvnode": "./bin/spvnode" }, "scripts": { "clean": "rm -f {browser/,}{bcoin.js,bcoin-worker.js}", "docs": "jsdoc -c jsdoc.json", - "lint": "eslint lib/ test/ migrate/ examples/ bench/ scripts/*.js bin/cli bin/node bin/spvnode || exit 0", + "lint": "eslint $(cat .eslintfiles) || exit 0", "lint-file": "eslint", - "test": "mocha --reporter spec test/*-test.js", - "test-browser": "BCOIN_NO_NATIVE=1 BCOIN_NO_SECP256K1=1 mocha --reporter spec test/*-test.js", + "test": "mocha --reporter spec test/*.js", + "test-browser": + "BCOIN_NO_NATIVE=1 BCOIN_NO_SECP256K1=1 mocha --reporter spec test/*.js", "test-file": "mocha --reporter spec", - "test-file-browser": "BCOIN_NO_NATIVE=1 BCOIN_NO_SECP256K1=1 mocha --reporter spec", + "test-file-browser": + "BCOIN_NO_NATIVE=1 BCOIN_NO_SECP256K1=1 mocha --reporter spec", "webpack": "webpack --config webpack.browser.js", "webpack-browser": "webpack --config webpack.browser.js", "webpack-compat": "webpack --config webpack.compat.js", diff --git a/scripts/dump.js b/scripts/dump.js index 1af07baf8..3fecf52c0 100644 --- a/scripts/dump.js +++ b/scripts/dump.js @@ -1,45 +1,22 @@ 'use strict'; -const fs = require('fs'); const heapdump = require('heapdump'); const MempoolEntry = require('../lib/mempool/mempoolentry'); const Coins = require('../lib/coins/coins'); -const TX = require('../lib/primitives/tx'); -const CoinView = require('../lib/coins/coinview'); +const common = require('../test/util/common'); -let SNAPSHOT = `${__dirname}/../dump.heapsnapshot`; -let tx = parseTX('../test/data/tx4.hex'); -let raw, coins, entry; - -function parseTX(file) { - let data = fs.readFileSync(`${__dirname}/${file}`, 'utf8'); - let parts = data.trim().split(/\n+/); - let raw = parts[0]; - let tx = TX.fromRaw(raw.trim(), 'hex'); - let view = new CoinView(); - let i, prev; - - for (i = 1; i < parts.length; i++) { - raw = parts[i]; - prev = TX.fromRaw(raw.trim(), 'hex'); - view.addTX(prev, -1); - } - - return { tx: tx, view: view }; -} - -raw = Coins.fromTX(tx.tx, 0).toRaw(); -coins = Coins.fromRaw(raw, tx.tx.hash('hex')); -entry = MempoolEntry.fromTX(tx.tx, tx.view, 1000000); +const [tx, view] = common.readTX('tx4').getTX(); +const coins = Coins.fromTX(tx, 0); +const entry = MempoolEntry.fromTX(tx, view, 1000000); setInterval(() => { console.log(tx.hash('hex')); - console.log(coins.hash); + console.log(coins.outputs.length); console.log(entry.tx); }, 60 * 1000); setImmediate(() => { - heapdump.writeSnapshot(SNAPSHOT, (err) => { + heapdump.writeSnapshot(`${__dirname}/../dump.heapsnapshot`, (err) => { if (err) throw err; }); diff --git a/scripts/fuzz.js b/scripts/fuzz.js index 88fc35086..87835e2cb 100644 --- a/scripts/fuzz.js +++ b/scripts/fuzz.js @@ -1,6 +1,5 @@ 'use strict'; -const assert = require('assert'); const util = require('../lib/utils/util'); const Script = require('../lib/script/script'); const Stack = require('../lib/script/stack'); @@ -10,17 +9,72 @@ const Output = require('../lib/primitives/output'); const Outpoint = require('../lib/primitives/outpoint'); const TX = require('../lib/primitives/tx'); const random = require('../lib/crypto/random'); +const secp256k1 = require('../lib/crypto/secp256k1'); +const flags = Script.flags; -const MANDATORY = Script.flags.MANDATORY_VERIFY_FLAGS | Script.flags.VERIFY_WITNESS; -const STANDARD = Script.flags.STANDARD_VERIFY_FLAGS; +let consensus = null; + +try { + consensus = require('nodeconsensus'); +} catch (e) { + ; +} + +if (consensus) + util.log('Running against bitcoinconsensus...'); + +const MANDATORY = flags.MANDATORY_VERIFY_FLAGS | flags.VERIFY_WITNESS; +const STANDARD = flags.STANDARD_VERIFY_FLAGS; + +function verifyConsensus(tx, index, output, value, flags) { + if (!consensus) + return 'OK'; + return consensus.verify(tx.toRaw(), index, output.toRaw(), value, flags); +} + +function assertConsensus(tx, output, flags, code) { + if (!consensus) + return; + + const err = verifyConsensus(tx, 0, output, 0, flags); + + if (err !== code) { + util.log('bitcoinconsensus mismatch!'); + util.log(`${err} (bitcoin core) !== ${code} (bcoin)`); + util.log(tx); + util.log(output); + util.log(flags); + util.log('TX: %s', tx.toRaw().toString('hex')); + util.log('Output Script: %s', output.toRaw().toString('hex')); + } +} + +function randomSignature() { + const r = secp256k1.generatePrivateKey(); + const s = secp256k1.generatePrivateKey(); + return secp256k1.toDER(Buffer.concat([r, s])); +} + +function randomKey() { + const x = secp256k1.generatePrivateKey(); + const y = secp256k1.generatePrivateKey(); + + if (util.random(0, 2) === 0) { + const p = Buffer.from([2 | (y[y.length - 1] & 1)]); + return Buffer.concat([p, x]); + } + + const p = Buffer.from([4]); + return Buffer.concat([p, x, y]); +} function randomOutpoint() { - let hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32).toString('hex'); return new Outpoint(hash, util.random(0, 0xffffffff)); } function randomInput() { - let input = Input.fromOutpoint(randomOutpoint()); + const input = Input.fromOutpoint(randomOutpoint()); if (util.random(0, 5) === 0) input.sequence = util.random(0, 0xffffffff); @@ -33,18 +87,17 @@ function randomOutput() { } function randomTX() { - let tx = new TX(); - let inputs = util.random(1, 5); - let outputs = util.random(0, 5); - let i; + const tx = new TX(); + const inputs = util.random(1, 5); + const outputs = util.random(0, 5); tx.version = util.random(0, 0xffffffff); - for (i = 0; i < inputs; i++) + for (let i = 0; i < inputs; i++) tx.inputs.push(randomInput()); - for (i = 0; i < outputs; i++) - tx.inputs.push(randomOutput()); + for (let i = 0; i < outputs; i++) + tx.outputs.push(randomOutput()); if (util.random(0, 5) === 0) tx.locktime = util.random(0, 0xffffffff); @@ -55,12 +108,11 @@ function randomTX() { } function randomWitness(redeem) { - let size = util.random(1, 100); - let witness = new Witness(); - let i, len; + const size = util.random(1, 100); + const witness = new Witness(); - for (i = 0; i < size; i++) { - len = util.random(0, 100); + for (let i = 0; i < size; i++) { + const len = util.random(0, 100); witness.push(random.randomBytes(len)); } @@ -73,37 +125,30 @@ function randomWitness(redeem) { } function randomInputScript(redeem) { - let size = util.random(1, 100); - let script = new Script(); - let i, len; + const size = util.random(1, 100); + const script = new Script(); - for (i = 0; i < size; i++) { - len = util.random(0, 100); - script.push(random.randomBytes(len)); + for (let i = 0; i < size; i++) { + const len = util.random(0, 100); + script.pushData(random.randomBytes(len)); } if (redeem) - script.push(redeem); - - script.compile(); + script.pushData(redeem); - return script; + return script.compile(); } function randomOutputScript() { - let size = util.random(1, 10000); + const size = util.random(1, 10000); return Script.fromRaw(random.randomBytes(size)); } function isPushOnly(script) { - let i, op; - if (script.isPushOnly()) return true; - for (i = 0; i < script.code.length; i++) { - op = script.code[i]; - + for (const op of script.code) { if (op.value === Script.opcodes.NOP) continue; @@ -120,7 +165,7 @@ function isPushOnly(script) { } function randomPubkey() { - let len = util.random(0, 2) === 0 ? 33 : 65; + const len = util.random(0, 2) === 0 ? 33 : 65; return Script.fromPubkey(random.randomBytes(len)); } @@ -129,13 +174,12 @@ function randomPubkeyhash() { } function randomMultisig() { - let n = util.random(1, 16); - let m = util.random(1, n); - let keys = []; - let i, len; + const n = util.random(1, 16); + const m = util.random(1, n); + const keys = []; - for (i = 0; i < n; i++) { - len = util.random(0, 2) === 0 ? 33 : 65; + for (let i = 0; i < n; i++) { + const len = util.random(0, 2) === 0 ? 33 : 65; keys.push(random.randomBytes(len)); } @@ -155,8 +199,8 @@ function randomWitnessScripthash() { } function randomProgram() { - let version = util.random(0, 16); - let size = util.random(2, 41); + const version = util.random(0, 16); + const size = util.random(2, 41); return Script.fromProgram(version, random.randomBytes(size)); } @@ -173,7 +217,7 @@ function randomRedeem() { case 4: return randomProgram(); } - assert(false); + throw new Error(); } function randomScript() { @@ -193,7 +237,7 @@ function randomScript() { case 6: return randomProgram(); } - assert(false); + throw new Error(); } function randomPubkeyContext() { @@ -215,7 +259,7 @@ function randomPubkeyhashContext() { } function randomScripthashContext() { - let redeem = randomRedeem(); + const redeem = randomRedeem(); return { input: randomInputScript(redeem.toRaw()), witness: new Witness(), @@ -234,7 +278,7 @@ function randomWitnessPubkeyhashContext() { } function randomWitnessScripthashContext() { - let redeem = randomRedeem(); + const redeem = randomRedeem(); return { input: new Script(), witness: randomWitness(redeem.toRaw()), @@ -244,10 +288,10 @@ function randomWitnessScripthashContext() { } function randomWitnessNestedContext() { - let redeem = randomRedeem(); - let program = Script.fromProgram(0, redeem.sha256()); + const redeem = randomRedeem(); + const program = Script.fromProgram(0, redeem.sha256()); return { - input: new Script([program.toRaw()]), + input: Script.fromItems([program.toRaw()]), witness: randomWitness(redeem.toRaw()), output: Script.fromScripthash(program.hash160()), redeem: redeem @@ -269,13 +313,12 @@ function randomContext() { case 5: return randomWitnessNestedContext(); } - assert(false); + throw new Error(); } function fuzzSimple(flags) { let tx = randomTX(); let total = -1; - let stack, input, output; for (;;) { if (++total % 1000 === 0) @@ -284,8 +327,8 @@ function fuzzSimple(flags) { if (total % 500 === 0) tx = randomTX(); - stack = new Stack(); - input = randomInputScript(); + const stack = new Stack(); + const input = randomInputScript(); try { input.execute(stack, flags, tx, 0, 0, 0); @@ -295,7 +338,7 @@ function fuzzSimple(flags) { throw e; } - output = randomOutputScript(); + const output = randomOutputScript(); try { output.execute(stack, flags, tx, 0, 0, 0); @@ -308,7 +351,7 @@ function fuzzSimple(flags) { if (stack.length === 0) continue; - if (!Script.bool(stack.top(-1))) + if (!stack.getBool(-1)) continue; if (isPushOnly(output)) @@ -332,7 +375,6 @@ function fuzzSimple(flags) { function fuzzVerify(flags) { let tx = randomTX(); let total = -1; - let input, output, witness; for (;;) { if (++total % 1000 === 0) @@ -341,9 +383,14 @@ function fuzzVerify(flags) { if (total % 500 === 0) tx = randomTX(); - input = randomInputScript(); - witness = randomWitness(); - output = randomOutputScript(); + const input = randomInputScript(); + const witness = randomWitness(); + const output = randomOutputScript(); + + tx.inputs[0].script = input; + tx.inputs[0].witness = witness; + + tx.refresh(); try { Script.verify( @@ -356,11 +403,15 @@ function fuzzVerify(flags) { flags ); } catch (e) { - if (e.type === 'ScriptError') + if (e.type === 'ScriptError') { + assertConsensus(tx, output, flags, e.code); continue; + } throw e; } + assertConsensus(tx, output, flags, 'OK'); + if (isPushOnly(output)) continue; @@ -382,7 +433,6 @@ function fuzzVerify(flags) { function fuzzLess(flags) { let tx = randomTX(); let total = -1; - let ctx; for (;;) { if (++total % 1000 === 0) @@ -391,7 +441,13 @@ function fuzzLess(flags) { if (total % 500 === 0) tx = randomTX(); - ctx = randomContext(); + const ctx = randomContext(); + const input = tx.inputs[0]; + + input.script = ctx.input; + input.witness = ctx.witness; + + tx.refresh(); try { Script.verify( @@ -404,11 +460,15 @@ function fuzzLess(flags) { flags ); } catch (e) { - if (e.type === 'ScriptError') + if (e.type === 'ScriptError') { + assertConsensus(tx, ctx.output, flags, e.code); continue; + } throw e; } + assertConsensus(tx, ctx.output, flags, 'OK'); + util.log('Produced valid scripts:'); util.log('Input:'); @@ -430,15 +490,20 @@ function fuzzLess(flags) { } function main() { - let flags = process.argv.indexOf('--standard') !== -1 ? STANDARD : MANDATORY; + const flags = process.argv.indexOf('--standard') !== -1 + ? STANDARD + : MANDATORY; switch (process.argv[2]) { case 'simple': - return fuzzSimple(flags); + fuzzSimple(flags); + break; case 'verify': - return fuzzVerify(flags); + fuzzVerify(flags); + break; case 'less': - return fuzzLess(flags); + fuzzLess(flags); + break; default: util.log('Please select a mode:'); util.log('simple, verify, less'); @@ -447,4 +512,7 @@ function main() { } } +randomKey; +randomSignature; + main(); diff --git a/scripts/gen.js b/scripts/gen.js index e4782e99b..e3fe3d3d4 100644 --- a/scripts/gen.js +++ b/scripts/gen.js @@ -1,22 +1,16 @@ 'use strict'; -const BN = require('../lib/crypto/bn'); const util = require('../lib/utils/util'); const consensus = require('../lib/protocol/consensus'); const encoding = require('../lib/utils/encoding'); const TX = require('../lib/primitives/tx'); const Block = require('../lib/primitives/block'); const Script = require('../lib/script/script'); -const Opcode = require('../lib/script/opcode'); -const opcodes = Script.opcodes; - -let main, testnet, regtest, segnet3, segnet4, btcd; function createGenesisBlock(options) { let flags = options.flags; - let script = options.script; + let key = options.key; let reward = options.reward; - let tx, block; if (!flags) { flags = Buffer.from( @@ -24,93 +18,90 @@ function createGenesisBlock(options) { 'ascii'); } - if (!script) { - script = Script.fromArray([ - Buffer.from('04678afdb0fe5548271967f1a67130b7105cd6a828e039' - + '09a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c3' - + '84df7ba0b8d578a4c702b6bf11d5f', 'hex'), - opcodes.OP_CHECKSIG - ]); + if (!key) { + key = Buffer.from('' + + '04678afdb0fe5548271967f1a67130b7105cd6a828e039' + + '09a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c3' + + '84df7ba0b8d578a4c702b6bf11d5f', 'hex'); } if (!reward) reward = 50 * consensus.COIN; - tx = new TX({ + const tx = new TX({ version: 1, - flag: 1, inputs: [{ prevout: { hash: encoding.NULL_HASH, index: 0xffffffff }, - script: [ - Opcode.fromNumber(new BN(486604799)), - Opcode.fromPush(Buffer.from([4])), - Opcode.fromData(flags) - ], + script: Script() + .pushInt(486604799) + .pushPush(Buffer.from([4])) + .pushData(flags) + .compile(), sequence: 0xffffffff }], outputs: [{ value: reward, - script: script + script: Script.fromPubkey(key) }], locktime: 0 }); - block = new Block({ + const block = new Block({ version: options.version, prevBlock: encoding.NULL_HASH, merkleRoot: tx.hash('hex'), - ts: options.ts, + time: options.time, bits: options.bits, nonce: options.nonce, height: 0 }); - block.addTX(tx); + block.txs.push(tx); return block; } -main = createGenesisBlock({ +const main = createGenesisBlock({ version: 1, - ts: 1231006505, + time: 1231006505, bits: 486604799, nonce: 2083236893 }); -testnet = createGenesisBlock({ +const testnet = createGenesisBlock({ version: 1, - ts: 1296688602, + time: 1296688602, bits: 486604799, nonce: 414098458 }); -regtest = createGenesisBlock({ +const regtest = createGenesisBlock({ version: 1, - ts: 1296688602, + time: 1296688602, bits: 545259519, nonce: 2 }); -segnet3 = createGenesisBlock({ +const segnet3 = createGenesisBlock({ version: 1, - ts: 1452831101, + time: 1452831101, bits: 486604799, nonce: 0 }); -segnet4 = createGenesisBlock({ +const segnet4 = createGenesisBlock({ version: 1, - ts: 1452831101, + time: 1452831101, bits: 503447551, nonce: 0 }); -btcd = createGenesisBlock({ +const btcd = createGenesisBlock({ version: 1, - ts: 1401292357, + time: 1401292357, bits: 545259519, nonce: 2 }); diff --git a/test/aes-test.js b/test/aes-test.js index 5817d9c80..32c547efa 100644 --- a/test/aes-test.js +++ b/test/aes-test.js @@ -1,158 +1,49 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); -const digest = require('../lib/crypto/digest'); +const assert = require('./util/assert'); const aes = require('../lib/crypto/aes'); -const pbkdf2 = require('../lib/crypto/pbkdf2'); -const nativeCrypto = require('crypto'); - -describe('AES', function() { - function pbkdf2key(passphrase, iterations, dkLen, ivLen, alg) { - let key = pbkdf2.derive(passphrase, '', iterations, dkLen + ivLen, 'sha512'); - return { - key: key.slice(0, dkLen), - iv: key.slice(dkLen, dkLen + ivLen) - }; - } - - function nencrypt(data, passphrase) { - let key, cipher; - - assert(nativeCrypto, 'No crypto module available.'); - assert(passphrase, 'No passphrase.'); - - if (typeof data === 'string') - data = Buffer.from(data, 'utf8'); - - if (typeof passphrase === 'string') - passphrase = Buffer.from(passphrase, 'utf8'); - - key = pbkdf2key(passphrase, 2048, 32, 16); - cipher = nativeCrypto.createCipheriv('aes-256-cbc', key.key, key.iv); - - return Buffer.concat([ - cipher.update(data), - cipher.final() - ]); - } - - function ndecrypt(data, passphrase) { - let key, decipher; - - assert(nativeCrypto, 'No crypto module available.'); - assert(passphrase, 'No passphrase.'); - - if (typeof data === 'string') - data = Buffer.from(data, 'hex'); - - if (typeof passphrase === 'string') - passphrase = Buffer.from(passphrase, 'utf8'); - - key = pbkdf2key(passphrase, 2048, 32, 16); - decipher = nativeCrypto.createDecipheriv('aes-256-cbc', key.key, key.iv); - - return Buffer.concat([ - decipher.update(data), - decipher.final() - ]); - } - - function bencrypt(data, passphrase) { - let key; - - assert(nativeCrypto, 'No crypto module available.'); - assert(passphrase, 'No passphrase.'); - - if (typeof data === 'string') - data = Buffer.from(data, 'utf8'); - - if (typeof passphrase === 'string') - passphrase = Buffer.from(passphrase, 'utf8'); - key = pbkdf2key(passphrase, 2048, 32, 16); - return aes.encipher(data, key.key, key.iv); - } +const key = Buffer.from( + '3a0c0bf669694ac7685e6806eeadee8e56c9b9bd22c3caa81c718ed4bbf809a1', + 'hex'); - function bdecrypt(data, passphrase) { - let key; +const iv = Buffer.from('6dd26d9045b73c377a9ed2ffeca72ffd', 'hex'); - assert(nativeCrypto, 'No crypto module available.'); - assert(passphrase, 'No passphrase.'); - - if (typeof data === 'string') - data = Buffer.from(data, 'hex'); - - if (typeof passphrase === 'string') - passphrase = Buffer.from(passphrase, 'utf8'); - - key = pbkdf2key(passphrase, 2048, 32, 16); - return aes.decipher(data, key.key, key.iv); - } - - function encrypt(data, passphrase) { - let key; - - assert(nativeCrypto, 'No crypto module available.'); - assert(passphrase, 'No passphrase.'); - - if (typeof data === 'string') - data = Buffer.from(data, 'utf8'); - - if (typeof passphrase === 'string') - passphrase = Buffer.from(passphrase, 'utf8'); - - key = pbkdf2key(passphrase, 2048, 32, 16); - - return aes.encipher(data, key.key, key.iv); - } - - function decrypt(data, passphrase) { - let key; - - assert(nativeCrypto, 'No crypto module available.'); - assert(passphrase, 'No passphrase.'); - - if (typeof data === 'string') - data = Buffer.from(data, 'hex'); - - if (typeof passphrase === 'string') - passphrase = Buffer.from(passphrase, 'utf8'); - - key = pbkdf2key(passphrase, 2048, 32, 16); - - return aes.decipher(data, key.key, key.iv); - } - - it('should encrypt and decrypt a hash with 2 blocks', () => { - let hash = digest.sha256(Buffer.alloc(0)); - let enchash = encrypt(hash, 'foo'); - let dechash = decrypt(enchash, 'foo'); +describe('AES', function() { + it('should encrypt and decrypt with 2 blocks', () => { + const data = Buffer.from( + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', + 'hex'); - let hash2 = digest.sha256(Buffer.alloc(0)); - let enchash2 = nencrypt(hash2, 'foo'); - let dechash2 = ndecrypt(enchash2, 'foo'); + const expected = Buffer.from('' + + '83de502a9c83112ca6383f2214a892a0cdad5ab2b3e192e' + + '9921ddb126b25262c41f1dcff4d67ccfb40e4116e5a4569c1', + 'hex'); - let hash3 = digest.sha256(Buffer.alloc(0)); - let enchash3 = bencrypt(hash3, 'foo'); - let dechash3 = bdecrypt(enchash3, 'foo'); + const ciphertext = aes.encipher(data, key, iv); + assert.bufferEqual(ciphertext, expected); - assert.deepEqual(hash, hash2); - assert.deepEqual(enchash, enchash2); - assert.deepEqual(dechash, dechash2); - assert.deepEqual(dechash, dechash3); + const plaintext = aes.decipher(ciphertext, key, iv); + assert.bufferEqual(plaintext, data); }); - it('should encrypt and decrypt a hash with uneven blocks', () => { - let hash = Buffer.concat([digest.sha256(Buffer.alloc(0)), Buffer.from([1,2,3])]); - let enchash = encrypt(hash, 'foo'); - let dechash = decrypt(enchash, 'foo'); + it('should encrypt and decrypt with uneven blocks', () => { + const data = Buffer.from( + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855010203', + 'hex'); + + const expected = Buffer.from('' + + '83de502a9c83112ca6383f2214a892a0cdad5ab2b3e192e9' + + '921ddb126b25262c5211801019a30c0c6f795296923e0af8', + 'hex'); - let hash2 = Buffer.concat([digest.sha256(Buffer.alloc(0)), Buffer.from([1,2,3])]); - let enchash2 = nencrypt(hash2, 'foo'); - let dechash2 = ndecrypt(enchash2, 'foo'); + const ciphertext = aes.encipher(data, key, iv); + assert.bufferEqual(ciphertext, expected); - assert.deepEqual(hash, hash2); - assert.deepEqual(enchash, enchash2); - assert.deepEqual(dechash, dechash2); + const plaintext = aes.decipher(ciphertext, key, iv); + assert.bufferEqual(plaintext, data); }); }); diff --git a/test/bech32-test.js b/test/bech32-test.js index a50a28551..e78f78fc9 100644 --- a/test/bech32-test.js +++ b/test/bech32-test.js @@ -21,127 +21,134 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const bech32 = require('../lib/utils/bech32'); const Address = require('../lib/primitives/address'); -describe('Bech32', function() { - const VALID_CHECKSUM = [ - 'A12UEL5L', - 'an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs', - 'abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw', - '11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j', - 'split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w' - ]; - - const VALID_ADDRESS = [ - [ - 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4', - Buffer.from([ - 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 - ]) - ], - [ - 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', - Buffer.from([ - 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, - 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, - 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, - 0x62 - ]) - ], - [ - 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx', - Buffer.from([ - 0x81, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, - 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, - 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 - ]) - ], - [ - 'BC1SW50QA3JX3S', - Buffer.from([ - 0x90, 0x02, 0x75, 0x1e - ]) - ], - [ - 'bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj', - Buffer.from([ - 0x82, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23 - ]) - ], - [ - 'tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy', - Buffer.from([ - 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, - 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, - 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, - 0x33 - ]) - ] - ]; - - const INVALID_ADDRESS = [ - 'tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty', - 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5', - 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2', - 'bc1rw5uspcuh', - 'bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90', - 'BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', - 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7', - 'tb1pw508d6qejxtdg4y5r3zarqfsj6c3', - 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv', - ]; - - function fromAddress(hrp, addr) { - let dec = bech32.decode(addr); - - if (dec.hrp !== hrp) - throw new Error('Invalid bech32 prefix or data length.'); - - if (dec.version === 0 && dec.hash.length !== 20 && dec.hash.length !== 32) - throw new Error('Malformed witness program.'); - - return { - version: dec.version, - program: dec.hash - }; - } - - function toAddress(hrp, version, program) { - let ret = bech32.encode(hrp, version, program); - - fromAddress(hrp, ret); - - return ret; - } - - function createProgram(version, program) { - let ver = Buffer.from([version ? version + 0x80 : 0, program.length]); - return Buffer.concat([ver, program]); - } +const validChecksums = [ + 'A12UEL5L', + 'an83characterlonghumanreadablepartthatcontains' + + 'thenumber1andtheexcludedcharactersbio1tt5tgs', + 'abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw', + '11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + + 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j', + 'split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w' +]; + +const validAddresses = [ + [ + 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4', + Buffer.from([ + 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 + ]) + ], + [ + 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', + Buffer.from([ + 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, + 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, + 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, + 0x62 + ]) + ], + [ + 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw50' + + '8d6qejxtdg4y5r3zarvary0c5xw7k7grplx', + Buffer.from([ + 0x81, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, + 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, + 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 + ]) + ], + [ + 'BC1SW50QA3JX3S', + Buffer.from([ + 0x90, 0x02, 0x75, 0x1e + ]) + ], + [ + 'bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj', + Buffer.from([ + 0x82, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23 + ]) + ], + [ + 'tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy', + Buffer.from([ + 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, + 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, + 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, + 0x33 + ]) + ] +]; + +const invalidAddresses = [ + 'tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty', + 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5', + 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2', + 'bc1rw5uspcuh', + 'bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d' + + '6qejxtdg4y5r3zarvary0c5xw7kw5rljs90', + 'BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', + 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7', + 'tb1pw508d6qejxtdg4y5r3zarqfsj6c3', + 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv' +]; + +function fromAddress(hrp, addr) { + const dec = bech32.decode(addr); + + if (dec.hrp !== hrp) + throw new Error('Invalid bech32 prefix or data length.'); + + if (dec.version === 0 && dec.hash.length !== 20 && dec.hash.length !== 32) + throw new Error('Malformed witness program.'); + + return { + version: dec.version, + program: dec.hash + }; +} + +function toAddress(hrp, version, program) { + const ret = bech32.encode(hrp, version, program); + + fromAddress(hrp, ret); + + return ret; +} + +function createProgram(version, program) { + const data = Buffer.allocUnsafe(2 + program.length); + data[0] = version ? version + 0x80 : 0; + data[1] = program.length; + program.copy(data, 2); + return data; +} - VALID_CHECKSUM.forEach((test) => { - it(`should have valid checksum for ${test}`, () => { - let ret = bech32.deserialize(test); - assert(ret); +describe('Bech32', function() { + for (const addr of validChecksums) { + it(`should have valid checksum for ${addr}`, () => { + assert(bech32.deserialize(addr)); }); - }); + } - VALID_ADDRESS.forEach((test) => { - let address = test[0]; - let scriptpubkey = test[1]; - it(`should have valid address for ${address}`, () => { + for (const [addr, script] of validAddresses) { + it(`should have valid address for ${addr}`, () => { let hrp = 'bc'; - let ret, ok, output, recreate; + let ret = null; try { - ret = fromAddress(hrp, address); + ret = fromAddress(hrp, addr); } catch (e) { ret = null; } @@ -149,108 +156,61 @@ describe('Bech32', function() { if (ret === null) { hrp = 'tb'; try { - ret = fromAddress(hrp, address); + ret = fromAddress(hrp, addr); } catch (e) { ret = null; } } - ok = ret !== null; - - if (ok) { - output = createProgram(ret.version, ret.program); - ok = output.compare(scriptpubkey) === 0; - } + assert(ret !== null); - if (ok) { - recreate = toAddress(hrp, ret.version, ret.program); - ok = (recreate === address.toLowerCase()); - } + const output = createProgram(ret.version, ret.program); + assert.bufferEqual(output, script); - assert(ok); + const recreate = toAddress(hrp, ret.version, ret.program); + assert.strictEqual(recreate, addr.toLowerCase()); }); - }); - - INVALID_ADDRESS.forEach((test) => { - it(`should have invalid address for ${test}`, () => { - let ok1, ok2, ok; - - try { - ok1 = fromAddress('bc', test); - } catch (e) { - ok1 = null; - } - - try { - ok2 = fromAddress('tb', test); - } catch (e) { - ok2 = null; - } + } - ok = ok1 === null && ok2 === null; - assert(ok); + for (const addr of invalidAddresses) { + it(`should have invalid address for ${addr}`, () => { + assert.throws(() => fromAddress('bc', addr)); + assert.throws(() => fromAddress('tb', addr)); }); - }); - - VALID_ADDRESS.forEach((test, i) => { - let address = test[0]; - let scriptpubkey = test[1]; - - // TODO: Fix. (wrong length for program) - // Need to drop old segwit addrs. - if (i >= 2 && i <= 4) - return; + } - it(`should have valid address for ${address}`, () => { - let ret, ok, output, recreate; + for (const [addr, script] of validAddresses) { + it(`should have valid address for ${addr}`, () => { + let ret = null; try { - ret = Address.fromBech32(address, 'main'); + ret = Address.fromBech32(addr, 'main'); } catch (e) { ret = null; } if (ret === null) { try { - ret = Address.fromBech32(address, 'testnet'); + ret = Address.fromBech32(addr, 'testnet'); } catch (e) { ret = null; } } - ok = ret !== null; + assert(ret !== null); - if (ok) { - output = createProgram(ret.version, ret.hash); - ok = output.compare(scriptpubkey) === 0; - } - - if (ok) { - recreate = ret.toBech32(); - ok = (recreate === address.toLowerCase()); - } + const output = createProgram(ret.version, ret.hash); + assert.bufferEqual(output, script); - assert(ok); + const recreate = ret.toBech32(); + assert.strictEqual(recreate, addr.toLowerCase()); }); - }); - - INVALID_ADDRESS.forEach((test) => { - it(`should have invalid address for ${test}`, () => { - let ok1, ok2; - - try { - ok1 = Address.fromBech32(test, 'main'); - } catch (e) { - ok1 = null; - } - - try { - ok2 = Address.fromBech32(test, 'testnet'); - } catch (e) { - ok2 = null; - } + } - assert(!ok1 && !ok2); + for (const addr of invalidAddresses) { + it(`should have invalid address for ${addr}`, () => { + assert.throws(() => Address.fromBech32(addr, 'main')); + assert.throws(() => Address.fromBech32(addr, 'testnet')); }); - }); + } }); diff --git a/test/bip150-test.js b/test/bip150-test.js index d816f5677..b78c1587e 100644 --- a/test/bip150-test.js +++ b/test/bip150-test.js @@ -1,34 +1,37 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const secp256k1 = require('../lib/crypto/secp256k1'); const BIP150 = require('../lib/net/bip150'); const BIP151 = require('../lib/net/bip151'); -describe('BIP150', function() { - let db = new BIP150.AuthDB(); - let ck = secp256k1.generatePrivateKey(); - let sk = secp256k1.generatePrivateKey(); +const db = new BIP150.AuthDB(); +const ck = secp256k1.generatePrivateKey(); +const sk = secp256k1.generatePrivateKey(); - db.addAuthorized(secp256k1.publicKeyCreate(ck, true)); - db.addKnown('127.0.0.2', secp256k1.publicKeyCreate(sk, true)); +db.addAuthorized(secp256k1.publicKeyCreate(ck, true)); +db.addKnown('127.0.0.2', secp256k1.publicKeyCreate(sk, true)); - let client = new BIP151(); - let server = new BIP151(); +const client = new BIP151(); +const server = new BIP151(); - client.bip150 = new BIP150(client, '127.0.0.2', true, db, ck); - server.bip150 = new BIP150(server, '127.0.0.1', false, db, sk); +client.bip150 = new BIP150(client, '127.0.0.2', true, db, ck); +server.bip150 = new BIP150(server, '127.0.0.1', false, db, sk); - function payload() { - return Buffer.from('deadbeef', 'hex'); - } +function payload() { + return Buffer.from('deadbeef', 'hex'); +} +describe('BIP150', function() { it('should do encinit', () => { - let init = server.toEncinit(); + const init = server.toEncinit(); client.encinit(init.publicKey, init.cipher); - init = client.toEncinit(); - server.encinit(init.publicKey, init.cipher); + const init2 = client.toEncinit(); + server.encinit(init2.publicKey, init2.cipher); assert(!client.handshake); assert(!server.handshake); @@ -49,14 +52,12 @@ describe('BIP150', function() { }); it('should do BIP150 handshake', () => { - let challenge, reply, propose, result; - - challenge = client.bip150.toChallenge(); - reply = server.bip150.challenge(challenge.hash); - propose = client.bip150.reply(reply); - challenge = server.bip150.propose(propose); - reply = client.bip150.challenge(challenge); - result = server.bip150.reply(reply); + const challenge = client.bip150.toChallenge(); + const reply = server.bip150.challenge(challenge.hash); + const propose = client.bip150.reply(reply); + const challenge2 = server.bip150.propose(propose); + const reply2 = client.bip150.challenge(challenge2); + const result = server.bip150.reply(reply2); assert(!result); assert(client.bip150.auth); @@ -64,64 +65,76 @@ describe('BIP150', function() { }); it('should encrypt payload from client to server', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('should encrypt payload from client to server (2)', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client (2)', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('client should rekey', () => { + const bytes = client.output.processed; let rekeyed = false; - let bytes = client.output.processed; client.once('rekey', () => { rekeyed = true; - let packet = client.packet('encack', client.toRekey().toRaw()); + const packet = client.packet('encack', client.toRekey().toRaw()); let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'encack'); + assert.strictEqual(cmd, 'encack'); server.encack(body); }); server.feed(packet); @@ -139,70 +152,86 @@ describe('BIP150', function() { }); it('should encrypt payload from client to server after rekey', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client after rekey', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('should encrypt payload from client to server after rekey (2)', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client after rekey (2)', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('should encrypt payloads both ways asynchronously', () => { - let spacket = server.packet('fake', payload()); - let cpacket = client.packet('fake', payload()); + const spacket = server.packet('fake', payload()); + const cpacket = client.packet('fake', payload()); + let cemitted = false; - let semitted = false; client.once('packet', (cmd, body) => { cemitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + + let semitted = false; server.once('packet', (cmd, body) => { semitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(spacket); server.feed(cpacket); + assert(cemitted); assert(semitted); }); diff --git a/test/bip151-test.js b/test/bip151-test.js index 637717088..42e7e86e1 100644 --- a/test/bip151-test.js +++ b/test/bip151-test.js @@ -1,16 +1,19 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const BIP151 = require('../lib/net/bip151'); -describe('BIP151', function() { - let client = new BIP151(); - let server = new BIP151(); +const client = new BIP151(); +const server = new BIP151(); - function payload() { - return Buffer.from('deadbeef', 'hex'); - } +function payload() { + return Buffer.from('deadbeef', 'hex'); +} +describe('BIP151', function() { it('should do encinit', () => { let init = server.toEncinit(); client.encinit(init.publicKey, init.cipher); @@ -37,64 +40,76 @@ describe('BIP151', function() { }); it('should encrypt payload from client to server', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('should encrypt payload from client to server (2)', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client (2)', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('client should rekey', () => { + const bytes = client.output.processed; let rekeyed = false; - let bytes = client.output.processed; client.once('rekey', () => { rekeyed = true; - let packet = client.packet('encack', client.toRekey().toRaw()); + const packet = client.packet('encack', client.toRekey().toRaw()); let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'encack'); + assert.strictEqual(cmd, 'encack'); server.encack(body); }); server.feed(packet); @@ -112,70 +127,86 @@ describe('BIP151', function() { }); it('should encrypt payload from client to server after rekey', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client after rekey', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('should encrypt payload from client to server after rekey (2)', () => { - let packet = client.packet('fake', payload()); + const packet = client.packet('fake', payload()); + let emitted = false; server.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + server.feed(packet); + assert(emitted); }); it('should encrypt payload from server to client after rekey (2)', () => { - let packet = server.packet('fake', payload()); + const packet = server.packet('fake', payload()); + let emitted = false; client.once('packet', (cmd, body) => { emitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(packet); + assert(emitted); }); it('should encrypt payloads both ways asynchronously', () => { - let spacket = server.packet('fake', payload()); - let cpacket = client.packet('fake', payload()); + const spacket = server.packet('fake', payload()); + const cpacket = client.packet('fake', payload()); + let cemitted = false; - let semitted = false; client.once('packet', (cmd, body) => { cemitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + + let semitted = false; server.once('packet', (cmd, body) => { semitted = true; - assert.equal(cmd, 'fake'); - assert.equal(body.toString('hex'), 'deadbeef'); + assert.strictEqual(cmd, 'fake'); + assert.bufferEqual(body, payload()); }); + client.feed(spacket); server.feed(cpacket); + assert(cemitted); assert(semitted); }); diff --git a/test/bip70-test.js b/test/bip70-test.js index f5fa11662..1e63ce2e5 100644 --- a/test/bip70-test.js +++ b/test/bip70-test.js @@ -1,6 +1,9 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const util = require('../lib/utils/util'); const bip70 = require('../lib/bip70'); const Address = require('../lib/primitives/address'); @@ -19,27 +22,27 @@ tests.ca = { }; x509.allowUntrusted = true; -x509.trusted = {}; +x509.trusted.clear(); -describe('BIP70', function() { - function testRequest(data) { - let request = bip70.PaymentRequest.fromRaw(data); - let ser; +x509.verifyTime = function() { + return true; +}; - assert.equal(request.pkiType, 'x509+sha256'); - assert(request.pkiData); - assert(request.getChain()); - assert(request.paymentDetails); - assert(request.paymentDetails.memo.length !== 0); - assert(request.paymentDetails.paymentUrl.length !== 0); +function testRequest(data) { + const req = bip70.PaymentRequest.fromRaw(data); - ser = request.toRaw(); - assert.equal(ser.toString('hex'), data.toString('hex')); - assert(request.verify()); - } + assert.strictEqual(req.pkiType, 'x509+sha256'); + assert(req.pkiData); + assert(req.getChain()); + assert(req.paymentDetails); + assert(req.paymentDetails.memo.length !== 0); + assert(req.paymentDetails.paymentUrl.length !== 0); - x509.verifyTime = function() { return true; }; + assert.bufferEqual(req.toRaw(), data); + assert(req.verify()); +} +describe('BIP70', function() { it('should parse and verify a payment request', () => { testRequest(tests.valid); testRequest(tests.invalid); @@ -47,120 +50,118 @@ describe('BIP70', function() { }); it('should verify cert chain', () => { - let request = bip70.PaymentRequest.fromRaw(tests.valid); + const req1 = bip70.PaymentRequest.fromRaw(tests.valid); - assert.equal(request.version, 1); - assert.equal(request.getChain().length, 4); - assert.equal(request.paymentDetails.paymentUrl, + assert.strictEqual(req1.version, 1); + assert.strictEqual(req1.getChain().length, 4); + assert.strictEqual(req1.paymentDetails.paymentUrl, 'https://test.bitpay.com/i/CMWpuFsjgmQ2ZLiyGfcF1W'); - assert.equal(request.paymentDetails.network, 'test'); - assert.equal(request.paymentDetails.time, 1408645830); - assert.equal(request.paymentDetails.expires, 1408646730); - assert.equal(request.paymentDetails.outputs.length, 1); - assert(!request.paymentDetails.merchantData); - assert(request.paymentDetails.isExpired()); + assert.strictEqual(req1.paymentDetails.network, 'test'); + assert.strictEqual(req1.paymentDetails.time, 1408645830); + assert.strictEqual(req1.paymentDetails.expires, 1408646730); + assert.strictEqual(req1.paymentDetails.outputs.length, 1); + assert(!req1.paymentDetails.merchantData); + assert(req1.paymentDetails.isExpired()); - assert(request.verifyChain()); + assert(req1.verifyChain()); - request = bip70.PaymentRequest.fromRaw(tests.invalid); + const req2 = bip70.PaymentRequest.fromRaw(tests.invalid); - assert.equal(request.version, 1); - assert.equal(request.getChain().length, 3); - assert.equal(request.paymentDetails.paymentUrl, + assert.strictEqual(req2.version, 1); + assert.strictEqual(req2.getChain().length, 3); + assert.strictEqual(req2.paymentDetails.paymentUrl, 'https://bitpay.com/i/PAQtNxX7KL8BtJBnfXyTaH'); - assert.equal(request.paymentDetails.network, 'main'); - assert.equal(request.paymentDetails.time, 1442409238); - assert.equal(request.paymentDetails.expires, 1442410138); - assert.equal(request.paymentDetails.outputs.length, 1); - assert.equal(request.paymentDetails.merchantData.length, 76); - assert(request.paymentDetails.getData('json')); - assert(request.paymentDetails.isExpired()); - - assert(request.verifyChain()); - - request.paymentDetails.setData({foo:1}, 'json'); - assert.equal(request.paymentDetails.merchantData.length, 9); - assert.deepStrictEqual(request.paymentDetails.getData('json'), {foo:1}); - assert(!request.verify()); - - request = bip70.PaymentRequest.fromRaw(tests.untrusted); - - assert.equal(request.version, -1); - assert.equal(request.getChain().length, 2); - assert.equal(request.paymentDetails.paymentUrl, + assert.strictEqual(req2.paymentDetails.network, 'main'); + assert.strictEqual(req2.paymentDetails.time, 1442409238); + assert.strictEqual(req2.paymentDetails.expires, 1442410138); + assert.strictEqual(req2.paymentDetails.outputs.length, 1); + assert.strictEqual(req2.paymentDetails.merchantData.length, 76); + assert(req2.paymentDetails.getData('json')); + assert(req2.paymentDetails.isExpired()); + + assert(req2.verifyChain()); + + req2.paymentDetails.setData({foo:1}, 'json'); + assert.strictEqual(req2.paymentDetails.merchantData.length, 9); + assert.deepStrictEqual(req2.paymentDetails.getData('json'), {foo:1}); + assert(!req2.verify()); + + const req3 = bip70.PaymentRequest.fromRaw(tests.untrusted); + + assert.strictEqual(req3.version, -1); + assert.strictEqual(req3.getChain().length, 2); + assert.strictEqual(req3.paymentDetails.paymentUrl, 'https://www.coinbase.com/rp/55f9ca703d5d80008c0001f4'); - assert.equal(request.paymentDetails.network, null); - assert.equal(request.paymentDetails.time, 1442433682); - assert.equal(request.paymentDetails.expires, 1442434548); - assert.equal(request.paymentDetails.outputs.length, 1); - assert.equal(request.paymentDetails.merchantData.length, 32); - assert.equal(request.paymentDetails.getData('utf8'), + assert.strictEqual(req3.paymentDetails.network, null); + assert.strictEqual(req3.paymentDetails.time, 1442433682); + assert.strictEqual(req3.paymentDetails.expires, 1442434548); + assert.strictEqual(req3.paymentDetails.outputs.length, 1); + assert.strictEqual(req3.paymentDetails.merchantData.length, 32); + assert.strictEqual(req3.paymentDetails.getData('utf8'), 'bb79b6f2310e321bd3b1d929edbeb358'); - assert(request.paymentDetails.isExpired()); + assert(req3.paymentDetails.isExpired()); - assert(request.verifyChain()); + assert(req3.verifyChain()); }); it('should fail to verify cert signatures when enforcing trust', () => { - let request; - x509.allowUntrusted = false; - request = bip70.PaymentRequest.fromRaw(tests.valid); - assert(!request.verifyChain()); + const req1 = bip70.PaymentRequest.fromRaw(tests.valid); + assert(!req1.verifyChain()); - request = bip70.PaymentRequest.fromRaw(tests.invalid); - assert(!request.verifyChain()); + const req2 = bip70.PaymentRequest.fromRaw(tests.invalid); + assert(!req2.verifyChain()); - request = bip70.PaymentRequest.fromRaw(tests.untrusted); - assert(!request.verifyChain()); + const req3 = bip70.PaymentRequest.fromRaw(tests.untrusted); + assert(!req3.verifyChain()); }); it('should verify cert signatures once root cert is added', () => { - let request = bip70.PaymentRequest.fromRaw(tests.valid); - x509.setTrust([request.getChain().pop()]); - assert(request.verifyChain()); + const req1 = bip70.PaymentRequest.fromRaw(tests.valid); + x509.setTrust([req1.getChain().pop()]); + assert(req1.verifyChain()); - request = bip70.PaymentRequest.fromRaw(tests.untrusted); - assert(!request.verifyChain()); + const req2 = bip70.PaymentRequest.fromRaw(tests.untrusted); + assert(!req2.verifyChain()); }); it('should still fail to verify cert signatures for invalid', () => { - let request = bip70.PaymentRequest.fromRaw(tests.invalid); - assert(!request.verifyChain()); + const req = bip70.PaymentRequest.fromRaw(tests.invalid); + assert(!req.verifyChain()); }); it('should get chain and ca for request', () => { - let request = bip70.PaymentRequest.fromRaw(tests.valid); - assert.equal(request.getChain().length, 4); - assert.equal(request.getCA().name, + const req = bip70.PaymentRequest.fromRaw(tests.valid); + assert.strictEqual(req.getChain().length, 4); + assert.strictEqual(req.getCA().name, 'Go Daddy Class 2 Certification Authority'); }); it('should validate untrusted once again', () => { - let request = bip70.PaymentRequest.fromRaw(tests.untrusted); - x509.setTrust([request.getChain().pop()]); + const req1 = bip70.PaymentRequest.fromRaw(tests.untrusted); + x509.setTrust([req1.getChain().pop()]); - request = bip70.PaymentRequest.fromRaw(tests.untrusted); - assert(request.verifyChain()); - assert.equal(request.getCA().name, + const req2 = bip70.PaymentRequest.fromRaw(tests.untrusted); + assert(req2.verifyChain()); + assert.strictEqual(req2.getCA().name, 'DigiCert SHA2 Extended Validation Server CA'); }); it('should parse a payment ack', () => { - let ack = bip70.PaymentACK.fromRaw(tests.ack); - assert.equal(ack.memo.length, 95); - assert.equal(ack.memo, 'Transaction received by BitPay.' + const ack = bip70.PaymentACK.fromRaw(tests.ack); + assert.strictEqual(ack.memo.length, 95); + assert.strictEqual(ack.memo, 'Transaction received by BitPay.' + ' Invoice will be marked as paid if the transaction is confirmed.'); - assert.equal(ack.toRaw().toString('hex'), tests.ack.toString('hex')); + assert.bufferEqual(ack.toRaw(), tests.ack); }); it('should create a payment request, sign, and verify', () => { - let request = new bip70.PaymentRequest({ + const req = new bip70.PaymentRequest({ version: 25, paymentDetails: { network: 'testnet', - paymentUrl: 'http://bcoin.io/payme', + paymentUrl: 'http://bcoin.io/payment', memo: 'foobar', time: util.now(), expires: util.now() + 3600, @@ -172,41 +173,43 @@ describe('BIP70', function() { } }); - assert.equal(request.pkiType, null); - assert(!request.pkiData); - assert.equal(request.getChain().length, 0); - assert(request.paymentDetails); - assert(request.paymentDetails.memo.length !== 0); - assert(request.paymentDetails.paymentUrl.length !== 0); - assert.deepStrictEqual(request.paymentDetails.getData('json'), {foo:'bar'}); - - assert.equal(request.version, 25); - assert.equal(request.paymentDetails.paymentUrl, 'http://bcoin.io/payme'); - assert.equal(request.paymentDetails.network, 'testnet'); - assert(request.paymentDetails.time <= util.now()); - assert.equal(request.paymentDetails.expires, - request.paymentDetails.time + 3600); - assert.equal(request.paymentDetails.outputs.length, 2); - assert(request.paymentDetails.merchantData); - assert(!request.paymentDetails.isExpired()); - - assert(!request.pkiData); - request.sign(tests.ca.priv, [tests.ca.crt]); - - assert(request.pkiData); - assert.equal(request.pkiType, 'x509+sha256'); - assert.equal(request.getChain().length, 1); - - assert(request.verify()); - assert(!request.verifyChain()); - - testRequest(request.toRaw()); + assert.strictEqual(req.pkiType, null); + assert(!req.pkiData); + assert.strictEqual(req.getChain().length, 0); + assert(req.paymentDetails); + assert(req.paymentDetails.memo.length !== 0); + assert(req.paymentDetails.paymentUrl.length !== 0); + assert.deepStrictEqual(req.paymentDetails.getData('json'), {foo:'bar'}); + + assert.strictEqual(req.version, 25); + assert.strictEqual(req.paymentDetails.paymentUrl, + 'http://bcoin.io/payment'); + assert.strictEqual(req.paymentDetails.network, 'testnet'); + assert(req.paymentDetails.time <= util.now()); + assert.strictEqual(req.paymentDetails.expires, + req.paymentDetails.time + 3600); + assert.strictEqual(req.paymentDetails.outputs.length, 2); + assert(req.paymentDetails.merchantData); + assert(!req.paymentDetails.isExpired()); + + assert(!req.pkiData); + req.setChain([tests.ca.crt]); + req.sign(tests.ca.priv); + + assert(req.pkiData); + assert.strictEqual(req.pkiType, 'x509+sha256'); + assert.strictEqual(req.getChain().length, 1); + + assert(req.verify()); + assert(!req.verifyChain()); + + testRequest(req.toRaw()); x509.setTrust([tests.ca.crt]); - assert(request.verifyChain()); - assert.equal(request.getCA().name, 'JJs CA'); + assert(req.verifyChain()); + assert.strictEqual(req.getCA().name, 'JJs CA'); - request.version = 24; - assert(!request.verify()); + req.version = 24; + assert(!req.verify()); }); }); diff --git a/test/block-test.js b/test/block-test.js index 5b7f32139..349514bed 100644 --- a/test/block-test.js +++ b/test/block-test.js @@ -1,506 +1,363 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const fs = require('fs'); -const assert = require('assert'); +const assert = require('./util/assert'); +const common = require('./util/common'); const Bloom = require('../lib/utils/bloom'); const Block = require('../lib/primitives/block'); -const Headers = require('../lib/primitives/headers'); const MerkleBlock = require('../lib/primitives/merkleblock'); -const CoinView = require('../lib/coins/coinview'); -const Coin = require('../lib/primitives/coin'); -const Coins = require('../lib/coins/coins'); -const UndoCoins = require('../lib/coins/undocoins'); const consensus = require('../lib/protocol/consensus'); const Script = require('../lib/script/script'); const encoding = require('../lib/utils/encoding'); const bip152 = require('../lib/net/bip152'); - -const block300025 = require('./data/block300025.json'); -const cmpct2block = fs.readFileSync(`${__dirname}/data/cmpct2.bin`); - -let cmpct1 = fs.readFileSync(`${__dirname}/data/compactblock.hex`, 'utf8'); -let cmpct2 = fs.readFileSync(`${__dirname}/data/cmpct2`, 'utf8'); - -cmpct1 = cmpct1.trim().split('\n'); -cmpct2 = cmpct2.trim(); - -function applyUndo(block, undo) { - let view = new CoinView(); - - for (let i = block.txs.length - 1; i > 0; i--) { - let tx = block.txs[i]; - - for (let j = tx.inputs.length - 1; j >= 0; j--) { - let input = tx.inputs[j]; - let prev = input.prevout.hash; - - if (!view.has(prev)) { - assert(!undo.isEmpty()); - - if (undo.top().height === -1) { - let coins = new Coins(); - coins.hash = prev; - coins.coinbase = false; - view.add(coins); - } - } - - undo.apply(view, input.prevout); - } - } - - assert(undo.isEmpty(), 'Undo coins data inconsistency.'); - - return view; -} +const CompactBlock = bip152.CompactBlock; +const TXRequest = bip152.TXRequest; +const TXResponse = bip152.TXResponse; + +// Block test vectors +const block300025 = common.readBlock('block300025'); + +// Merkle block test vectors +const merkle300025 = common.readMerkle('merkle300025'); + +// Compact block test vectors +const block426884 = common.readBlock('block426884'); +const compact426884 = common.readCompact('compact426884'); +const block898352 = common.readBlock('block898352'); +const compact898352 = common.readCompact('compact898352'); + +// Sigops counting test vectors +// Format: [name, sigops, weight] +const sigopsVectors = [ + ['block928816', 9109, 3568200], + ['block928828', 23236, 2481560], + ['block928831', 10035, 3992382], + ['block928848', 11319, 3992537], + ['block928849', 9137, 3682105], + ['block928927', 10015, 3992391], + ['block1087400', 1298, 193331] +]; describe('Block', function() { - let mblock, raw, block, raw2; - - mblock = new MerkleBlock({ - version: 2, - prevBlock: 'd1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0000000000000000', - merkleRoot: '28bec1d35af480ba3884553d72694f6ba6c163a5c081d7e6edaec15f373f19af', - ts: 1399713634, - bits: 419465580, - nonce: 1186968784, - totalTX: 461, - hashes: [ - '7d22e53bce1bbb3294d1a396c5acc45bdcc8f192cb492f0d9f55421fd4c62de1', - '9d6d585fdaf3737b9a54aaee1dd003f498328d699b7dfb42dd2b44b6ebde2333', - '8b61da3053d6f382f2145bdd856bc5dcf052c3a11c1784d3d51b2cbe0f6d0923', - 'd7bbaae4716cb0d329d755b707cee588cddc68601f99bc05fef1fabeb8dfe4a0', - '7393f84cd04ca8931975c66282ebf1847c78d8de6c2578d4f9bae23bc6f30857', - 'ec8c51de3170301430ec56f6703533d9ea5b05c6fa7068954bcb90eed8c2ee5c', - 'c7c152869db09a5ae2291fa03142912d9d7aba75be7d491a8ac4230ee9a920cb', - '5adbf04583354515a225f2c418de7c5cdac4cef211820c79717cd2c50412153f', - '1f5e46b9da3a8b1241f4a1501741d3453bafddf6135b600b926e3f4056c6d564', - '33825657ba32afe269819f01993bd77baba86379043168c94845d32370e53562' - ], - flags: Buffer.from([245, 122, 0]) - }); - raw = mblock.toRaw().toString('hex'); - - raw2 = '02000000d1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0' - + '00000000000000028bec1d35af480ba3884553d72694f6ba6c163a5c081d7e6edaec' - + '15f373f19af62ef6d536c890019d0b4bf46cd0100000a7d22e53bce1bbb3294d1a39' - + '6c5acc45bdcc8f192cb492f0d9f55421fd4c62de19d6d585fdaf3737b9a54aaee1dd' - + '003f498328d699b7dfb42dd2b44b6ebde23338b61da3053d6f382f2145bdd856bc5d' - + 'cf052c3a11c1784d3d51b2cbe0f6d0923d7bbaae4716cb0d329d755b707cee588cdd' - + 'c68601f99bc05fef1fabeb8dfe4a07393f84cd04ca8931975c66282ebf1847c78d8d' - + 'e6c2578d4f9bae23bc6f30857ec8c51de3170301430ec56f6703533d9ea5b05c6fa7' - + '068954bcb90eed8c2ee5cc7c152869db09a5ae2291fa03142912d9d7aba75be7d491' - + 'a8ac4230ee9a920cb5adbf04583354515a225f2c418de7c5cdac4cef211820c79717' - + 'cd2c50412153f1f5e46b9da3a8b1241f4a1501741d3453bafddf6135b600b926e3f4' - + '056c6d56433825657ba32afe269819f01993bd77baba86379043168c94845d32370e' - + '5356203f57a00'; - - mblock = MerkleBlock.fromRaw(raw2, 'hex'); - this.timeout(10000); it('should parse partial merkle tree', () => { - let tree; + const [block] = merkle300025.getBlock(); - assert(mblock.verifyPOW()); - assert(mblock.verifyBody()); - assert(mblock.verify()); + assert(block.verifyPOW()); + assert(block.verifyBody()); + assert(block.verify()); - tree = mblock.getTree(); + const tree = block.getTree(); - assert.equal(tree.matches.length, 2); - assert.equal(mblock.hash('hex'), + assert.strictEqual(tree.matches.length, 2); + assert.strictEqual(block.hash('hex'), '8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000'); - assert.equal(mblock.rhash(), + assert.strictEqual(block.rhash(), '0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c'); - assert.equal( + assert.strictEqual( tree.matches[0].toString('hex'), '7393f84cd04ca8931975c66282ebf1847c78d8de6c2578d4f9bae23bc6f30857'); - assert.equal( + assert.strictEqual( tree.matches[1].toString('hex'), 'ec8c51de3170301430ec56f6703533d9ea5b05c6fa7068954bcb90eed8c2ee5c'); }); - it('should decode/encode with parser/framer', () => { - let b = MerkleBlock.fromRaw(raw, 'hex'); - assert.equal(b.toRaw().toString('hex'), raw); - assert.equal(raw, raw2); - }); - - it('should be verifiable', () => { - let b = MerkleBlock.fromRaw(raw, 'hex'); - assert(b.verify()); + it('should decode/encode merkle block', () => { + const [block] = merkle300025.getBlock(); + block.refresh(); + assert.bufferEqual(block.toRaw(), merkle300025.getRaw()); }); - it('should be serialized and deserialized and still verify', () => { - let raw = mblock.toRaw(); - let b = MerkleBlock.fromRaw(raw); - assert.deepEqual(b.toRaw(), raw); - assert(b.verify()); + it('should verify merkle block', () => { + const [block] = merkle300025.getBlock(); + assert(block.verify()); }); - it('should be jsonified and unjsonified and still verify', () => { - let raw = mblock.toJSON(); - let b = MerkleBlock.fromJSON(raw); - assert.deepEqual(b.toJSON(), raw); - assert(b.verify()); + it('should be encoded/decoded and still verify', () => { + const [block1] = merkle300025.getBlock(); + const raw = block1.toRaw(); + const block2 = MerkleBlock.fromRaw(raw); + assert.bufferEqual(block2.toRaw(), raw); + assert(block2.verify()); }); - it('should calculate reward properly', () => { - let height = 0; - let total = 0; - - for (;;) { - let reward = consensus.getReward(height, 210000); - assert(reward <= consensus.COIN * 50); - total += reward; - if (reward === 0) - break; - height++; - } - - assert.equal(height, 6930000); - assert.equal(total, 2099999997690000); + it('should be jsonified/unjsonified and still verify', () => { + const [block1] = merkle300025.getBlock(); + const json = block1.toJSON(); + const block2 = MerkleBlock.fromJSON(json); + assert.deepStrictEqual(block2.toJSON(), json); + assert(block2.verify()); }); it('should parse JSON', () => { - block = Block.fromJSON(block300025); - assert.equal(block.hash('hex'), + const [block1] = block300025.getBlock(); + const block2 = Block.fromJSON(block1.toJSON()); + assert.strictEqual(block2.hash('hex'), '8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000'); - assert.equal(block.rhash(), + assert.strictEqual(block2.rhash(), '0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c'); - assert.equal(block.merkleRoot, block.createMerkleRoot('hex')); + assert.strictEqual(block2.merkleRoot, block2.createMerkleRoot('hex')); }); it('should create a merkle block', () => { - let filter, item1, item2, mblock2; + const filter = Bloom.fromRate(1000, 0.01, Bloom.flags.NONE); - filter = Bloom.fromRate(1000, 0.01, Bloom.flags.NONE); - - item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b'; - item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10' + const item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b'; + const item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10' + 'e763272c6c9ca052972c69e3884a9022084215e2eef' + '0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e'; filter.add(item1, 'hex'); filter.add(item2, 'hex'); - mblock2 = MerkleBlock.fromBlock(block, filter); + const [block1] = block300025.getBlock(); + const block2 = MerkleBlock.fromBlock(block1, filter); - assert(mblock2.verifyBody()); - assert.deepEqual(mblock2.toRaw(), mblock.toRaw()); + assert(block2.verifyBody()); + assert.bufferEqual(block2.toRaw(), merkle300025.getRaw()); }); it('should verify a historical block', () => { - let view = new CoinView(); - let height = block300025.height; - let sigops = 0; - let reward = 0; - let flags; - - for (let i = 1; i < block300025.txs.length; i++) { - let tx = block300025.txs[i]; - for (let j = 0; j < tx.inputs.length; j++) { - let input = tx.inputs[j]; - let coin = Coin.fromJSON(input.coin); - view.addCoin(coin); - } - } + const [block, view] = block300025.getBlock(); + const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; + const height = 300025; assert(block.verify()); assert(block.txs[0].isCoinbase()); assert(block.txs[0].isSane()); assert(!block.hasWitness()); - assert.equal(block.getWeight(), 1136924); + assert.strictEqual(block.getWeight(), 1136924); - flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; + let sigops = 0; + let reward = 0; for (let i = 1; i < block.txs.length; i++) { - let tx = block.txs[i]; + const tx = block.txs[i]; + assert(tx.isSane()); assert(tx.verifyInputs(view, height)); assert(tx.verify(view, flags)); assert(!tx.hasWitness()); + sigops += tx.getSigopsCost(view, flags); - view.addTX(tx, height); reward += tx.getFee(view); + + view.addTX(tx, height); } reward += consensus.getReward(height, 210000); - assert.equal(sigops, 5280); - assert.equal(reward, 2507773345); - assert.equal(reward, block.txs[0].outputs[0].value); + assert.strictEqual(sigops, 5280); + assert.strictEqual(reward, 2507773345); + assert.strictEqual(reward, block.txs[0].outputs[0].value); }); it('should fail with a bad merkle root', () => { - let block2 = new Block(block); - let reason; - block2.merkleRoot = encoding.NULL_HASH; - block2.refresh(); - assert(!block2.verifyPOW()); - [, reason] = block2.checkBody(); - assert.equal(reason, 'bad-txnmrklroot'); - assert(!block2.verify()); - block2.merkleRoot = block.merkleRoot; - block2.refresh(); - assert(block2.verify()); + const [block] = block300025.getBlock(); + const merkleRoot = block.merkleRoot; + block.merkleRoot = encoding.NULL_HASH; + block.refresh(); + assert(!block.verifyPOW()); + const [, reason] = block.checkBody(); + assert.strictEqual(reason, 'bad-txnmrklroot'); + assert(!block.verify()); + block.merkleRoot = merkleRoot; + block.refresh(); + assert(block.verify()); }); it('should fail on merkle block with a bad merkle root', () => { - let mblock2 = new MerkleBlock(mblock); - let reason; - mblock2.merkleRoot = encoding.NULL_HASH; - mblock2.refresh(); - assert(!mblock2.verifyPOW()); - [, reason] = mblock2.checkBody(); - assert.equal(reason, 'bad-txnmrklroot'); - assert(!mblock2.verify()); - mblock2.merkleRoot = mblock.merkleRoot; - mblock2.refresh(); - assert(mblock2.verify()); + const [block] = merkle300025.getBlock(); + const merkleRoot = block.merkleRoot; + block.merkleRoot = encoding.NULL_HASH; + block.refresh(); + assert(!block.verifyPOW()); + const [, reason] = block.checkBody(); + assert.strictEqual(reason, 'bad-txnmrklroot'); + assert(!block.verify()); + block.merkleRoot = merkleRoot; + block.refresh(); + assert(block.verify()); }); it('should fail with a low target', () => { - let block2 = new Block(block); - block2.bits = 403014710; - block2.refresh(); - assert(!block2.verifyPOW()); - assert(block2.verifyBody()); - assert(!block2.verify()); - block2.bits = block.bits; - block2.refresh(); - assert(block2.verify()); + const [block] = block300025.getBlock(); + const bits = block.bits; + block.bits = 403014710; + block.refresh(); + assert(!block.verifyPOW()); + assert(block.verifyBody()); + assert(!block.verify()); + block.bits = bits; + block.refresh(); + assert(block.verify()); }); it('should fail on duplicate txs', () => { - let block2 = new Block(block); - let reason; - block2.txs.push(block2.txs[block2.txs.length - 1]); - block2.refresh(); - [, reason] = block2.checkBody(); - assert.equal(reason, 'bad-txns-duplicate'); + const [block] = block300025.getBlock(); + block.txs.push(block.txs[block.txs.length - 1]); + block.refresh(); + const [, reason] = block.checkBody(); + assert.strictEqual(reason, 'bad-txns-duplicate'); }); it('should verify with headers', () => { - let headers = new Headers(block); + const headers = block300025.getHeaders(); assert(headers.verifyPOW()); assert(headers.verifyBody()); assert(headers.verify()); }); it('should handle compact block', () => { - let block = Block.fromRaw(cmpct1[1], 'hex'); - let cblock1 = bip152.CompactBlock.fromRaw(cmpct1[0], 'hex'); - let cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock1.keyNonce); - let map = new Map(); - let i, tx, mempool, result; + const [block] = block426884.getBlock(); + const [cblock1] = compact426884.getBlock(); + const cblock2 = CompactBlock.fromBlock(block, false, cblock1.keyNonce); assert(cblock1.init()); - assert.equal(cblock1.toRaw().toString('hex'), cmpct1[0]); - assert.equal(cblock2.toRaw().toString('hex'), cmpct1[0]); + assert.bufferEqual(cblock1.toRaw(), compact426884.getRaw()); + assert.bufferEqual(cblock2.toRaw(), compact426884.getRaw()); - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - map.set(tx.hash('hex'), { tx: tx }); - } - - mempool = { - map: map - }; + const map = new Map(); - assert.equal(cblock1.sid(block.txs[1].hash()), 125673511480291); + for (let i = 1; i < block.txs.length; i++) { + const tx = block.txs[i]; + map.set(tx.hash('hex'), { tx }); + } - result = cblock1.fillMempool(false, mempool); - assert(result); + const full = cblock1.fillMempool(false, { map }); + assert(full); - for (i = 0; i < cblock1.available.length; i++) - assert(cblock1.available[i]); + for (const tx of cblock1.available) + assert(tx); - assert.equal( - cblock1.toBlock().toRaw().toString('hex'), - block.toRaw().toString('hex')); + assert.bufferEqual(cblock1.toBlock().toRaw(), block.toRaw()); }); it('should handle half-full compact block', () => { - let block = Block.fromRaw(cmpct1[1], 'hex'); - let cblock1 = bip152.CompactBlock.fromRaw(cmpct1[0], 'hex'); - let cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock1.keyNonce); - let map = new Map(); - let i, tx, mempool, result, req, res; + const [block] = block426884.getBlock(); + const [cblock1] = compact426884.getBlock(); + const cblock2 = CompactBlock.fromBlock(block, false, cblock1.keyNonce); assert(cblock1.init()); - assert.equal(cblock1.toRaw().toString('hex'), cmpct1[0]); - assert.equal(cblock2.toRaw().toString('hex'), cmpct1[0]); + assert.bufferEqual(cblock1.toRaw(), compact426884.getRaw()); + assert.bufferEqual(cblock2.toRaw(), compact426884.getRaw()); - for (i = 0; i < block.txs.length >>> 1; i++) { - tx = block.txs[i]; - map.set(tx.hash('hex'), { tx: tx }); - } - - mempool = { - map: map - }; - - assert.equal(cblock1.sid(block.txs[1].hash()), 125673511480291); + const map = new Map(); - result = cblock1.fillMempool(false, mempool); - assert(!result); + for (let i = 1; i < ((block.txs.length + 1) >>> 1); i++) { + const tx = block.txs[i]; + map.set(tx.hash('hex'), { tx }); + } - req = cblock1.toRequest(); - assert.equal(req.hash, cblock1.hash('hex')); - assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]); + const full = cblock1.fillMempool(false, { map }); + assert(!full); - req = bip152.TXRequest.fromRaw(req.toRaw()); - assert.equal(req.hash, cblock1.hash('hex')); - assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]); + const rawReq = cblock1.toRequest().toRaw(); + const req = TXRequest.fromRaw(rawReq); + assert.strictEqual(req.hash, cblock1.hash('hex')); - res = bip152.TXResponse.fromBlock(block, req); - res = bip152.TXResponse.fromRaw(res.toRaw()); + const rawRes = TXResponse.fromBlock(block, req).toRaw(); + const res = TXResponse.fromRaw(rawRes); - result = cblock1.fillMissing(res); - assert(result); + const filled = cblock1.fillMissing(res); + assert(filled); - for (i = 0; i < cblock1.available.length; i++) - assert(cblock1.available[i]); + for (const tx of cblock1.available) + assert(tx); - assert.equal( - cblock1.toBlock().toRaw().toString('hex'), - block.toRaw().toString('hex')); + assert.bufferEqual(cblock1.toBlock().toRaw(), block.toRaw()); }); it('should handle compact block', () => { - let block = Block.fromRaw(cmpct2block); - let cblock1 = bip152.CompactBlock.fromRaw(cmpct2, 'hex'); - let cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock1.keyNonce); - let map = new Map(); - let i, tx, result, mempool; + const [block] = block898352.getBlock(); + const [cblock1] = compact898352.getBlock(); + const cblock2 = CompactBlock.fromBlock(block, false, cblock1.keyNonce); assert(cblock1.init()); - assert.equal(cblock1.toRaw().toString('hex'), cmpct2); - assert.equal(cblock2.toRaw().toString('hex'), cmpct2); + assert.bufferEqual(cblock1.toRaw(), compact898352.getRaw()); + assert.bufferEqual(cblock2.toRaw(), compact898352.getRaw()); - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - map.set(tx.hash('hex'), { tx: tx }); - } + assert.strictEqual(cblock1.sid(block.txs[1].hash()), 125673511480291); - mempool = { - map: map - }; + const map = new Map(); - result = cblock1.fillMempool(false, mempool); - assert(result); + for (let i = 1; i < block.txs.length; i++) { + const tx = block.txs[i]; + map.set(tx.hash('hex'), { tx }); + } - for (i = 0; i < cblock1.available.length; i++) - assert(cblock1.available[i]); + const full = cblock1.fillMempool(false, { map }); + assert(full); - assert.equal( - cblock1.toBlock().toRaw().toString('hex'), - block.toRaw().toString('hex')); + for (const tx of cblock1.available) + assert(tx); + + assert.bufferEqual(cblock1.toBlock().toRaw(), block.toRaw()); }); it('should handle half-full compact block', () => { - let block = Block.fromRaw(cmpct2block); - let cblock1 = bip152.CompactBlock.fromRaw(cmpct2, 'hex'); - let cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock1.keyNonce); - let map = new Map(); - let i, tx, mempool, result, req, res; + const [block] = block898352.getBlock(); + const [cblock1] = compact898352.getBlock(); + const cblock2 = CompactBlock.fromBlock(block, false, cblock1.keyNonce); assert(cblock1.init()); - assert.equal(cblock1.toRaw().toString('hex'), cmpct2); - assert.equal(cblock2.toRaw().toString('hex'), cmpct2); - - for (i = 0; i < block.txs.length >>> 1; i++) { - tx = block.txs[i]; - map.set(tx.hash('hex'), { tx: tx }); - } + assert.bufferEqual(cblock1.toRaw(), compact898352.getRaw()); + assert.bufferEqual(cblock2.toRaw(), compact898352.getRaw()); - mempool = { - map: map - }; + assert.strictEqual(cblock1.sid(block.txs[1].hash()), 125673511480291); - result = cblock1.fillMempool(false, mempool); - assert(!result); + const map = new Map(); - req = cblock1.toRequest(); - assert.equal(req.hash, cblock1.hash('hex')); + for (let i = 1; i < ((block.txs.length + 1) >>> 1); i++) { + const tx = block.txs[i]; + map.set(tx.hash('hex'), { tx }); + } - req = bip152.TXRequest.fromRaw(req.toRaw()); - assert.equal(req.hash, cblock1.hash('hex')); + const full = cblock1.fillMempool(false, { map }); + assert(!full); - res = bip152.TXResponse.fromBlock(block, req); - res = bip152.TXResponse.fromRaw(res.toRaw()); + const rawReq = cblock1.toRequest().toRaw(); + const req = TXRequest.fromRaw(rawReq); + assert.strictEqual(req.hash, cblock1.hash('hex')); + assert.deepStrictEqual(req.indexes, [5, 6, 7, 8, 9]); - result = cblock1.fillMissing(res); - assert(result); + const rawRes = TXResponse.fromBlock(block, req).toRaw(); + const res = TXResponse.fromRaw(rawRes); - for (i = 0; i < cblock1.available.length; i++) - assert(cblock1.available[i]); + const filled = cblock1.fillMissing(res); + assert(filled); - assert.equal( - cblock1.toBlock().toRaw().toString('hex'), - block.toRaw().toString('hex')); - }); - - it('should count sigops for block 928828 (testnet)', () => { - let blockRaw = fs.readFileSync(`${__dirname}/data/block928828.raw`); - let undoRaw = fs.readFileSync(`${__dirname}/data/undo928828.raw`); - let block = Block.fromRaw(blockRaw); - let undo = UndoCoins.fromRaw(undoRaw); - let view = applyUndo(block, undo); - let sigops = 0; - let flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; - let i, tx; + for (const tx of cblock1.available) + assert(tx); - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - sigops += tx.getSigopsCost(view, flags); - } - - assert.equal(sigops, 23236); - assert.equal(block.getWeight(), 2481560); + assert.bufferEqual(cblock1.toBlock().toRaw(), block.toRaw()); }); - it('should count sigops for block 928927 (testnet)', () => { - let blockRaw = fs.readFileSync(`${__dirname}/data/block928927.raw`); - let undoRaw = fs.readFileSync(`${__dirname}/data/undo928927.raw`); - let block = Block.fromRaw(blockRaw); - let undo = UndoCoins.fromRaw(undoRaw); - let view = applyUndo(block, undo); - let sigops = 0; - let flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; - let i, tx; - - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - sigops += tx.getSigopsCost(view, flags); - } + for (const cache of [false, true]) { + const word = cache ? 'with' : 'without'; + for (const [name, sigops, weight] of sigopsVectors) { + const ctx = common.readBlock(name); + it(`should count sigops for ${name} (${word} cache)`, () => { + const [block, view] = ctx.getBlock(); + const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; - assert.equal(sigops, 10015); - assert.equal(block.getWeight(), 3992391); - }); + if (!cache) + block.refresh(true); - it('should count sigops for block 1087400 (testnet)', () => { - let blockRaw = fs.readFileSync(`${__dirname}/data/block1087400.raw`); - let undoRaw = fs.readFileSync(`${__dirname}/data/undo1087400.raw`); - let block = Block.fromRaw(blockRaw); - let undo = UndoCoins.fromRaw(undoRaw); - let view = applyUndo(block, undo); - let sigops = 0; - let flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; - let i, tx; + let count = 0; + for (const tx of block.txs) + count += tx.getSigopsCost(view, flags); - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - sigops += tx.getSigopsCost(view, flags); + assert.strictEqual(count, sigops); + assert.strictEqual(block.getWeight(), weight); + }); } - - assert.equal(sigops, 1298); - assert.equal(block.getWeight(), 193331); - }); + } }); diff --git a/test/bloom-test.js b/test/bloom-test.js index 08efc5dc2..34b8934d0 100644 --- a/test/bloom-test.js +++ b/test/bloom-test.js @@ -1,174 +1,183 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const Bloom = require('../lib/utils/bloom'); const RollingFilter = require('../lib/utils/rollingfilter'); const murmur3 = require('../lib/utils/murmur3'); -describe('Bloom', function() { - const filterHex = '' - + '000000000000000000000000000000000000000000000000088004000000000000000' - + '000000000200000000000000000000000000000000800000000000000000002000000' - + '000000000000002000000000000000000000000000000000000000000040000200000' - + '0000000001000000800000080000000'; +function testMurmur(str, seed, expect, enc) { + if (!enc) + enc = 'ascii'; - function mm(str, seed, expect, enc) { - assert.equal(murmur3(Buffer.from(str, enc || 'ascii'), seed), expect); - } + const data = Buffer.from(str, enc); + const hash = murmur3(data, seed); + assert.strictEqual(hash, expect); +} + +describe('Bloom', function() { this.timeout(20000); it('should do proper murmur3', () => { - mm('', 0, 0); - mm('', 0xfba4c795, 0x6a396f08); - mm('00', 0xfba4c795, 0x2a101837); - mm('hello world', 0, 0x5e928f0f); - - mm('', 0x00000000, 0x00000000, 'hex'); - mm('', 0xfba4c795, 0x6a396f08, 'hex'); - mm('', 0xffffffff, 0x81f16f39, 'hex'); - - mm('00', 0x00000000, 0x514e28b7, 'hex'); - mm('00', 0xfba4c795, 0xea3f0b17, 'hex'); - mm('ff', 0x00000000, 0xfd6cf10d, 'hex'); - - mm('0011', 0x00000000, 0x16c6b7ab, 'hex'); - mm('001122', 0x00000000, 0x8eb51c3d, 'hex'); - mm('00112233', 0x00000000, 0xb4471bf8, 'hex'); - mm('0011223344', 0x00000000, 0xe2301fa8, 'hex'); - mm('001122334455', 0x00000000, 0xfc2e4a15, 'hex'); - mm('00112233445566', 0x00000000, 0xb074502c, 'hex'); - mm('0011223344556677', 0x00000000, 0x8034d2a0, 'hex'); - mm('001122334455667788', 0x00000000, 0xb4698def, 'hex'); + testMurmur('', 0, 0); + testMurmur('', 0xfba4c795, 0x6a396f08); + testMurmur('00', 0xfba4c795, 0x2a101837); + testMurmur('hello world', 0, 0x5e928f0f); + + testMurmur('', 0x00000000, 0x00000000, 'hex'); + testMurmur('', 0xfba4c795, 0x6a396f08, 'hex'); + testMurmur('', 0xffffffff, 0x81f16f39, 'hex'); + + testMurmur('00', 0x00000000, 0x514e28b7, 'hex'); + testMurmur('00', 0xfba4c795, 0xea3f0b17, 'hex'); + testMurmur('ff', 0x00000000, 0xfd6cf10d, 'hex'); + + testMurmur('0011', 0x00000000, 0x16c6b7ab, 'hex'); + testMurmur('001122', 0x00000000, 0x8eb51c3d, 'hex'); + testMurmur('00112233', 0x00000000, 0xb4471bf8, 'hex'); + testMurmur('0011223344', 0x00000000, 0xe2301fa8, 'hex'); + testMurmur('001122334455', 0x00000000, 0xfc2e4a15, 'hex'); + testMurmur('00112233445566', 0x00000000, 0xb074502c, 'hex'); + testMurmur('0011223344556677', 0x00000000, 0x8034d2a0, 'hex'); + testMurmur('001122334455667788', 0x00000000, 0xb4698def, 'hex'); }); it('should test and add stuff', () => { - let b = new Bloom(512, 10, 156); + const filter = new Bloom(512, 10, 156); - b.add('hello', 'ascii'); - assert(b.test('hello', 'ascii')); - assert(!b.test('hello!', 'ascii')); - assert(!b.test('ping', 'ascii')); + filter.add('hello', 'ascii'); + assert(filter.test('hello', 'ascii')); + assert(!filter.test('hello!', 'ascii')); + assert(!filter.test('ping', 'ascii')); - b.add('hello!', 'ascii'); - assert(b.test('hello!', 'ascii')); - assert(!b.test('ping', 'ascii')); + filter.add('hello!', 'ascii'); + assert(filter.test('hello!', 'ascii')); + assert(!filter.test('ping', 'ascii')); - b.add('ping', 'ascii'); - assert(b.test('ping', 'ascii')); + filter.add('ping', 'ascii'); + assert(filter.test('ping', 'ascii')); }); it('should serialize to the correct format', () => { - let filter = new Bloom(952, 6, 3624314491, Bloom.flags.NONE); - let item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b'; - let item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10' + const filter = new Bloom(952, 6, 3624314491, Bloom.flags.NONE); + const item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b'; + const item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10' + 'e763272c6c9ca052972c69e3884a9022084215e2eef' + '0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e'; + + const expected = Buffer.from('' + + '000000000000000000000000000000000000000000000000088004000000000000000' + + '000000000200000000000000000000000000000000800000000000000000002000000' + + '000000000000002000000000000000000000000000000000000000000040000200000' + + '0000000001000000800000080000000', + 'hex'); + filter.add(item1, 'hex'); filter.add(item2, 'hex'); - assert.equal(filter.filter.toString('hex'), filterHex); + + assert.bufferEqual(filter.filter, expected); }); it('should handle 1m ops with regular filter', () => { - let filter = Bloom.fromRate(210000, 0.00001, -1); - let i, j, str; + const filter = Bloom.fromRate(210000, 0.00001, -1); filter.tweak = 0xdeadbeef; // ~1m operations - for (i = 0; i < 1000; i++) { - str = 'foobar' + i; + for (let i = 0; i < 1000; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true); - assert(filter.test(str + '-', 'ascii') === false); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j--); } }); it('should handle 1m ops with rolling filter', () => { - let filter = new RollingFilter(210000, 0.00001); - let i, j, str; + const filter = new RollingFilter(210000, 0.00001); filter.tweak = 0xdeadbeef; // ~1m operations - for (i = 0; i < 1000; i++) { - str = 'foobar' + i; + for (let i = 0; i < 1000; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true); - assert(filter.test(str + '-', 'ascii') === false); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j--); } }); it('should handle rolling generations', () => { - let filter = new RollingFilter(50, 0.00001); - let i, j, str; + const filter = new RollingFilter(50, 0.00001); filter.tweak = 0xdeadbeee; - for (i = 0; i < 25; i++) { - str = 'foobar' + i; + for (let i = 0; i < 25; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true); - assert(filter.test(str + '-', 'ascii') === false); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j--); } - for (i = 25; i < 50; i++) { - str = 'foobar' + i; + for (let i = 25; i < 50; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true, str); - assert(filter.test(str + '-', 'ascii') === false, str); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j--); } - for (i = 50; i < 75; i++) { - str = 'foobar' + i; + for (let i = 50; i < 75; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true, str); - assert(filter.test(str + '-', 'ascii') === false, str); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j--); } - for (i = 75; i < 100; i++) { - str = 'foobar' + i; + for (let i = 75; i < 100; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true, str); - assert(filter.test(str + '-', 'ascii') === false, str); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j-- > 25); - assert(filter.test('foobar 24', 'ascii') === false); + assert(!filter.test('foobar 24', 'ascii')); } - for (i = 100; i < 125; i++) { - str = 'foobar' + i; + for (let i = 100; i < 125; i++) { + const str = 'foobar' + i; + let j = i; filter.add(str, 'ascii'); - j = i; do { - str = 'foobar' + j; - assert(filter.test(str, 'ascii') === true, str); - assert(filter.test(str + '-', 'ascii') === false, str); + const str = 'foobar' + j; + assert(filter.test(str, 'ascii')); + assert(!filter.test(str + '-', 'ascii')); } while (j-- > 50); } - assert(filter.test('foobar 49', 'ascii') === false); + assert(!filter.test('foobar 49', 'ascii')); }); }); diff --git a/test/chachapoly-test.js b/test/chachapoly-test.js index 5399e3474..27beb23c1 100644 --- a/test/chachapoly-test.js +++ b/test/chachapoly-test.js @@ -1,74 +1,62 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const ChaCha20 = require('../lib/crypto/chacha20'); const Poly1305 = require('../lib/crypto/poly1305'); const AEAD = require('../lib/crypto/aead'); -describe('ChaCha20 / Poly1305 / AEAD', function() { - function testChaCha(options) { - let key = options.key; - let nonce = options.nonce; - let plain = options.plain; - let ciphertext = options.ciphertext; - let counter = options.counter; - let chacha, plainenc; - - key = Buffer.from(key, 'hex'); - nonce = Buffer.from(nonce, 'hex'); - plain = Buffer.from(plain, 'hex'); - ciphertext = Buffer.from(ciphertext, 'hex'); - - chacha = new ChaCha20(); - chacha.init(key, nonce, counter); - plainenc = Buffer.from(plain); - chacha.encrypt(plainenc); - assert.deepEqual(plainenc, ciphertext); - - chacha = new ChaCha20(); - chacha.init(key, nonce, counter); - chacha.encrypt(ciphertext); - assert.deepEqual(plain, ciphertext); - } - - function testAEAD(options) { - let plain = options.plain; - let aad = options.aad; - let key = options.key; - let nonce = options.nonce; - let pk = options.pk; - let ciphertext = options.ciphertext; - let tag = options.tag; - let aead, plainenc; - - plain = Buffer.from(plain, 'hex'); - aad = Buffer.from(aad, 'hex'); - key = Buffer.from(key, 'hex'); - nonce = Buffer.from(nonce, 'hex'); - pk = Buffer.from(pk, 'hex'); - ciphertext = Buffer.from(ciphertext, 'hex'); - tag = Buffer.from(tag, 'hex'); - - aead = new AEAD(); - aead.init(key, nonce); - assert.equal(aead.chacha20.getCounter(), 1); - assert.deepEqual(aead.polyKey, pk); - aead.aad(aad); - plainenc = Buffer.from(plain); - aead.encrypt(plainenc); - assert.deepEqual(plainenc, ciphertext); - assert.deepEqual(aead.finish(), tag); - - aead = new AEAD(); - aead.init(key, nonce); - assert.equal(aead.chacha20.getCounter(), 1); - assert.deepEqual(aead.polyKey, pk); - aead.aad(aad); - aead.decrypt(ciphertext); - assert.deepEqual(ciphertext, plain); - assert.deepEqual(aead.finish(), tag); - } +function testChaCha(options) { + const key = Buffer.from(options.key, 'hex'); + const nonce = Buffer.from(options.nonce, 'hex'); + const plain = Buffer.from(options.plain, 'hex'); + const ciphertext = Buffer.from(options.ciphertext, 'hex'); + const counter = options.counter; + + const ctx1 = new ChaCha20(); + ctx1.init(key, nonce, counter); + const plainenc = Buffer.from(plain); + ctx1.encrypt(plainenc); + assert.bufferEqual(plainenc, ciphertext); + + const ctx2 = new ChaCha20(); + ctx2.init(key, nonce, counter); + ctx2.encrypt(ciphertext); + assert.bufferEqual(plain, ciphertext); +} + +function testAEAD(options) { + const plain = Buffer.from(options.plain, 'hex'); + const aad = Buffer.from(options.aad, 'hex'); + const key = Buffer.from(options.key, 'hex'); + const nonce = Buffer.from(options.nonce, 'hex'); + const pk = Buffer.from(options.pk, 'hex'); + const ciphertext = Buffer.from(options.ciphertext, 'hex'); + const tag = Buffer.from(options.tag, 'hex'); + + const ctx1 = new AEAD(); + ctx1.init(key, nonce); + assert.strictEqual(ctx1.chacha20.getCounter(), 1); + assert.bufferEqual(ctx1.polyKey, pk); + ctx1.aad(aad); + const plainenc = Buffer.from(plain); + ctx1.encrypt(plainenc); + assert.bufferEqual(plainenc, ciphertext); + assert.bufferEqual(ctx1.finish(), tag); + + const ctx2 = new AEAD(); + ctx2.init(key, nonce); + assert.strictEqual(ctx2.chacha20.getCounter(), 1); + assert.bufferEqual(ctx2.polyKey, pk); + ctx2.aad(aad); + ctx2.decrypt(ciphertext); + assert.bufferEqual(ciphertext, plain); + assert.bufferEqual(ctx2.finish(), tag); +} +describe('ChaCha20 / Poly1305 / AEAD', function() { it('should perform chacha20', () => { testChaCha({ key: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', @@ -96,7 +84,8 @@ describe('ChaCha20 / Poly1305 / AEAD', function() { + '0000000000000000000000000000000000000000000000000000000000000000', ciphertext: '' + '76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b77' - + '0dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586', + + '0dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669' + + 'b2ee6586', counter: 0 }); }); @@ -159,35 +148,37 @@ describe('ChaCha20 / Poly1305 / AEAD', function() { }); it('should perform poly1305', () => { - let expected = Buffer.from('ddb9da7ddd5e52792730ed5cda5f90a4', 'hex'); - let key = Buffer.allocUnsafe(32); - let msg = Buffer.allocUnsafe(73); - let mac; - let i; + const expected = Buffer.from('ddb9da7ddd5e52792730ed5cda5f90a4', 'hex'); + const key = Buffer.allocUnsafe(32); + const msg = Buffer.allocUnsafe(73); - for (i = 0; i < key.length; i++) + for (let i = 0; i < key.length; i++) key[i] = i + 221; - for (i = 0; i < msg.length; i++) + for (let i = 0; i < msg.length; i++) msg[i] = i + 121; - mac = Poly1305.auth(msg, key); + const mac = Poly1305.auth(msg, key); assert(Poly1305.verify(mac, expected)); - assert.deepEqual(mac, expected); + assert.bufferEqual(mac, expected); }); it('should perform poly1305', () => { - let key = '85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b'; - let msg = 'Cryptographic Forum Research Group'; - let tag = 'a8061dc1305136c6c22b8baf0c0127a9'; - let mac; + const key = Buffer.from('' + + '85d6be7857556d337f4452fe42d506a' + + '80103808afb0db2fd4abff6af4149f51b', + 'hex'); - key = Buffer.from(key, 'hex'); - msg = Buffer.from(msg, 'ascii'); - tag = Buffer.from(tag, 'hex'); + const msg = Buffer.from('Cryptographic Forum Research Group', 'ascii'); + const tag = Buffer.from('a8061dc1305136c6c22b8baf0c0127a9', 'hex'); + + const mac = Poly1305.auth(msg, key); - mac = Poly1305.auth(msg, key); assert(Poly1305.verify(mac, tag)); + + mac[0] = 0; + + assert(!Poly1305.verify(mac, tag)); }); it('should create an AEAD and encrypt', () => { diff --git a/test/chain-test.js b/test/chain-test.js index 94808c987..c3785303b 100644 --- a/test/chain-test.js +++ b/test/chain-test.js @@ -1,85 +1,113 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); -const BN = require('../lib/crypto/bn'); +const assert = require('./util/assert'); const consensus = require('../lib/protocol/consensus'); const encoding = require('../lib/utils/encoding'); const Coin = require('../lib/primitives/coin'); const Script = require('../lib/script/script'); const Chain = require('../lib/blockchain/chain'); +const WorkerPool = require('../lib/workers/workerpool'); const Miner = require('../lib/mining/miner'); const MTX = require('../lib/primitives/mtx'); const MemWallet = require('./util/memwallet'); const Network = require('../lib/protocol/network'); const Output = require('../lib/primitives/output'); const common = require('../lib/blockchain/common'); +const Opcode = require('../lib/script/opcode'); const opcodes = Script.opcodes; -describe('Chain', function() { - const network = Network.get('regtest'); - const chain = new Chain({ db: 'memory', network: network }); - const miner = new Miner({ chain: chain, version: 4 }); - const wallet = new MemWallet({ network: network }); - const wwallet = new MemWallet({ network: network, witness: true }); - const cpu = miner.cpu; - let tip1, tip2; +const network = Network.get('regtest'); - this.timeout(45000); +const workers = new WorkerPool({ + enabled: true +}); - async function addBlock(block, flags) { - let entry; +const chain = new Chain({ + db: 'memory', + network, + workers +}); - try { - entry = await chain.add(block, flags); - } catch (e) { - assert(e.type === 'VerifyError'); - return e.reason; - } +const miner = new Miner({ + chain, + version: 4, + workers +}); - if (!entry) - return 'bad-prevblk'; +const cpu = miner.cpu; - return 'OK'; - } +const wallet = new MemWallet({ + network, + witness: false +}); + +const witWallet = new MemWallet({ + network, + witness: true +}); - async function mineBlock(job, flags) { - let block = await job.mineAsync(); - return await addBlock(block, flags); +let tip1 = null; +let tip2 = null; + +async function addBlock(block, flags) { + let entry; + + try { + entry = await chain.add(block, flags); + } catch (e) { + assert.strictEqual(e.type, 'VerifyError'); + return e.reason; } - async function mineCSV(tx) { - let job = await cpu.createJob(); - let rtx; + if (!entry) + return 'bad-prevblk'; - rtx = new MTX(); + return 'OK'; +} - rtx.addOutput({ - script: [ - Script.array(new BN(1)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY - ], - value: 10000 - }); +async function mineBlock(job, flags) { + const block = await job.mineAsync(); + return await addBlock(block, flags); +} - rtx.addTX(tx, 0); +async function mineCSV(fund) { + const job = await cpu.createJob(); + const spend = new MTX(); - rtx.setLocktime(chain.height); + spend.addOutput({ + script: [ + Opcode.fromInt(1), + Opcode.fromSymbol('checksequenceverify') + ], + value: 10000 + }); - wallet.sign(rtx); + spend.addTX(fund, 0); + spend.setLocktime(chain.height); - job.addTX(rtx.toTX(), rtx.view); - job.refresh(); + wallet.sign(spend); - return await job.mineAsync(); - } + const [tx, view] = spend.commit(); - chain.on('connect', (entry, block) => { - wallet.addBlock(entry, block.txs); - }); + job.addTX(tx, view); + job.refresh(); - chain.on('disconnect', (entry, block) => { - wallet.removeBlock(entry, block.txs); - }); + return await job.mineAsync(); +} + +chain.on('connect', (entry, block) => { + wallet.addBlock(entry, block.txs); +}); + +chain.on('disconnect', (entry, block) => { + wallet.removeBlock(entry, block.txs); +}); + +describe('Chain', function() { + this.timeout(45000); it('should open chain and miner', async () => { await chain.open(); @@ -92,25 +120,21 @@ describe('Chain', function() { }); it('should mine 200 blocks', async () => { - let i, block; - - for (i = 0; i < 200; i++) { - block = await cpu.mineBlock(); + for (let i = 0; i < 200; i++) { + const block = await cpu.mineBlock(); assert(block); assert(await chain.add(block)); } - assert.equal(chain.height, 200); + assert.strictEqual(chain.height, 200); }); it('should mine competing chains', async () => { - let i, mtx, job1, job2, blk1, blk2, hash1, hash2; + for (let i = 0; i < 10; i++) { + const job1 = await cpu.createJob(tip1); + const job2 = await cpu.createJob(tip2); - for (i = 0; i < 10; i++) { - job1 = await cpu.createJob(tip1); - job2 = await cpu.createJob(tip2); - - mtx = await wallet.create({ + const mtx = await wallet.create({ outputs: [{ address: wallet.getAddress(), value: 10 * 1e8 @@ -123,16 +147,16 @@ describe('Chain', function() { job1.refresh(); job2.refresh(); - blk1 = await job1.mineAsync(); - blk2 = await job2.mineAsync(); + const blk1 = await job1.mineAsync(); + const blk2 = await job2.mineAsync(); - hash1 = blk1.hash('hex'); - hash2 = blk2.hash('hex'); + const hash1 = blk1.hash('hex'); + const hash2 = blk2.hash('hex'); assert(await chain.add(blk1)); assert(await chain.add(blk2)); - assert(chain.tip.hash === hash1); + assert.strictEqual(chain.tip.hash, hash1); tip1 = await chain.db.getEntry(hash1); tip2 = await chain.db.getEntry(hash2); @@ -140,33 +164,31 @@ describe('Chain', function() { assert(tip1); assert(tip2); - assert(!(await tip2.isMainChain())); + assert(!await tip2.isMainChain()); } }); it('should have correct chain value', () => { - assert.equal(chain.db.state.value, 897500000000); - assert.equal(chain.db.state.coin, 220); - assert.equal(chain.db.state.tx, 221); + assert.strictEqual(chain.db.state.value, 897500000000); + assert.strictEqual(chain.db.state.coin, 220); + assert.strictEqual(chain.db.state.tx, 221); }); it('should have correct wallet balance', async () => { - assert.equal(wallet.balance, 897500000000); + assert.strictEqual(wallet.balance, 897500000000); }); it('should handle a reorg', async () => { - let forked = false; - let entry, block; + assert.strictEqual(chain.height, 210); - assert.equal(chain.height, 210); - - entry = await chain.db.getEntry(tip2.hash); + const entry = await chain.db.getEntry(tip2.hash); assert(entry); - assert(chain.height === entry.height); + assert.strictEqual(chain.height, entry.height); - block = await cpu.mineBlock(entry); + const block = await cpu.mineBlock(entry); assert(block); + let forked = false; chain.once('reorganize', () => { forked = true; }); @@ -174,98 +196,98 @@ describe('Chain', function() { assert(await chain.add(block)); assert(forked); - assert(chain.tip.hash === block.hash('hex')); + assert.strictEqual(chain.tip.hash, block.hash('hex')); assert(chain.tip.chainwork.cmp(tip1.chainwork) > 0); }); it('should have correct chain value', () => { - assert.equal(chain.db.state.value, 900000000000); - assert.equal(chain.db.state.coin, 221); - assert.equal(chain.db.state.tx, 222); + assert.strictEqual(chain.db.state.value, 900000000000); + assert.strictEqual(chain.db.state.coin, 221); + assert.strictEqual(chain.db.state.tx, 222); }); it('should have correct wallet balance', async () => { - assert.equal(wallet.balance, 900000000000); + assert.strictEqual(wallet.balance, 900000000000); }); it('should check main chain', async () => { - let result = await tip1.isMainChain(); + const result = await tip1.isMainChain(); assert(!result); }); it('should mine a block after a reorg', async () => { - let block = await cpu.mineBlock(); - let hash, entry, result; + const block = await cpu.mineBlock(); assert(await chain.add(block)); - hash = block.hash('hex'); - entry = await chain.db.getEntry(hash); + const hash = block.hash('hex'); + const entry = await chain.db.getEntry(hash); assert(entry); - assert(chain.tip.hash === entry.hash); + assert.strictEqual(chain.tip.hash, entry.hash); - result = await entry.isMainChain(); + const result = await entry.isMainChain(); assert(result); }); it('should prevent double spend on new chain', async () => { - let job = await cpu.createJob(); - let mtx, block; - - mtx = await wallet.create({ + const mtx = await wallet.create({ outputs: [{ address: wallet.getAddress(), value: 10 * 1e8 }] }); - job.addTX(mtx.toTX(), mtx.view); - job.refresh(); + { + const job = await cpu.createJob(); - block = await job.mineAsync(); + job.addTX(mtx.toTX(), mtx.view); + job.refresh(); - assert(await chain.add(block)); + const block = await job.mineAsync(); - job = await cpu.createJob(); + assert(await chain.add(block)); + } - assert(mtx.outputs.length > 1); - mtx.outputs.pop(); + { + const job = await cpu.createJob(); - job.addTX(mtx.toTX(), mtx.view); - job.refresh(); + assert(mtx.outputs.length > 1); + mtx.outputs.pop(); - assert.equal(await mineBlock(job), 'bad-txns-inputs-missingorspent'); + job.addTX(mtx.toTX(), mtx.view); + job.refresh(); + + assert.strictEqual(await mineBlock(job), + 'bad-txns-inputs-missingorspent'); + } }); it('should fail to connect coins on an alternate chain', async () => { - let block = await chain.db.getBlock(tip1.hash); - let cb = block.txs[0]; - let mtx = new MTX(); - let job; + const block = await chain.db.getBlock(tip1.hash); + const cb = block.txs[0]; + const mtx = new MTX(); mtx.addTX(cb, 0); mtx.addOutput(wallet.getAddress(), 10 * 1e8); wallet.sign(mtx); - job = await cpu.createJob(); + const job = await cpu.createJob(); job.addTX(mtx.toTX(), mtx.view); job.refresh(); - assert.equal(await mineBlock(job), 'bad-txns-inputs-missingorspent'); + assert.strictEqual(await mineBlock(job), 'bad-txns-inputs-missingorspent'); }); it('should have correct chain value', () => { - assert.equal(chain.db.state.value, 905000000000); - assert.equal(chain.db.state.coin, 224); - assert.equal(chain.db.state.tx, 225); + assert.strictEqual(chain.db.state.value, 905000000000); + assert.strictEqual(chain.db.state.coin, 224); + assert.strictEqual(chain.db.state.tx, 225); }); it('should get coin', async () => { - let mtx, job, block, tx, output, coin; - - mtx = await wallet.send({ + const mtx = await wallet.send({ outputs: [ { address: wallet.getAddress(), @@ -282,286 +304,287 @@ describe('Chain', function() { ] }); - job = await cpu.createJob(); + const job = await cpu.createJob(); job.addTX(mtx.toTX(), mtx.view); job.refresh(); - block = await job.mineAsync(); + const block = await job.mineAsync(); assert(await chain.add(block)); - tx = block.txs[1]; - output = Coin.fromTX(tx, 2, chain.height); + const tx = block.txs[1]; + const output = Coin.fromTX(tx, 2, chain.height); - coin = await chain.db.getCoin(tx.hash('hex'), 2); + const coin = await chain.db.getCoin(tx.hash('hex'), 2); - assert.deepEqual(coin.toRaw(), output.toRaw()); + assert.bufferEqual(coin.toRaw(), output.toRaw()); }); it('should have correct wallet balance', async () => { - assert.equal(wallet.balance, 907500000000); - assert.equal(wallet.receiveDepth, 15); - assert.equal(wallet.changeDepth, 14); - assert.equal(wallet.txs, 226); + assert.strictEqual(wallet.balance, 907500000000); + assert.strictEqual(wallet.receiveDepth, 15); + assert.strictEqual(wallet.changeDepth, 14); + assert.strictEqual(wallet.txs, 226); }); it('should get tips and remove chains', async () => { - let tips = await chain.db.getTips(); + { + const tips = await chain.db.getTips(); - assert.notEqual(tips.indexOf(chain.tip.hash), -1); - assert.equal(tips.length, 2); + assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + assert.strictEqual(tips.length, 2); + } await chain.db.removeChains(); - tips = await chain.db.getTips(); + { + const tips = await chain.db.getTips(); - assert.notEqual(tips.indexOf(chain.tip.hash), -1); - assert.equal(tips.length, 1); + assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + assert.strictEqual(tips.length, 1); + } }); it('should rescan for transactions', async () => { let total = 0; - await chain.db.scan(0, wallet.filter, (block, txs) => { + await chain.db.scan(0, wallet.filter, async (block, txs) => { total += txs.length; - return Promise.resolve(); }); - assert.equal(total, 226); + assert.strictEqual(total, 226); }); it('should activate csv', async () => { - let deployments = network.deployments; - let i, block, prev, state, cache; + const deployments = network.deployments; miner.options.version = -1; - assert.equal(chain.height, 214); + assert.strictEqual(chain.height, 214); - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert.equal(state, 1); + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 1); - for (i = 0; i < 417; i++) { - block = await cpu.mineBlock(); + for (let i = 0; i < 417; i++) { + const block = await cpu.mineBlock(); assert(await chain.add(block)); switch (chain.height) { - case 288: - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert.equal(state, 1); + case 288: { + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 1); break; - case 432: - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert.equal(state, 2); + } + case 432: { + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 2); break; - case 576: - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert.equal(state, 3); + } + case 576: { + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 3); break; + } } } - assert.equal(chain.height, 631); + assert.strictEqual(chain.height, 631); assert(chain.state.hasCSV()); assert(chain.state.hasWitness()); - cache = await chain.db.getStateCache(); - assert.deepEqual(cache, chain.db.stateCache); - assert.equal(chain.db.stateCache.updates.length, 0); + const cache = await chain.db.getStateCache(); + assert.deepStrictEqual(cache, chain.db.stateCache); + assert.strictEqual(chain.db.stateCache.updates.length, 0); assert(await chain.db.verifyDeployments()); }); it('should have activated segwit', async () => { - let deployments = network.deployments; - let prev = await chain.tip.getPrevious(); - let state = await chain.getState(prev, deployments.segwit); - assert.equal(state, 3); + const deployments = network.deployments; + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.segwit); + assert.strictEqual(state, 3); }); it('should test csv', async () => { - let tx = (await chain.db.getBlock(chain.height - 100)).txs[0]; - let block = await mineCSV(tx); - let csv, job, rtx; + const tx = (await chain.db.getBlock(chain.height - 100)).txs[0]; + const csvBlock = await mineCSV(tx); - assert(await chain.add(block)); + assert(await chain.add(csvBlock)); - csv = block.txs[1]; + const csv = csvBlock.txs[1]; - rtx = new MTX(); + const spend = new MTX(); - rtx.addOutput({ + spend.addOutput({ script: [ - Script.array(new BN(2)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY + Opcode.fromInt(2), + Opcode.fromSymbol('checksequenceverify') ], value: 10000 }); - rtx.addTX(csv, 0); - rtx.setSequence(0, 1, false); + spend.addTX(csv, 0); + spend.setSequence(0, 1, false); - job = await cpu.createJob(); + const job = await cpu.createJob(); - job.addTX(rtx.toTX(), rtx.view); + job.addTX(spend.toTX(), spend.view); job.refresh(); - block = await job.mineAsync(); + const block = await job.mineAsync(); assert(await chain.add(block)); }); it('should fail csv with bad sequence', async () => { - let csv = (await chain.db.getBlock(chain.height - 100)).txs[0]; - let rtx = new MTX(); - let job; + const csv = (await chain.db.getBlock(chain.height - 100)).txs[0]; + const spend = new MTX(); - rtx.addOutput({ + spend.addOutput({ script: [ - Script.array(new BN(1)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY + Opcode.fromInt(1), + Opcode.fromSymbol('checksequenceverify') ], value: 1 * 1e8 }); - rtx.addTX(csv, 0); - rtx.setSequence(0, 1, false); + spend.addTX(csv, 0); + spend.setSequence(0, 1, false); - job = await cpu.createJob(); - job.addTX(rtx.toTX(), rtx.view); + const job = await cpu.createJob(); + job.addTX(spend.toTX(), spend.view); job.refresh(); - assert.equal(await mineBlock(job), 'mandatory-script-verify-flag-failed'); + assert.strictEqual(await mineBlock(job), + 'mandatory-script-verify-flag-failed'); }); it('should mine a block', async () => { - let block = await cpu.mineBlock(); + const block = await cpu.mineBlock(); assert(block); assert(await chain.add(block)); }); it('should fail csv lock checks', async () => { - let tx = (await chain.db.getBlock(chain.height - 100)).txs[0]; - let block = await mineCSV(tx); - let csv, job, rtx; + const tx = (await chain.db.getBlock(chain.height - 100)).txs[0]; + const csvBlock = await mineCSV(tx); - assert(await chain.add(block)); + assert(await chain.add(csvBlock)); - csv = block.txs[1]; + const csv = csvBlock.txs[1]; - rtx = new MTX(); + const spend = new MTX(); - rtx.addOutput({ + spend.addOutput({ script: [ - Script.array(new BN(2)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY + Opcode.fromInt(2), + Opcode.fromSymbol('checksequenceverify') ], value: 1 * 1e8 }); - rtx.addTX(csv, 0); - rtx.setSequence(0, 2, false); + spend.addTX(csv, 0); + spend.setSequence(0, 2, false); - job = await cpu.createJob(); - job.addTX(rtx.toTX(), rtx.view); + const job = await cpu.createJob(); + job.addTX(spend.toTX(), spend.view); job.refresh(); - assert.equal(await mineBlock(job), 'bad-txns-nonfinal'); + assert.strictEqual(await mineBlock(job), 'bad-txns-nonfinal'); }); it('should have correct wallet balance', async () => { - assert.equal(wallet.balance, 1412499980000); + assert.strictEqual(wallet.balance, 1412499980000); }); it('should fail to connect bad bits', async () => { - let job = await cpu.createJob(); + const job = await cpu.createJob(); job.attempt.bits = 553713663; - assert.equal(await mineBlock(job), 'bad-diffbits'); + assert.strictEqual(await mineBlock(job), 'bad-diffbits'); }); it('should fail to connect bad MTP', async () => { - let mtp = await chain.tip.getMedianTime(); - let job = await cpu.createJob(); - job.attempt.ts = mtp - 1; - assert.equal(await mineBlock(job), 'time-too-old'); + const mtp = await chain.tip.getMedianTime(); + const job = await cpu.createJob(); + job.attempt.time = mtp - 1; + assert.strictEqual(await mineBlock(job), 'time-too-old'); }); it('should fail to connect bad time', async () => { - let job = await cpu.createJob(); - let now = network.now() + 3 * 60 * 60; - job.attempt.ts = now; - assert.equal(await mineBlock(job), 'time-too-new'); + const job = await cpu.createJob(); + const now = network.now() + 3 * 60 * 60; + job.attempt.time = now; + assert.strictEqual(await mineBlock(job), 'time-too-new'); }); it('should fail to connect bad locktime', async () => { - let job = await cpu.createJob(); - let tx = await wallet.send({ locktime: 100000 }); + const job = await cpu.createJob(); + const tx = await wallet.send({ locktime: 100000 }); job.pushTX(tx.toTX()); job.refresh(); - assert.equal(await mineBlock(job), 'bad-txns-nonfinal'); + assert.strictEqual(await mineBlock(job), 'bad-txns-nonfinal'); }); it('should fail to connect bad cb height', async () => { - let bip34height = network.block.bip34height; - let job = await cpu.createJob(); + const bip34height = network.block.bip34height; + const job = await cpu.createJob(); job.attempt.height = 10; job.attempt.refresh(); try { network.block.bip34height = 0; - assert.equal(await mineBlock(job), 'bad-cb-height'); + assert.strictEqual(await mineBlock(job), 'bad-cb-height'); } finally { network.block.bip34height = bip34height; } }); it('should fail to connect bad witness nonce size', async () => { - let block = await cpu.mineBlock(); - let tx = block.txs[0]; - let input = tx.inputs[0]; + const block = await cpu.mineBlock(); + const tx = block.txs[0]; + const input = tx.inputs[0]; input.witness.set(0, Buffer.allocUnsafe(33)); - input.witness.compile(); block.refresh(true); - assert.equal(await addBlock(block), 'bad-witness-nonce-size'); + assert.strictEqual(await addBlock(block), 'bad-witness-nonce-size'); }); it('should fail to connect bad witness nonce', async () => { - let block = await cpu.mineBlock(); - let tx = block.txs[0]; - let input = tx.inputs[0]; + const block = await cpu.mineBlock(); + const tx = block.txs[0]; + const input = tx.inputs[0]; input.witness.set(0, encoding.ONE_HASH); - input.witness.compile(); block.refresh(true); - assert.equal(await addBlock(block), 'bad-witness-merkle-match'); + assert.strictEqual(await addBlock(block), 'bad-witness-merkle-match'); }); it('should fail to connect bad witness commitment', async () => { - let flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; - let block = await cpu.mineBlock(); - let tx = block.txs[0]; - let output = tx.outputs[1]; - let commit; + const flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; + const block = await cpu.mineBlock(); + const tx = block.txs[0]; + const output = tx.outputs[1]; assert(output.script.isCommitment()); - commit = Buffer.from(output.script.get(1)); + const commit = Buffer.from(output.script.getData(1)); commit.fill(0, 10); - output.script.set(1, commit); + output.script.setData(1, commit); output.script.compile(); block.refresh(true); block.merkleRoot = block.createMerkleRoot('hex'); - assert.equal(await addBlock(block, flags), 'bad-witness-merkle-match'); + assert.strictEqual(await addBlock(block, flags), + 'bad-witness-merkle-match'); }); it('should fail to connect unexpected witness', async () => { - let flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; - let block = await cpu.mineBlock(); - let tx = block.txs[0]; - let output = tx.outputs[1]; + const flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; + const block = await cpu.mineBlock(); + const tx = block.txs[0]; + const output = tx.outputs[1]; assert(output.script.isCommitment()); @@ -570,227 +593,219 @@ describe('Chain', function() { block.refresh(true); block.merkleRoot = block.createMerkleRoot('hex'); - assert.equal(await addBlock(block, flags), 'unexpected-witness'); + assert.strictEqual(await addBlock(block, flags), 'unexpected-witness'); }); it('should add wit addrs to miner', async () => { miner.addresses.length = 0; - miner.addAddress(wwallet.getReceive()); - assert.equal(wwallet.getReceive().getType(), 'witness'); + miner.addAddress(witWallet.getReceive()); + assert.strictEqual(witWallet.getReceive().getType(), 'witness'); }); it('should mine 2000 witness blocks', async () => { - let i, block; - - for (i = 0; i < 2001; i++) { - block = await cpu.mineBlock(); + for (let i = 0; i < 2001; i++) { + const block = await cpu.mineBlock(); assert(block); assert(await chain.add(block)); } - assert.equal(chain.height, 2636); + assert.strictEqual(chain.height, 2636); }); it('should mine a witness tx', async () => { - let block = await chain.db.getBlock(chain.height - 2000); - let cb = block.txs[0]; - let mtx = new MTX(); - let job; + const prev = await chain.db.getBlock(chain.height - 2000); + const cb = prev.txs[0]; + const mtx = new MTX(); mtx.addTX(cb, 0); - mtx.addOutput(wwallet.getAddress(), 1000); + mtx.addOutput(witWallet.getAddress(), 1000); - wwallet.sign(mtx); + witWallet.sign(mtx); - job = await cpu.createJob(); + const job = await cpu.createJob(); job.addTX(mtx.toTX(), mtx.view); job.refresh(); - block = await job.mineAsync(); + const block = await job.mineAsync(); assert(await chain.add(block)); }); it('should mine fail to connect too much weight', async () => { - let start = chain.height - 2000; - let end = chain.height - 200; - let job = await cpu.createJob(); - let mtx = new MTX(); - let i, j, block, cb; + const start = chain.height - 2000; + const end = chain.height - 200; + const job = await cpu.createJob(); - for (i = start; i <= end; i++) { - block = await chain.db.getBlock(i); - cb = block.txs[0]; + for (let i = start; i <= end; i++) { + const block = await chain.db.getBlock(i); + const cb = block.txs[0]; - mtx = new MTX(); + const mtx = new MTX(); mtx.addTX(cb, 0); - for (j = 0; j < 16; j++) - mtx.addOutput(wwallet.getAddress(), 1); + for (let j = 0; j < 16; j++) + mtx.addOutput(witWallet.getAddress(), 1); - wwallet.sign(mtx); + witWallet.sign(mtx); job.pushTX(mtx.toTX()); } job.refresh(); - assert.equal(await mineBlock(job), 'bad-blk-weight'); + assert.strictEqual(await mineBlock(job), 'bad-blk-weight'); }); it('should mine fail to connect too much size', async () => { - let start = chain.height - 2000; - let end = chain.height - 200; - let job = await cpu.createJob(); - let mtx = new MTX(); - let i, j, block, cb; + const start = chain.height - 2000; + const end = chain.height - 200; + const job = await cpu.createJob(); - for (i = start; i <= end; i++) { - block = await chain.db.getBlock(i); - cb = block.txs[0]; + for (let i = start; i <= end; i++) { + const block = await chain.db.getBlock(i); + const cb = block.txs[0]; - mtx = new MTX(); + const mtx = new MTX(); mtx.addTX(cb, 0); - for (j = 0; j < 20; j++) - mtx.addOutput(wwallet.getAddress(), 1); + for (let j = 0; j < 20; j++) + mtx.addOutput(witWallet.getAddress(), 1); - wwallet.sign(mtx); + witWallet.sign(mtx); job.pushTX(mtx.toTX()); } job.refresh(); - assert.equal(await mineBlock(job), 'bad-blk-length'); + assert.strictEqual(await mineBlock(job), 'bad-blk-length'); }); it('should mine a big block', async () => { - let start = chain.height - 2000; - let end = chain.height - 200; - let job = await cpu.createJob(); - let mtx = new MTX(); - let i, j, block, cb; + const start = chain.height - 2000; + const end = chain.height - 200; + const job = await cpu.createJob(); - for (i = start; i <= end; i++) { - block = await chain.db.getBlock(i); - cb = block.txs[0]; + for (let i = start; i <= end; i++) { + const block = await chain.db.getBlock(i); + const cb = block.txs[0]; - mtx = new MTX(); + const mtx = new MTX(); mtx.addTX(cb, 0); - for (j = 0; j < 15; j++) - mtx.addOutput(wwallet.getAddress(), 1); + for (let j = 0; j < 15; j++) + mtx.addOutput(witWallet.getAddress(), 1); - wwallet.sign(mtx); + witWallet.sign(mtx); job.pushTX(mtx.toTX()); } job.refresh(); - assert.equal(await mineBlock(job), 'OK'); + assert.strictEqual(await mineBlock(job), 'OK'); }); it('should fail to connect bad versions', async () => { - let i, job; - - for (i = 0; i <= 3; i++) { - job = await cpu.createJob(); + for (let i = 0; i <= 3; i++) { + const job = await cpu.createJob(); job.attempt.version = i; - assert.equal(await mineBlock(job), 'bad-version'); + assert.strictEqual(await mineBlock(job), 'bad-version'); } }); it('should fail to connect bad amount', async () => { - let job = await cpu.createJob(); + const job = await cpu.createJob(); job.attempt.fees += 1; job.refresh(); - assert.equal(await mineBlock(job), 'bad-cb-amount'); + assert.strictEqual(await mineBlock(job), 'bad-cb-amount'); }); it('should fail to connect premature cb spend', async () => { - let job = await cpu.createJob(); - let block = await chain.db.getBlock(chain.height - 98); - let cb = block.txs[0]; - let mtx = new MTX(); + const job = await cpu.createJob(); + const block = await chain.db.getBlock(chain.height - 98); + const cb = block.txs[0]; + const mtx = new MTX(); mtx.addTX(cb, 0); - mtx.addOutput(wwallet.getAddress(), 1); + mtx.addOutput(witWallet.getAddress(), 1); - wwallet.sign(mtx); + witWallet.sign(mtx); job.addTX(mtx.toTX(), mtx.view); job.refresh(); - assert.equal(await mineBlock(job), + assert.strictEqual(await mineBlock(job), 'bad-txns-premature-spend-of-coinbase'); }); it('should fail to connect vout belowout', async () => { - let job = await cpu.createJob(); - let block = await chain.db.getBlock(chain.height - 99); - let cb = block.txs[0]; - let mtx = new MTX(); + const job = await cpu.createJob(); + const block = await chain.db.getBlock(chain.height - 99); + const cb = block.txs[0]; + const mtx = new MTX(); mtx.addTX(cb, 0); - mtx.addOutput(wwallet.getAddress(), 1e8); + mtx.addOutput(witWallet.getAddress(), 1e8); - wwallet.sign(mtx); + witWallet.sign(mtx); job.pushTX(mtx.toTX()); job.refresh(); - assert.equal(await mineBlock(job), + assert.strictEqual(await mineBlock(job), 'bad-txns-in-belowout'); }); it('should fail to connect outtotal toolarge', async () => { - let job = await cpu.createJob(); - let block = await chain.db.getBlock(chain.height - 99); - let cb = block.txs[0]; - let mtx = new MTX(); + const job = await cpu.createJob(); + const block = await chain.db.getBlock(chain.height - 99); + const cb = block.txs[0]; + const mtx = new MTX(); mtx.addTX(cb, 0); - mtx.addOutput(wwallet.getAddress(), Math.floor(consensus.MAX_MONEY / 2)); - mtx.addOutput(wwallet.getAddress(), Math.floor(consensus.MAX_MONEY / 2)); - mtx.addOutput(wwallet.getAddress(), Math.floor(consensus.MAX_MONEY / 2)); - wwallet.sign(mtx); + const value = Math.floor(consensus.MAX_MONEY / 2); + + mtx.addOutput(witWallet.getAddress(), value); + mtx.addOutput(witWallet.getAddress(), value); + mtx.addOutput(witWallet.getAddress(), value); + + witWallet.sign(mtx); job.pushTX(mtx.toTX()); job.refresh(); - assert.equal(await mineBlock(job), + assert.strictEqual(await mineBlock(job), 'bad-txns-txouttotal-toolarge'); }); it('should mine 111 multisig blocks', async () => { - let flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; - let i, j, script, cb, output, val, block; + const flags = common.flags.DEFAULT_FLAGS & ~common.flags.VERIFY_POW; - script = new Script(); - script.push(new BN(20)); + const redeem = new Script(); + redeem.pushInt(20); - for (i = 0; i < 20; i++) - script.push(encoding.ZERO_KEY); + for (let i = 0; i < 20; i++) + redeem.pushData(encoding.ZERO_KEY); - script.push(new BN(20)); - script.push(opcodes.OP_CHECKMULTISIG); - script.compile(); + redeem.pushInt(20); + redeem.pushOp(opcodes.OP_CHECKMULTISIG); - script = Script.fromScripthash(script.hash160()); + redeem.compile(); - for (i = 0; i < 111; i++) { - block = await cpu.mineBlock(); - cb = block.txs[0]; - val = cb.outputs[0].value; + const script = Script.fromScripthash(redeem.hash160()); + + for (let i = 0; i < 111; i++) { + const block = await cpu.mineBlock(); + const cb = block.txs[0]; + const val = cb.outputs[0].value; cb.outputs[0].value = 0; - for (j = 0; j < Math.min(100, val); j++) { - output = new Output(); + for (let j = 0; j < Math.min(100, val); j++) { + const output = new Output(); output.script = script.clone(); output.value = 1; @@ -803,47 +818,48 @@ describe('Chain', function() { assert(await chain.add(block, flags)); } - assert.equal(chain.height, 2749); + assert.strictEqual(chain.height, 2749); }); it('should fail to connect too many sigops', async () => { - let start = chain.height - 110; - let end = chain.height - 100; - let job = await cpu.createJob(); - let i, j, mtx, script, block, cb; + const start = chain.height - 110; + const end = chain.height - 100; + const job = await cpu.createJob(); + + const script = new Script(); + + script.pushInt(20); - script = new Script(); - script.push(new BN(20)); + for (let i = 0; i < 20; i++) + script.pushData(encoding.ZERO_KEY); - for (i = 0; i < 20; i++) - script.push(encoding.ZERO_KEY); + script.pushInt(20); + script.pushOp(opcodes.OP_CHECKMULTISIG); - script.push(new BN(20)); - script.push(opcodes.OP_CHECKMULTISIG); script.compile(); - for (i = start; i <= end; i++) { - block = await chain.db.getBlock(i); - cb = block.txs[0]; + for (let i = start; i <= end; i++) { + const block = await chain.db.getBlock(i); + const cb = block.txs[0]; if (cb.outputs.length === 2) continue; - mtx = new MTX(); + const mtx = new MTX(); - for (j = 2; j < cb.outputs.length; j++) { + for (let j = 2; j < cb.outputs.length; j++) { mtx.addTX(cb, j); - mtx.inputs[j - 2].script = new Script([script.toRaw()]); + mtx.inputs[j - 2].script.fromItems([script.toRaw()]); } - mtx.addOutput(wwallet.getAddress(), 1); + mtx.addOutput(witWallet.getAddress(), 1); job.pushTX(mtx.toTX()); } job.refresh(); - assert.equal(await mineBlock(job), 'bad-blk-sigops'); + assert.strictEqual(await mineBlock(job), 'bad-blk-sigops'); }); it('should cleanup', async () => { diff --git a/test/coins-test.js b/test/coins-test.js index 81f4281de..5c545923a 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -1,125 +1,103 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const Output = require('../lib/primitives/output'); const Input = require('../lib/primitives/input'); const Outpoint = require('../lib/primitives/outpoint'); const CoinView = require('../lib/coins/coinview'); -const Coins = require('../lib/coins/coins'); +const CoinEntry = require('../lib/coins/coinentry'); const StaticWriter = require('../lib/utils/staticwriter'); const BufferReader = require('../lib/utils/reader'); -const parseTX = require('./util/common').parseTX; - -let data = parseTX('data/tx1.hex'); -let tx1 = data.tx; - -function collect(coins) { - let outputs = []; - let i; +const common = require('./util/common'); - for (i = 0; i < coins.outputs.length; i++) { - if (!coins.isUnspent(i)) - continue; - outputs.push(coins.getOutput(i)); - } - - return outputs; -} +const tx1 = common.readTX('tx1'); -function reserialize(coins) { - let raw = coins.toRaw(); - return Coins.fromRaw(raw); +function reserialize(coin) { + const raw = coin.toRaw(); + const entry = CoinEntry.fromRaw(raw); + entry.raw = null; + return CoinEntry.fromRaw(entry.toRaw()); } function deepCoinsEqual(a, b) { - assert(a.outputs.length > 0); - assert(b.outputs.length > 0); - assert.strictEqual(a.version, b.version); assert.strictEqual(a.height, b.height); assert.strictEqual(a.coinbase, b.coinbase); - assert.strictEqual(a.length(), b.length()); - assert.deepStrictEqual(collect(a), collect(b)); + assert.bufferEqual(a.raw, b.raw); } describe('Coins', function() { it('should instantiate coinview from tx', () => { - let hash = tx1.hash('hex'); - let view = new CoinView(); - let prevout = new Outpoint(hash, 0); - let input = Input.fromOutpoint(prevout); - let coins, entry, output; - - view.addTX(tx1, 1); + const [tx] = tx1.getTX(); + const hash = tx.hash('hex'); + const view = new CoinView(); + const prevout = new Outpoint(hash, 0); + const input = Input.fromOutpoint(prevout); - coins = view.get(hash); + view.addTX(tx, 1); - assert.equal(coins.version, 1); - assert.equal(coins.height, 1); - assert.equal(coins.coinbase, false); - assert.equal(coins.outputs.length, tx1.outputs.length); + const coins = view.get(hash); + assert.strictEqual(coins.outputs.size, tx.outputs.length); - entry = coins.get(0); + const entry = coins.get(0); assert(entry); - assert(!entry.spent); - assert.equal(entry.offset, 0); - assert.equal(entry.size, 0); - assert.equal(entry.raw, null); - assert(entry.output instanceof Output); - assert.equal(entry.spent, false); + assert.strictEqual(entry.version, 1); + assert.strictEqual(entry.height, 1); + assert.strictEqual(entry.coinbase, false); + assert.strictEqual(entry.raw, null); + assert.instanceOf(entry.output, Output); + assert.strictEqual(entry.spent, false); - output = view.getOutput(input); + const output = view.getOutputFor(input); assert(output); - deepCoinsEqual(coins, reserialize(coins)); + deepCoinsEqual(entry, reserialize(entry)); }); it('should spend an output', () => { - let hash = tx1.hash('hex'); - let view = new CoinView(); - let coins, entry, length; + const [tx] = tx1.getTX(); + const hash = tx.hash('hex'); + const view = new CoinView(); - view.addTX(tx1, 1); + view.addTX(tx, 1); - coins = view.get(hash); + const coins = view.get(hash); assert(coins); - length = coins.length(); - view.spendOutput(hash, 0); + const length = coins.outputs.size; - coins = view.get(hash); - assert(coins); + view.spendEntry(new Outpoint(hash, 0)); - entry = coins.get(0); + assert.strictEqual(view.get(hash), coins); + + const entry = coins.get(0); assert(entry); assert(entry.spent); - deepCoinsEqual(coins, reserialize(coins)); - assert.strictEqual(coins.length(), length); + deepCoinsEqual(entry, reserialize(entry)); + assert.strictEqual(coins.outputs.size, length); - assert.equal(view.undo.items.length, 1); + assert.strictEqual(view.undo.items.length, 1); }); it('should handle coin view', () => { - let view = new CoinView(); - let i, tx, size, bw, br; - let raw, res, prev, coins; - - for (i = 1; i < data.txs.length; i++) { - tx = data.txs[i]; - view.addTX(tx, 1); - } + const [tx, view] = tx1.getTX(); - size = view.getSize(tx1); - bw = new StaticWriter(size); - raw = view.toWriter(bw, tx1).render(); - br = new BufferReader(raw); - res = CoinView.fromReader(br, tx1); + const size = view.getSize(tx); + const bw = new StaticWriter(size); + const raw = view.toWriter(bw, tx).render(); + const br = new BufferReader(raw); + const res = CoinView.fromReader(br, tx); - prev = tx1.inputs[0].prevout; - coins = res.get(prev.hash); + const prev = tx.inputs[0].prevout; + const coins = res.get(prev.hash); - assert.deepStrictEqual(coins.get(0), reserialize(coins).get(0)); + assert.strictEqual(coins.outputs.size, 1); + assert.strictEqual(coins.get(0), null); + deepCoinsEqual(coins.get(1), reserialize(coins.get(1))); }); }); diff --git a/test/consensus-test.js b/test/consensus-test.js new file mode 100644 index 000000000..9cd15b37d --- /dev/null +++ b/test/consensus-test.js @@ -0,0 +1,67 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + +'use strict'; + +const assert = require('./util/assert'); +const consensus = require('../lib/protocol/consensus'); +const BN = require('../lib/crypto/bn'); + +describe('Consensus', function() { + it('should calculate reward properly', () => { + let height = 0; + let total = 0; + + for (;;) { + const reward = consensus.getReward(height, 210000); + assert(reward <= consensus.COIN * 50); + total += reward; + if (reward === 0) + break; + height++; + } + + assert.strictEqual(height, 6930000); + assert.strictEqual(total, 2099999997690000); + }); + + it('should verify proof-of-work', () => { + const bits = 0x1900896c; + + const hash = Buffer.from( + '672b3f1bb11a994267ea4171069ba0aa4448a840f38e8f340000000000000000', + 'hex' + ); + + assert(consensus.verifyPOW(hash, bits)); + }); + + it('should convert bits to target', () => { + const bits = 0x1900896c; + const target = consensus.fromCompact(bits); + const expected = new BN( + '0000000000000000896c00000000000000000000000000000000000000000000', + 'hex'); + + assert.strictEqual(target.toString('hex'), expected.toString('hex')); + }); + + it('should convert target to bits', () => { + const target = new BN( + '0000000000000000896c00000000000000000000000000000000000000000000', + 'hex'); + + const bits = consensus.toCompact(target); + const expected = 0x1900896c; + + assert.strictEqual(bits, expected); + }); + + it('should check version bit', () => { + assert(consensus.hasBit(0x20000001, 0)); + assert(!consensus.hasBit(0x20000000, 0)); + assert(!consensus.hasBit(0x10000001, 0)); + assert(consensus.hasBit(0x20000003, 1)); + assert(consensus.hasBit(0x20000003, 0)); + }); +}); diff --git a/test/data/block1087400-undo.raw b/test/data/block1087400-undo.raw new file mode 100644 index 000000000..fa0de1ec0 Binary files /dev/null and b/test/data/block1087400-undo.raw differ diff --git a/test/data/block300025-undo.raw b/test/data/block300025-undo.raw new file mode 100644 index 000000000..2df73c355 Binary files /dev/null and b/test/data/block300025-undo.raw differ diff --git a/test/data/block300025.json b/test/data/block300025.json deleted file mode 100644 index 75a4fde89..000000000 --- a/test/data/block300025.json +++ /dev/null @@ -1,38912 +0,0 @@ -{ - "type": "block", - "hash": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "height": 300025, - "version": 2, - "prevBlock": "00000000000000005cbe0d56fc3714fdea1b542b848c9d9da8fdbd11441d83d1", - "merkleRoot": "af193f375fc1aeede6d781c0a563c1a66b4f69723d558438ba80f45ad3c1be28", - "ts": 1399713634, - "bits": 419465580, - "nonce": 1186968784, - "totalTX": 0, - "txs": [ - { - "type": "tx", - "hash": "13055be6d6784afa78ed08454651e4c81a03f96297b32f71992ef07e462b97f3", - "witnessHash": "0000000000000000000000000000000000000000000000000000000000000000", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 0, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0000000000000000000000000000000000000000000000000000000000000000", - "index": 4294967295 - }, - "coin": null, - "script": "03f99304e4b883e5bda9e7a59ee4bb99e9b1bcfabe6d6d4b69d66115595589c94866351760e113942b7489eb31fb37dd6458a7f906dda0100000000000000083e9191b1ca000004d696e65642062792067616263", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2507773345, - "script": "76a914c825a1ecf2a6830c4401620c3a16f1995057c2ab88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a17cb56f386346017346398e9fe1b72a33e2a405fd1a8c826d3beb93e87521ef", - "witnessHash": "a17cb56f386346017346398e9fe1b72a33e2a405fd1a8c826d3beb93e87521ef", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 1, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "94708d4ac4532953baafcdc0aebc3ac50ffe72201585dae17f041b206da2eadc", - "index": 1 - }, - "coin": { - "version": 1, - "height": 269602, - "value": 474236104, - "script": "76a914dde8c137cbe849ffe184a29c93173d086908bafc88ac", - "coinbase": false, - "hash": "94708d4ac4532953baafcdc0aebc3ac50ffe72201585dae17f041b206da2eadc", - "index": 1 - }, - "script": "4830450221008d859c70f9e295de3f9d87d412e9ab7cef52313e8b8d29a66c8bce2dc80489fb02202a0a1ddea15200cddb5995d9b4e69ab5af1c12653a051bce444606deb40bd69f012102fab0756bc1428a54a9811f6e21eea5a399ee92954d1e438b691dbc361e6d3bcf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 17073588, - "script": "76a9144a58ac48115a26d8acc8941b7729f602db8d63d088ac" - }, - { - "value": 457152516, - "script": "76a914dde8c137cbe849ffe184a29c93173d086908bafc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cf9c554c6881a2672476a82c222ac09ffbf15806a7050d8e66bc0f197a2af86e", - "witnessHash": "cf9c554c6881a2672476a82c222ac09ffbf15806a7050d8e66bc0f197a2af86e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 2, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ce78809dc91fc2045460ca44ce2e4c5ce77775bc1f9bae21a201cc91fedb58fd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 273564, - "value": 4900000, - "script": "76a914c29b39493f94d8230ef1d5943e4a19b90dccd35c88ac", - "coinbase": false, - "hash": "ce78809dc91fc2045460ca44ce2e4c5ce77775bc1f9bae21a201cc91fedb58fd", - "index": 0 - }, - "script": "47304402200434b30d33028ed1e77c68015ec09978aff8ffd30fd63f9c6f66302aeaa2e9b302202f44d7e852f2d851a0524faa19ecaeae11e86705367a4c54e3329e84bdc4bb24012103918dd1e4c0ba1bb5c783dde27ba58646b120c055c9d6744684e56d86134df0ad", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3800000, - "script": "76a9142be2976a9b33febdbd907360ea34522bccd39e8188ac" - }, - { - "value": 1000000, - "script": "76a91403e74730a8235375802444c9e67772a5cae0e43388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "479a5e9cc43d1d4af90783de28f5448c315f62c966dbe37ebe6625f15fe59cf5", - "witnessHash": "479a5e9cc43d1d4af90783de28f5448c315f62c966dbe37ebe6625f15fe59cf5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 3, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4c87bc7a6f181b457005c7e66a85c349691ecfe616f4c1a9a5afa75d382df492", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299945, - "value": 362911992, - "script": "76a914a06c3bcd8b7d34101140c3b6226c44980aa5ac9888ac", - "coinbase": false, - "hash": "4c87bc7a6f181b457005c7e66a85c349691ecfe616f4c1a9a5afa75d382df492", - "index": 0 - }, - "script": "483045022100d7f7935d2559e3d62d60bc0ee6f8d06b248866912ab43a8fbb7837de2de40ef402203714065b9d0f77572eb4d52bdcd8a63bd9b19e0c43dcab22c1706e3ae5c73f9b01210260a68f5a3cc9bca17a043ad8b7c88d7101fb9412b57aac8708a2a14defd69f9b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 58380000, - "script": "76a914337bbf2414c5f62889d70689177dfc1a85a45ca488ac" - }, - { - "value": 304431992, - "script": "76a9142ace895a0e3b1bf093e73bbab15cf87de8a7b24888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "29b04bcefb7c6dfd7f33b38f7e4f2eaa5df022edb011ab935a5e7792857856db", - "witnessHash": "29b04bcefb7c6dfd7f33b38f7e4f2eaa5df022edb011ab935a5e7792857856db", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 4, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fba191bec53d0ac4cf542fb96c474256dc103407eca59e320c13a11bf1b59c94", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299861, - "value": 49051960, - "script": "76a914b526df90f2bb0c5830b469b8b8f96d25e127de5d88ac", - "coinbase": false, - "hash": "fba191bec53d0ac4cf542fb96c474256dc103407eca59e320c13a11bf1b59c94", - "index": 1 - }, - "script": "4730440220472399ab5260ea623ff8b6acf6072693afff58fc70455fe4f194e6d6e95b18720220646b7c02ddaa27dbe3eee11fe243d76d3e7890563c0d0fdda3380cb069fc7685014104a5ed97469860bbe8f05b9964dbc83bb17e5d14383a54fc4395e1e698d01011f6827632c50871df697d46faab766a267cd3b12a17244db5af311133953b440e31", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 19900000, - "script": "76a9142f3fcdd0d9f2f5203cacded82512902d58f656cf88ac" - }, - { - "value": 29051960, - "script": "76a914b526df90f2bb0c5830b469b8b8f96d25e127de5d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "84064bcb6588b5cb101940dda858cf081d5bda93c46aba86df237c6ef59367ff", - "witnessHash": "84064bcb6588b5cb101940dda858cf081d5bda93c46aba86df237c6ef59367ff", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 5, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7f7889d41778755cd8d009780d8c65e154fed4c5e57711d518e46bcc07209e30", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 49990000, - "script": "76a91406f1b66fa14429389cbffa656966993eab656f3788ac", - "coinbase": false, - "hash": "7f7889d41778755cd8d009780d8c65e154fed4c5e57711d518e46bcc07209e30", - "index": 1 - }, - "script": "4730440220099b55e2011ff4b68688346a994df9134364680d2584aca96bd456d085958e490220570e096e6a4f75f735e1dc89f6dc8dfa7737291435bc259e3fb8a0a25f04a56e01410403899f47637b223c8b9350381425639d7ac7c7431f7fce463e7c668520d5b306ff52d80ca6dea4e3e289355a7133183e0a3d6b484dc22213aa38bab05cf0f881", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 249950, - "script": "76a914e13898157be26174194169702552de162aa9919b88ac" - }, - { - "value": 49640050, - "script": "76a91419034a421bf9f6a14657f39c806944d3e197d1cf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9fee29567f0472b7148cba6e4b4670b81f57e0e52bbcc275239a40361f837708", - "witnessHash": "9fee29567f0472b7148cba6e4b4670b81f57e0e52bbcc275239a40361f837708", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 6, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "275803d3609105914f517d706bea09b0c0064998d181a38ef5b0787496a2fa65", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1080000, - "script": "76a91406f1b6703d3f56427bfcfd372f952d50d04b64bd88ac", - "coinbase": false, - "hash": "275803d3609105914f517d706bea09b0c0064998d181a38ef5b0787496a2fa65", - "index": 0 - }, - "script": "493046022100ea2cdaf34f447d59dabdcbe354b62e14f078124d87afec7743461eeb1b8c2421022100d0624ffde1edb5a056d8ce0ed60c7596cd3787f8f2bb93cc4b7bd6c7c1ac4cfe014104606bf18bd8b5994b1e37ce13e7eed33e8508234a40d8795cfa6fe1f875c7e7eea13d31dc6fc77d2cc02880a9848d1573005d246a7a215b6b1ef48f7296a9d0b3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5460, - "script": "76a9148b8050768153f806f459f11ea200954aa6f6c72388ac" - }, - { - "value": 974540, - "script": "76a914b4f5b5a9e5119d3f0327d4ff64a1b0a97fc423d988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1404ba05dd0b1f36de0251b1eafcb0ab91cba1a0934e8facf219962757419e50", - "witnessHash": "1404ba05dd0b1f36de0251b1eafcb0ab91cba1a0934e8facf219962757419e50", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 7, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "092a65ac32e4cad45056c6d7366f8bf4c20808bebdfe12b5cf12023824c33abf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1000000, - "script": "76a91406f1b6703d3f56427bfcfd372f952d50d04b64bd88ac", - "coinbase": false, - "hash": "092a65ac32e4cad45056c6d7366f8bf4c20808bebdfe12b5cf12023824c33abf", - "index": 0 - }, - "script": "473044022013bbb55586aaa76b122a0c54a2c47fabfe23db91e8ba5fa48f929573c338f617022055baf8a200566a1895cec5732c0e0156ee7a3df560f4dac6183daa7b4f90ac36014104606bf18bd8b5994b1e37ce13e7eed33e8508234a40d8795cfa6fe1f875c7e7eea13d31dc6fc77d2cc02880a9848d1573005d246a7a215b6b1ef48f7296a9d0b3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e14e35fafeb5ca7f22c73faccdc2e85c9683e31ceaca100b2b8d5fd10c5db961", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299801, - "value": 159100000, - "script": "76a9140d2c815e3aca96576569aa62d5fd06ad1116a5d788ac", - "coinbase": false, - "hash": "e14e35fafeb5ca7f22c73faccdc2e85c9683e31ceaca100b2b8d5fd10c5db961", - "index": 1 - }, - "script": "483045022100da9b95c20e8c784722c1bfbbbeaa90bd8263f14d32738cf325f43a80f28cc92e02207e263ddc819451de158520e71757ef649be96ab6ad5e60d666a53c96b3047a7a014104e9147ece1c26d3319f6b7b5dbad45ab33429f77668857b9b4f3c7422632d6794a826c8e89791c6a2efb7fc4f2e1b3428a10e470315ff096a547f2e3bf91703e6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1957000, - "script": "76a914192631d280209f63886c0c591d34af37c3597a8188ac" - }, - { - "value": 158043000, - "script": "76a9141d811176562c8291a1c481af63b9b0460f9539fe88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0e0a2581f96035681c02a2ac57afcbe20fe3ce0336f8e9e77af18d321932fecb", - "witnessHash": "0e0a2581f96035681c02a2ac57afcbe20fe3ce0336f8e9e77af18d321932fecb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 8, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a8d3a2d04c032d9c9619e2528c84f25e58f127bdb49f022982c728b58470d9e2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1900000, - "script": "76a91406f1b66ffe49df7fce684df16c62f59dc9adbd3f88ac", - "coinbase": false, - "hash": "a8d3a2d04c032d9c9619e2528c84f25e58f127bdb49f022982c728b58470d9e2", - "index": 0 - }, - "script": "48304502200c8b70406f261d4b921f242d4f017e563f5dc59fe0638120db7a71ee8a670b18022100ceacfbc0bebb58298203496379711efc6d4189b1c5da3cc2e49a76fecaab13aa0141048cc0b94178715f03ed3d0bceb368191d0fdd7fc16d806567f6f2c45aecafb8f53e5ef849564072189b9b4f8bfe1564da776567ba359cfb0c05e839bcf65371ab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2ccee8ab399ed6e7073a1fe42f156143eeaba424e8d14f0c359e58dbcc60c955", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4492540, - "script": "76a914231eaa596ef11e796966fd829350defd5c7edc0788ac", - "coinbase": false, - "hash": "2ccee8ab399ed6e7073a1fe42f156143eeaba424e8d14f0c359e58dbcc60c955", - "index": 1 - }, - "script": "4730440220065364c93b7f5682d5db502b7f7745f0484d75090ef95ed22ef905c52a5a15d702201073de556983a4fc0660bb10b33de47ad5aadd9d699905ce5f7c6e426e2ec5d2014104581c88854a7db0726977e7cdba582ff428f0402d51498b08a23d7a3cf206f21de6ca79baeaf5dc2d4bdabfa39299a0185a1a863f101661df2ad7a30dc23a5178", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3807311, - "script": "76a91426eda44de2416f71aa90079f4ef44dd6b849d31c88ac" - }, - { - "value": 2485229, - "script": "76a914220aff37d2665794bfc25db189633bf7042b650d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1bff350c4779d9d98f2e619f9bc5a227a18955c8f544420da436f8d3c02668d0", - "witnessHash": "1bff350c4779d9d98f2e619f9bc5a227a18955c8f544420da436f8d3c02668d0", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 9, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1b5077a90a0211682c8e43c45720c6efb8f40aeaf445af9d43a30551854c8cf5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 17183342135, - "script": "76a9142e40a49056c250698cfc847b84528e7b5df3ec9888ac", - "coinbase": false, - "hash": "1b5077a90a0211682c8e43c45720c6efb8f40aeaf445af9d43a30551854c8cf5", - "index": 0 - }, - "script": "47304402200612c1c764e89b9c98f551526e4a3eada6fee532cdc4d7e5f46772624f3bc60a0220625815975118d56e14c70fd61d0ef4109b9c33b824e6123c833296e985fb02830121036e975050aa6b1de92cb49c5867a98550947304b3024dd0563415e98bc08d8204", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10079600, - "script": "76a914bc71df046ed4fe884acb9641475ceb84e71c163d88ac" - }, - { - "value": 17173212535, - "script": "76a9148ce75a361a939e0f2de59dc0db71fd7c18b826fa88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2250515cf1406e226770e41da3fadd8fc43d21f5c24906df196cfea0bea6fe8c", - "witnessHash": "2250515cf1406e226770e41da3fadd8fc43d21f5c24906df196cfea0bea6fe8c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 10, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a8b99f2e5fd3c13f53d8aacaec2fa34e6015c7c01fdf0bd729e33383dadefc5a", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 12757259041, - "script": "76a914483d262a98a8a91b36f3d011c736a242bbafa4c788ac", - "coinbase": false, - "hash": "a8b99f2e5fd3c13f53d8aacaec2fa34e6015c7c01fdf0bd729e33383dadefc5a", - "index": 2 - }, - "script": "47304402204e0b50c84fd6c006cf4ac6d269277e50d21d89db488f767e3cbec163ffda4e0d0220643c369808490bc13b2afe67324436b3a8891cb86b01d760cf7c01e7b7ec35ee0121038eebe6d14a0b9aee04459bfc80012565cbb6e17b1c11bcbe39db038f30d061aa", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5900000, - "script": "76a9142d7038bb5e39660062912642066bc2be9f525f1488ac" - }, - { - "value": 12751309041, - "script": "76a914dfa500e463d9f1d3fa336b73f602f004920b2dc788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "46b706617b1f908013cb469bdaa66d0c5a8a39689700f940cea4247083730e86", - "witnessHash": "46b706617b1f908013cb469bdaa66d0c5a8a39689700f940cea4247083730e86", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 11, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cdefb11014da8548167f91a724658bdaf812a4b5111208b0a41d3f68124de06e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4223546278, - "script": "76a91485d286072dfb5fa0f78f1b448ecfa8f16fb34c9188ac", - "coinbase": false, - "hash": "cdefb11014da8548167f91a724658bdaf812a4b5111208b0a41d3f68124de06e", - "index": 1 - }, - "script": "483045022100b4c0c32a205227792e12c9cdfee1dc9bc874cecaa3de7e45d4c6600643f4c87f022075f5a8c249f693ee2ecc6e41a2c523be0befe46edfb6a689cd9d79e16776966b0121024fc94824a23f6414e94ad843e9cd08c1afcf6843f438bb7548f01ba06e7e31d0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 29528390, - "script": "76a914da4284634385ed758e056a341030b4f796ee2c2f88ac" - }, - { - "value": 4193967888, - "script": "76a9140e1dd3d35deac6896c762d10d30651096da4300488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f7f2b176e9be30cf8a627edd4c351b0cea2acd24ad3be57ef6b1d93b6bdec8fb", - "witnessHash": "f7f2b176e9be30cf8a627edd4c351b0cea2acd24ad3be57ef6b1d93b6bdec8fb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 12, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "339b36868debde9351f463776f19dff4c16340d8209beaf9c3c7154a84c902b6", - "index": 86 - }, - "coin": { - "version": 1, - "height": 299161, - "value": 1011499, - "script": "76a914cc3fa5df5dee431ad178a480982ef89a454630dc88ac", - "coinbase": false, - "hash": "339b36868debde9351f463776f19dff4c16340d8209beaf9c3c7154a84c902b6", - "index": 86 - }, - "script": "48304502204677281e2e2352fadd35dbbb356aa16cc7f6bc44928249be81024af3ced10205022100e1b475bf52198d845f12be6989091ea448c71459a4340e13648ec003da386a32012103e2211c99443dae7afb5314a5a7b9e782da72b2e7da5672dea2d76aaf490b78e6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 733266, - "script": "76a914655faeb69c88debf10001a5ce9617f1cceef619988ac" - }, - { - "value": 228233, - "script": "76a914f21e87e9134d3a84bca77be4362c833b21db972b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "162f6199f249402b7f366b166bacd93e57471a4105387cd754a75b3ad70f9b39", - "witnessHash": "162f6199f249402b7f366b166bacd93e57471a4105387cd754a75b3ad70f9b39", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 13, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2191533d9f23d1c249b78ff916656ae15bd070b2509fbb99f3494ae08dceed20", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2853132, - "script": "76a91443f0232d3da6ed55134ee98f5fa15152eac3cdc688ac", - "coinbase": false, - "hash": "2191533d9f23d1c249b78ff916656ae15bd070b2509fbb99f3494ae08dceed20", - "index": 0 - }, - "script": "483045022100b2c0aada17a5404becb98c91550a1d1f3f6f7e92bb0ba5da2e5fbdb3b4ebbcc0022041e0975e117d74002016c46fe140f1489f1bce1be4d8365df156e30b8d5b4b8c01210225699102c9788298358010295ac57be435676f8450119e100d54ba2e33e40e4b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1291516, - "script": "76a914f6763f7b5a7433d4a60ec83e4c7b799f5c6ac2c488ac" - }, - { - "value": 1511616, - "script": "76a914586a354302fadc7cedf5736044e365aee807ab8e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "78754544b29d89312f2d16b4789e8861a0b54d26a9248cf895fc9df06fc83fc2", - "witnessHash": "78754544b29d89312f2d16b4789e8861a0b54d26a9248cf895fc9df06fc83fc2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 14, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3ef0c02df99e5d29164e7c61ff5997eb274f032c7a7342d6e4fcb77cef4c7c64", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297127, - "value": 8104561, - "script": "76a914d9bd8833e2ffdee28db81bc5c1f38859e0eb1d9f88ac", - "coinbase": false, - "hash": "3ef0c02df99e5d29164e7c61ff5997eb274f032c7a7342d6e4fcb77cef4c7c64", - "index": 0 - }, - "script": "483045022100b30aa565ea4db27f970a31b0d4de60bf5089412ae47366e821194963d367900c022050879769b083947415d530425a0e4e1d7841ebf645c5a6130faf04ff21d046800121037e9a06833327e3109f96677dc9657e88f8eddaff55ecbec2a8a06373ce36f46a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d1a73ddb2897c0a0d31d6cdbc0016e54cf12392082adfe8629f62215d217ae13", - "index": 1 - }, - "coin": { - "version": 1, - "height": 296037, - "value": 79611, - "script": "76a9141269e127673afa811c4c74e37f6b61e4267b6d1d88ac", - "coinbase": false, - "hash": "d1a73ddb2897c0a0d31d6cdbc0016e54cf12392082adfe8629f62215d217ae13", - "index": 1 - }, - "script": "483045022100df066970e4a2fe47f789e9f5e6b2f65ace4cec4acd9ef8275ef10a865c7aa46d0220211456ad62c6113592cfeae2d4df07e8cbb2ab5106f8458fced89bc3cf7bcc6101210349d51b6a940dd1ea4a6b6e02ba2f1a709accf145be22335d0cc8d407e46adac0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8060000, - "script": "76a91454fcebb9be81c95d0aa7c462b824ede2dc96f76788ac" - }, - { - "value": 74172, - "script": "76a9141fda42096ee5ee39514eb594f0036c03e41da45a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0c53187e2958931ed8626280e7bd513d2b0cfa807794d2dfb7492d79f456f9a8", - "witnessHash": "0c53187e2958931ed8626280e7bd513d2b0cfa807794d2dfb7492d79f456f9a8", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 15, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b123b9ecafa9f8486c71ca2ffbd179bd8373c5fbd0d63f306c736823c6e02d4c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 110000, - "script": "76a914be23007ebb9232f84a3f8d4b0c16fbab0182550088ac", - "coinbase": false, - "hash": "b123b9ecafa9f8486c71ca2ffbd179bd8373c5fbd0d63f306c736823c6e02d4c", - "index": 0 - }, - "script": "48304502204f23a5e32dac0450be84f2b1e549f102db0232f620eed9e3035f17f41fb2326f022100b8d5fc53c91ed99fa362b51d9c468a03575c4d845d70058746b12c948713b925014104d532af2a5d6d7ef209bbb4688ee5f9a05047b8314a707ea0aad96807cee00f6f0e9a0de612c0371eb1d4500202ce5bf6be9c1591c3d10f2abe61442cab9ce5da", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 89303, - "script": "76a91488940fe182deda820cb5f005ac00e15bdd54d93488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a02c6999cd47a5e72590ef4a747addae150cff83f7cafdc82b33cf17b5c41cec", - "witnessHash": "a02c6999cd47a5e72590ef4a747addae150cff83f7cafdc82b33cf17b5c41cec", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 16, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "40cbefb7cfe3efb586ce1e5727928a6714d77939431d9d7a20c7bf7decdc3eda", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 8970000, - "script": "76a9147467eb3bc9313db512d600fb7c96144aed065daf88ac", - "coinbase": false, - "hash": "40cbefb7cfe3efb586ce1e5727928a6714d77939431d9d7a20c7bf7decdc3eda", - "index": 0 - }, - "script": "493046022100b4925bc53175b16eb85b18d1d6ec82f16b2ae6b1af18307e1cd8fbf508719dbf022100ac35a302e21594db7f671f87f7ac2817e17fbee09a276c959d64f1ded9be2354014104a2122d293732c6ef2d1cd2ece96d17a829e9c6f566c670397f5c56013f2003ebf9e8f62ebd259711942fbcf4b9907feb7997df80412f5e9951499cb90508fc5b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8950000, - "script": "76a914717de9108474c90051224d6a97a1db93cb569e6c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7881e5c8abe79dcb726a254cd0b48f09379f358959bc1012712c2e3783f68aad", - "witnessHash": "7881e5c8abe79dcb726a254cd0b48f09379f358959bc1012712c2e3783f68aad", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 17, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "59950bdd1030cacc43b935dd38a87e83be30ba3c06d385e0d539a2c8196de74f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 34307696, - "script": "76a9146cd663323023b2c5c7f7cacd48daf4a7715c234b88ac", - "coinbase": false, - "hash": "59950bdd1030cacc43b935dd38a87e83be30ba3c06d385e0d539a2c8196de74f", - "index": 0 - }, - "script": "483045022100c7e70dccd46520584f9ffbc3cf6be55b2309240c5ccfb040c7914dcdddcb7e5d022066b1ddb0e6ff094538c014d0719070671059a83a2265d2d349f5cde73aa66992012103b302a60a76a1dc01183473276ccf87081f185f57831577efffd57c103df32636", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4287696, - "script": "76a914de1aec15396a83b3d0bd9f4222332c08c356763988ac" - }, - { - "value": 30000000, - "script": "76a914ec6353d6f3672c899547551208e61223cb2dc20f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fd3ce309bc93ed54182334585fa67ee9c1777021dfc4aba4436b78918488b687", - "witnessHash": "fd3ce309bc93ed54182334585fa67ee9c1777021dfc4aba4436b78918488b687", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 18, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5cbeb4a3a829e1f232faed261d2dc2f3b7a9d6c328d2d050869e6d7c25952728", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298377, - "value": 2000000, - "script": "76a9140989211e013ab24d37385c14c51f0b530a44df4b88ac", - "coinbase": false, - "hash": "5cbeb4a3a829e1f232faed261d2dc2f3b7a9d6c328d2d050869e6d7c25952728", - "index": 1 - }, - "script": "493046022100e44ff7c1b538ff0c6b861a5548c1e097e9bcfc209277727e1fbfcd19b8f01609022100d355c5596ad3795f679ace155311e26ab121ab97f00c1dd1cb017959427abdce0121038dc2efe0aba9ed648aebebd8e5871ee293682dc73b806c980e414c573e061a4d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 500000, - "script": "76a9144504ca217fab53cdc7099674542e633fe3558b2888ac" - }, - { - "value": 1480000, - "script": "76a914914d4b6bb77813d860485979f85992421400f02288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "19e49ffabfee963615d48e58cf0dfe1e569ac0ed4553fea8621242edc7953ae4", - "witnessHash": "19e49ffabfee963615d48e58cf0dfe1e569ac0ed4553fea8621242edc7953ae4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 19, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ed68f131b916b100527bc41da70b56a4288fac0b83b9ba912d76578db827b067", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 16338963, - "script": "76a914386a579d20e1f6d698c38a3e290a3e9f28beccee88ac", - "coinbase": false, - "hash": "ed68f131b916b100527bc41da70b56a4288fac0b83b9ba912d76578db827b067", - "index": 0 - }, - "script": "47304402207a0118c3bca7fb5ed82a09c6c3c648e90d98268c8ad2f209128f8b664164983e0220360cd86ff755e4dd3633ea21b6cd39c74ac8de4053d2257900bfc374971ac2120141049304b2705c670bf1ecf08b96a2c58753b161a4129590a325c74f4d1388e75c75650e455ecbe58de9287a1bd862446e7b681c7dd3f8a0ea113d489bcc4afe631d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 14241234, - "script": "76a9140f1e96bbac248f62f7d1a7909bb541455b7f4bcb88ac" - }, - { - "value": 2077729, - "script": "76a9148b2f63aa2c6dda5f8e592ea18db887fe364485a588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "312143313cc80c122f23ca0dc8d74ebce16f4ab27ad3bd06b490c20c6a7ebc66", - "witnessHash": "312143313cc80c122f23ca0dc8d74ebce16f4ab27ad3bd06b490c20c6a7ebc66", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 20, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "61d7349b6dd675c602da753b3d8b71bd0b56b260853e37f58743b858b0c2ad38", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 12602359, - "script": "76a914846884f070bd8d236385411fd43f4375228dfa3888ac", - "coinbase": false, - "hash": "61d7349b6dd675c602da753b3d8b71bd0b56b260853e37f58743b858b0c2ad38", - "index": 0 - }, - "script": "47304402204c97ec2bfbd062c464c86ca95595f6e5073897649aa9cce61f209584000ca29b02202bc05aa3652a0fc9798b1f72901db9190421c9805a9e67e6df32bd0c1f88240601410450f530633f763eae2b84b831eed3b05439f32b0f4f8186e879b059cd151bfc6531e2c48ba06d4f731ab9f53202cf2ddbc4bedbf6b065d549600f9e66e71d068b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11296804, - "script": "76a9144d2fbb552b05af884a64f004b9677bb82becdab888ac" - }, - { - "value": 1285555, - "script": "76a914ec30aba01f6deb0e1161a6ae6137d0ed47d71ccf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "898a03be617f58a0fc8aef4c5415f9d4e20621850a0d0afd32be8a500f368de1", - "witnessHash": "898a03be617f58a0fc8aef4c5415f9d4e20621850a0d0afd32be8a500f368de1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 21, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "eb1e430212ed6eb93f46dab40ecff057a5d3b62322ec84fd53b9fc44ea5f407e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 7988142, - "script": "76a91483a3f14be3e4f50864405fdd9b4a495b9cd780f288ac", - "coinbase": false, - "hash": "eb1e430212ed6eb93f46dab40ecff057a5d3b62322ec84fd53b9fc44ea5f407e", - "index": 1 - }, - "script": "473044022018cdbc90abbe2bddd4a5a302bf4ba7661dd80f2b633f024e764411cdf83132d002206f83e5b766a293b6eac9cc2239061d5d7b65f000d6b5d63512ba26c387bda149014104e740c66fc8fdd2d3503f71e3b8b71132653647beef33093d8ae76016228204a0eeb892da1f974a6c9ea96fec3492322389fbf9eae6fba88ccbb42fcc00bb9756", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4968142, - "script": "76a91483a3f14be3e4f50864405fdd9b4a495b9cd780f288ac" - }, - { - "value": 3000000, - "script": "76a914a6511d422458ce969d6ff0358ba43b463ce98a9088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a9d865a4d8713e6eb332f7f4b20e2ddd8cb9458076f741199426b11d22d82870", - "witnessHash": "a9d865a4d8713e6eb332f7f4b20e2ddd8cb9458076f741199426b11d22d82870", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 22, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0e212d7eb1b6cb40d739050512dc5b383f1fe63e0eea573cdef0e491d5259468", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299734, - "value": 70000000, - "script": "76a914d9230ad8984691d6fe80de4d47d0a51008a6196d88ac", - "coinbase": false, - "hash": "0e212d7eb1b6cb40d739050512dc5b383f1fe63e0eea573cdef0e491d5259468", - "index": 0 - }, - "script": "483045022100914d6c498655ee5ef79bf66eacec5a59c6a6b749942b7a51e25658dbde2937b502202166af91fe76397799e19c5dc512900ab068d500531087fd5009664639d03ea2014104aec9474a7857a767cd0d42833c041179e97341198aaa7fcbf596297e59c88beaf561f71afb28530f5799684570866da0fb775671d3cbc5cc2502e2d3b5a123fc", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5000000, - "script": "76a914ad789c4c9a2995636f9c64349e863930649eb04088ac" - }, - { - "value": 64980000, - "script": "76a914d9230ad8984691d6fe80de4d47d0a51008a6196d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9ced854ec57b7e9507c49b80595788e7695a37bbe085d81c1a08b719014caa0c", - "witnessHash": "9ced854ec57b7e9507c49b80595788e7695a37bbe085d81c1a08b719014caa0c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 23, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ab4d6474ed7097e6ed4bbdc6dac3faf85c9233206126bfa618bf9ea7d62a43e5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 220946, - "script": "76a914e6cdb321870d70ab0786422c55d176267d0eefe888ac", - "coinbase": false, - "hash": "ab4d6474ed7097e6ed4bbdc6dac3faf85c9233206126bfa618bf9ea7d62a43e5", - "index": 0 - }, - "script": "48304502203479e1f194332ce5721dd30a979db8c15729077c6aacf75ccd6ad85d34ef14df022100ff2b7141a55c4730c2d5c858bc0123e380b91d423d6e634b60fc71655986178401210244182720a7597dac6fd41d64491d0dcbdb14a7f132c5c6105f2ad6f9abefd0a9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 210000, - "script": "76a91432a7df1cc1a6f3ff21737f0f66412e8d8cf27d8688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "32abb1debf3ba9c240feea7fcf0c32c9e4230be80da39276a91572f51b508cc1", - "witnessHash": "32abb1debf3ba9c240feea7fcf0c32c9e4230be80da39276a91572f51b508cc1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 24, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ce8a7e9746f1cb8de9bf07eb9600ea06b34b609ce531ed978a4d3c686b041e17", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 1040000, - "script": "76a914e698d96e924c3b6e675c836a11d64252fd74b54c88ac", - "coinbase": false, - "hash": "ce8a7e9746f1cb8de9bf07eb9600ea06b34b609ce531ed978a4d3c686b041e17", - "index": 1 - }, - "script": "47304402203e29eca46b7a6fb428a4387bb3710099aef28fb83158253ab45cd1277c0e5f3902202320903af0d897e04fb8bd11c73b08f7297463e5f468077d4b0cc572659fadba01210236aa63ac25f805833298877a2179b882a90e716a93448f524e63bd6cd60739b8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7b41c451c3fd8ebe93eb702aa5788d68091a675801da670f0c1683b09fa03b4e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297864, - "value": 30000000, - "script": "76a9141b6b91b30c409529e911b5b8f3d0c20443ff7c6388ac", - "coinbase": false, - "hash": "7b41c451c3fd8ebe93eb702aa5788d68091a675801da670f0c1683b09fa03b4e", - "index": 0 - }, - "script": "493046022100ed70f637f0b2cd98ed2be0f0d359cca6008979cafe00e8381fb3dc2b06be5b0d022100e52c56dd7d004622b20eed3b0688163881d19a5ef374ccbdf9ee4892fe3c9d14012102dd8cf552b8bc62abd6b573cd235cec4901c72ef039f364353780d55f537e0b31", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 30000000, - "script": "76a91405435e2798b3b66dec568f4b4651ce7350fc131788ac" - }, - { - "value": 1020000, - "script": "76a9143d1f652976555827a4ff644a3fbb7088bb917bfa88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8b85b8fb989f2ef49e8939a50a186f79b214bb5e8c278fa6e5efdce73ee38319", - "witnessHash": "8b85b8fb989f2ef49e8939a50a186f79b214bb5e8c278fa6e5efdce73ee38319", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 25, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bcbd8568a9608d46a2868e9b263765c669adf64a2f1fd395303c5333df9f80f6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 54980000, - "script": "76a914ecd012edd92652b4ae156b2f5934cd897d14bb9988ac", - "coinbase": false, - "hash": "bcbd8568a9608d46a2868e9b263765c669adf64a2f1fd395303c5333df9f80f6", - "index": 0 - }, - "script": "47304402201da25775ec6d838c8570f19a0e110795feef13abd99e02349ee87ceb9caadf280220140b2b47104ffcda46701703a27716f4c67e86b02d592e1f152241bad7ffee3d01210362278b77316cf811832a472c014d17beda342a07c8bf6f1e0ea23920e483ea5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 54970000, - "script": "76a914d37f779e26718f0deec1aef0b026918e3395073f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "878b62bc56344e7713e39ba5ceb739ada5bc0cfde9f74ef9966108783d31ee8d", - "witnessHash": "878b62bc56344e7713e39ba5ceb739ada5bc0cfde9f74ef9966108783d31ee8d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 26, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fa1050cee3943c2efef86c4f4a11c20f309476632c4f602eeaf7caa1ad6cafee", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299990, - "value": 2105923, - "script": "76a9143622cc09a893b6d258a8865d988db31b1161256b88ac", - "coinbase": false, - "hash": "fa1050cee3943c2efef86c4f4a11c20f309476632c4f602eeaf7caa1ad6cafee", - "index": 0 - }, - "script": "47304402200ee3e9bdb03cfd45bc4def490e72db394274174c06ec26829ca85c020d59938b02206bc62ba813d58bd7b980ed2c7fb123e8e2ffff855b1212f45f4d4165cefc1bc1012103edf1ffeda92c1698eb0370cb125947c3f7ecb9e3ab3fd0cd980f413b514c68c8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2095923, - "script": "76a914a98fb3420fa3dea2695b8a150d3dc9b94cd4104d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "20d8e77631d35238054c0e0f1dd6ed7f42edc0a578c50318affd211c0a5c335a", - "witnessHash": "20d8e77631d35238054c0e0f1dd6ed7f42edc0a578c50318affd211c0a5c335a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 27, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a5693df0d8f53d44eaa192cbaa8b25e93f1b0ee11eda9e410bb258a488de821f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 296204, - "value": 12100, - "script": "76a91482f69329052eed1f1e02c41639a3055be44da61d88ac", - "coinbase": false, - "hash": "a5693df0d8f53d44eaa192cbaa8b25e93f1b0ee11eda9e410bb258a488de821f", - "index": 0 - }, - "script": "47304402200d2e9bae0dba9e3f79ca6a500ec6d71a028112cd14758c7a118e30e70ca888d702200369798959456573ddb8d5c808e68a04da02cd784f0820866657fa4ef338c37901210236cf55773ccd9ee3de709dd0b130bc6e53466ff140870236f7c017248f840e54", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2100, - "script": "76a914f75b71d1b0df9aa8011c19daa2c9fe15b3d61c5788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0c9df6a2c82cca4ea85ac80e7e8efafa9b2adcbbec879ea4ac62e8a40afc771f", - "witnessHash": "0c9df6a2c82cca4ea85ac80e7e8efafa9b2adcbbec879ea4ac62e8a40afc771f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 28, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7d4d851dc0d83bdee3aa2ad35eebda16268f42357b9b5298ac96d1271bb8cb9b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 110000, - "script": "76a91444f93ee19597602385db41658264c577fc6cd54b88ac", - "coinbase": false, - "hash": "7d4d851dc0d83bdee3aa2ad35eebda16268f42357b9b5298ac96d1271bb8cb9b", - "index": 1 - }, - "script": "4730440220755a0f82ca89f0a51e4c4e23f8d3c4b475a5fb9fd08699b80ddb0200e473e39c02203e0170d37377fd7fad12836794263cfc2b2088366acc8455843558db5f487bd30121022c1720309b6a8e5e544ab1660e31ad9b8c415d3c6fb322bc4583591127daae6a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a914ac078397f0e4a10c0a57face4bcd4d072e5ee12e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9e382c8d2224011a08bf3fb12af895fabe9d204fc07388c7c250e9e0b586b103", - "witnessHash": "9e382c8d2224011a08bf3fb12af895fabe9d204fc07388c7c250e9e0b586b103", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 29, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b9922deadd2db7b8b22f7c131dce4ed97a572280bbbe956c6d54b30006a71166", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299981, - "value": 100000000, - "script": "76a914439b96e79889a41346b322713e0fe8241bcd139988ac", - "coinbase": false, - "hash": "b9922deadd2db7b8b22f7c131dce4ed97a572280bbbe956c6d54b30006a71166", - "index": 0 - }, - "script": "483045022100ece739218419b7e138bff7d666352b6681cfed264d52c85c6c229d2facbd0bd302203e90bd399c6bf045b546c90ed90e6ba1a4e7371b2570eb1d53d7ef2b2a30bb1f012102ffa61094c8ff6ebe824809ea9756701aecf25396a2e046beb63fe6178ce4164d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 99990000, - "script": "76a9142deae64f4a27a793a1aa33d3b16c442738f45eb588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8a9c0788c60344ec13f21eb7c6032119d7fef634735b919c1e905d9bac41c6aa", - "witnessHash": "8a9c0788c60344ec13f21eb7c6032119d7fef634735b919c1e905d9bac41c6aa", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 30, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 1543 - }, - "coin": { - "version": 1, - "height": 299989, - "value": 5900000, - "script": "76a914c8d37561b8f3840411b895b109b0734ab28e349888ac", - "coinbase": false, - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 1543 - }, - "script": "483045022100f33cc41513875c951fdcae1fb253d65c6948b7cc15181bedc0409f09b4665a6f022076baeea8a648a2d540bdf43b85df6ab0b73acabfa92024696ae2f36539792894012103d53a8e03079f42c38c4eca2e05540dfbbdf6fa23c057f5599cb4e273a79c33a5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5890000, - "script": "76a914d6c4ecd10aa488af64e01ca8327d155081b761ab88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f15f1388ee2aaba9d14d76fe47593ead43663d62e3b61f8f50ad9bc632bb07ed", - "witnessHash": "f15f1388ee2aaba9d14d76fe47593ead43663d62e3b61f8f50ad9bc632bb07ed", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 31, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a9da56e3a0e67368401c0781e44c137011c522a40cd27365a1be0bf1bd71b7c4", - "index": 144 - }, - "coin": { - "version": 1, - "height": 299957, - "value": 502689, - "script": "76a914e49d72cd0c408776ba248df40c3cd5db0e7d0f9a88ac", - "coinbase": false, - "hash": "a9da56e3a0e67368401c0781e44c137011c522a40cd27365a1be0bf1bd71b7c4", - "index": 144 - }, - "script": "483045022100b6930c2f0671e77477eaeafa542e2d92747cbed1eff65206b61fb9de329e5f9802207ac34aecbe7d5bd567beb741b6fea83102ac8902aa0e0a79f9eb320bd761745e0121021b5ca0e67023bb957359566318c96ab5a53bb13bf55b5c9431365be0f6d9a37f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 492689, - "script": "76a9149f3e7e15604ac6e87198b7c2799b2fb4148d258988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2d0d4bcc96d94413aa96404bcd1734b43333897390eae801c180a17682254f10", - "witnessHash": "2d0d4bcc96d94413aa96404bcd1734b43333897390eae801c180a17682254f10", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 32, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 241 - }, - "coin": { - "version": 1, - "height": 299989, - "value": 35890000, - "script": "76a914cb3b446b1696a5dfa17cc99c5156ed13575baba288ac", - "coinbase": false, - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 241 - }, - "script": "493046022100f51568175a1aa5b8e807ebe17c49bd3d2bfda977e543fe903359d9351fcb44c40221009bd96ebe68190dd298e5d2ce4dcd0b7178afa1a53c81f245006d4acb803fc10b0121034b0842ebf64b61222a49b62fe5e2640f40efe87252ac8c95879556c7190b1096", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 35880000, - "script": "76a914e174479a8e57ffc1b11f5174fe58cba41ea1683388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "70043fd4ad382558452a6b30a73ef229064eaedf591649ff20d7ef7e6c505bfd", - "witnessHash": "70043fd4ad382558452a6b30a73ef229064eaedf591649ff20d7ef7e6c505bfd", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 33, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4f4657352da128fd8483d01f87daa6b9171cd9d0869d39255998ea4fe1183ab1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297713, - "value": 384078079, - "script": "76a9149b4be8eb8f182d7108bf0014d951e7e2300f92cb88ac", - "coinbase": false, - "hash": "4f4657352da128fd8483d01f87daa6b9171cd9d0869d39255998ea4fe1183ab1", - "index": 1 - }, - "script": "483045022046aa933561130a311dd47d8ab9a98660254a19be31aef85a0bde1580710521e2022100bb77cf998f21ba43e509320925d6426e3639f61402d06d77aa86ab9bb98ca11101210367deaf78d1b381544375b436733e304c7dbecf4918266e3ff0087dae7ce3bf66", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3891000, - "script": "76a914d5270008c2b07123292c824ec07b64f736feaf0188ac" - }, - { - "value": 380175729, - "script": "76a91427c51158bd917760b34754818f1ad7ec4cdebd4388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c0c1520ea8d4836acbd874033b457505c4d0c1dc6fcb28068417eccdceaf7201", - "witnessHash": "c0c1520ea8d4836acbd874033b457505c4d0c1dc6fcb28068417eccdceaf7201", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 34, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dcec155fb496eb39dd9a5cde5171f70f1499ac23701acf67305e53687179d32c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297715, - "value": 338351610, - "script": "76a9142cd8e3493ad743b07ed581b207485f3ce9a5856088ac", - "coinbase": false, - "hash": "dcec155fb496eb39dd9a5cde5171f70f1499ac23701acf67305e53687179d32c", - "index": 1 - }, - "script": "48304502202410f7435c4b7990f07d10ad87af27c2b4408dbfc6ac2de9345dc2240981417c022100ad419c87cee3af06ccdeb4ee85797f692b864e6297fbea4dcbc98ede4f4a83fe01210380a34b27af54c18546678e8a08b95adc0e38bf8a799abc782fc9d3a4f6e250f0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 303000, - "script": "76a914f32423743e5c20b8d2440abdd8962b0dae57161c88ac" - }, - { - "value": 338037260, - "script": "76a914ad8a134e2afdc78a2c0aa7018ad63e771ceb66ce88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "19a97a7ea5104239dd739f86802942575d2bb2d8ee81b3c7b3aceb2d2e746f37", - "witnessHash": "19a97a7ea5104239dd739f86802942575d2bb2d8ee81b3c7b3aceb2d2e746f37", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 35, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "294f252b5f6e3bb31ec964bceb21eecfdd5676760eb57cc84e229157032dbc2c", - "index": 116 - }, - "coin": { - "version": 1, - "height": 297716, - "value": 359146, - "script": "76a9147c8421fe921f28abbe12a17116bde94b76d7247188ac", - "coinbase": false, - "hash": "294f252b5f6e3bb31ec964bceb21eecfdd5676760eb57cc84e229157032dbc2c", - "index": 116 - }, - "script": "493046022100c32817d23440c4d887c1f744abd052479d89ffe4ae087a23ef704f478048b3d5022100e757257cc2c3150ffbd067fc9fb30033ba9d6cf0bf65ba64c826c4e2ebfa8bb101210225ac297fcac7d470ca9b11e386dd9d0835a9acbfce7bab7254202d2467961085", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e5654631acd6af9fc28202709d5d89eeafad937562fc0c569c969260b8bef726", - "index": 10 - }, - "coin": { - "version": 1, - "height": 297717, - "value": 2081367, - "script": "76a91413f050981700ed649892a7bf237e7abefca3930988ac", - "coinbase": false, - "hash": "e5654631acd6af9fc28202709d5d89eeafad937562fc0c569c969260b8bef726", - "index": 10 - }, - "script": "483045022100b2947126b338ee1a9bbd72400b473f255d465ae9142e7114398398d7fcc76d0802201362bc23f3f4469de0d70b862aa0ba024bf823e5986adbe6073fddbfb101ff83012102121b30a9c0e774b45667a99ff129ca00c20da370a6b1fb7302da27c2f701ce99", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3292073dc0bb7405cee4f90cd28fe002dec64324cfe7162885f7264bec1ee252", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297717, - "value": 268265950, - "script": "76a91440d98daf8069ac1b4de3fa45b372ec20ec8d280988ac", - "coinbase": false, - "hash": "3292073dc0bb7405cee4f90cd28fe002dec64324cfe7162885f7264bec1ee252", - "index": 1 - }, - "script": "48304502203e2803b953c953b8a8c0065d365f38a1f2696dce7cd8fe154ad53e3f3c846c79022100c58011916121e72effbf878bd5680430d446ffbd6ba6c55a37d2911c6596317d012102bcb3f7aa4b8f0fe315689c1c17aaf386e9580a6adc6d2dca11ae0c37f42aa0e9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 62201000, - "script": "76a9143ded3e89087c0e67ed47c85d329bf4c73065338188ac" - }, - { - "value": 208479213, - "script": "76a914c408cfba1b84870b4cc11f8596e63271135fc76688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0fc3170c023676eeb77ef9ac453b26c5aee0a0fb249f2d6b247c7de439bf847e", - "witnessHash": "0fc3170c023676eeb77ef9ac453b26c5aee0a0fb249f2d6b247c7de439bf847e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 36, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5d4b14b4fcf26d281a62b2e13bc110fea7722b996e856803ab0f7724d42b3eab", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299905, - "value": 426813, - "script": "76a914b7fbdf3ddf121a1a60c2c43dee8af414960d648088ac", - "coinbase": false, - "hash": "5d4b14b4fcf26d281a62b2e13bc110fea7722b996e856803ab0f7724d42b3eab", - "index": 1 - }, - "script": "4730440220519eff177321aac952a354977a2ef0bb3fe48e8108f865b52b7a852b329480a802202f0a847d913757515f6533cad6602b039382a7353f8742231555ca8d1ca234780141041ec8bc6ceb79adfaf4a6c8de39a4ff0de1d3b49068e1c85bcce2d257430c91e5880998e8788b780fe88b0d7ffccb96c7fe6d1ea396fb0ace4337414eb0f376f2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6d85a7b662de50cea6ea39da98c51c4b3bf7b4bbb4c620c854987b3c4c8a1d31", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 77489, - "script": "76a914ddc0ac91815f5f5d842337aa43c0a6927ec6ea8788ac", - "coinbase": false, - "hash": "6d85a7b662de50cea6ea39da98c51c4b3bf7b4bbb4c620c854987b3c4c8a1d31", - "index": 1 - }, - "script": "4730440220255d3da36cf7d90c00cee7b0748fe2086c705a5b32a417160923c4486a508d3702202989bda47a5142eb86dd28a66a465a6ee12625a37369bf6498c5f867cb547c39014104b783ffcfef3588966bf06271a3155e0ee4bbc44dcf67f768c1012e5600e5c06fc538e76c25907972000034b275f191367e0fa1bf4ceb13b81ad6befa16e06563", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 426300, - "script": "76a9147d13586d6f7aed481ea74774121dd1ab50535a9c88ac" - }, - { - "value": 57489, - "script": "76a9141838727768579f8a35bebe6aa0ce2c3c02c03f8088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "73147be7f4277aa0fcdac127640897a19c699074de0d621d5ff5d4bb34c141e1", - "witnessHash": "73147be7f4277aa0fcdac127640897a19c699074de0d621d5ff5d4bb34c141e1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 37, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "553f2783e44db375b920b575a11fa927a50ec7472a66c7c76e3f05c78168fd7d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 400000000, - "script": "76a914787dd893b51b743439213f56b64285ac80b92a8d88ac", - "coinbase": false, - "hash": "553f2783e44db375b920b575a11fa927a50ec7472a66c7c76e3f05c78168fd7d", - "index": 1 - }, - "script": "4730440220407aff4a885c7bed8078b2806a17dcb1fa2bce3277e3e08daa562a59026711710220532f8e598151cd0fd9425541df468e58b87fc710cfadd19a2b1e17159e917e9b0141043461619c5ee2cd676b50a62661f87fbc4383da624309a438c680e83fd8636646717fc60b6efa59f5305936ccfb59001c7d3cb4a9fcc5660397c2f66398ae3014", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ee25f05b51a4928be707f0025f67c011fd2aafa21f029b56bb8b935e121a827c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117481, - "script": "76a91473a7dbcb8a205ecdeee1f4742db18765abcad3a188ac", - "coinbase": false, - "hash": "ee25f05b51a4928be707f0025f67c011fd2aafa21f029b56bb8b935e121a827c", - "index": 1 - }, - "script": "483045022035dad5cf6d70b9097f7c452946c01380c143938b482d7be2f5a8da068197f7fa022100b552dcd06f88124b909ec7801f5c06fc690c73c5e5c6717a115a7b1ed4c582d2014104a38d2c68ed1c069269a3e59c640b0f2214e99d0ed6c54f5e1388e44bf24fead0743a812f1045069b55424d65ea9465b78298975a9508af809487c5b82b09b444", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 400000000, - "script": "76a914cff207a539af9ee7f32bcb27091ecf7c1ce9b35688ac" - }, - { - "value": 97481, - "script": "76a91489638c427b4bd9583acc929f0cfb2e29cc8ba18e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4765e89f7d028206085da98cd352b64610b6c00ec4273dfcc3206244caee0928", - "witnessHash": "4765e89f7d028206085da98cd352b64610b6c00ec4273dfcc3206244caee0928", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 38, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d522cf3389f3bf870e06e8c5a0eb0b21c3f8228f60b761c1ebe10defa0fe1784", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 103402306, - "script": "76a9144ce233ff80184ad99b4062698dc3ef7f7e1449ec88ac", - "coinbase": false, - "hash": "d522cf3389f3bf870e06e8c5a0eb0b21c3f8228f60b761c1ebe10defa0fe1784", - "index": 3 - }, - "script": "4730440220060c95aea72ae5c10ea8b75d59da2fa56c4696eb2bd2c5ef59b6fa76a74d4c1b02201b90332e371e3407acf9eebb9ef2b9b22e91139cfb076062ff19accae79134290141048cccec22581f4cf1f1eda94011b19f3be524cb637eb1e2972452ec82c5d1e07a6995ea5c383b80fd69330910328a723f3b05dd674f549e43720ba7fea520583f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "692654a5e91888abd20bea2db828c20c96bf7e326c6553465a6349ef08408d94", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137454, - "script": "76a9148d45f0d1eb7d58baf376349ba5653885e085e8f788ac", - "coinbase": false, - "hash": "692654a5e91888abd20bea2db828c20c96bf7e326c6553465a6349ef08408d94", - "index": 1 - }, - "script": "483045022100dea21280e0f1e6c2ba7098994652cf8db97a8544dffaa4d5a7115818e849c1a502204622dd06db48703949c087e20abaa8fa3a7feabbd22400d88566d618f0cc1dbd014104045570c01721a2afa6b10df3cdfb8f71ff9ac3c66414ca58419062e7547b9054d739d2befcb13b5bce962daf19fb943cb4305227d2408c9ef1bed9647b9592d0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 103402306, - "script": "76a914b491b97929dc49f6356541022ba19303429fc86988ac" - }, - { - "value": 117454, - "script": "76a9144f1255c12a52ad3a2414710f684c7a6d2f9c915a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0456a2d502039be6a1f93985edc7b58f18f1a1f8ef9415c959835a0e7f23342d", - "witnessHash": "0456a2d502039be6a1f93985edc7b58f18f1a1f8ef9415c959835a0e7f23342d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 39, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dadac023400aae08b1f6b25fe428f6eed1ca3f5ca4f0f71b22fc716e774e880d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 89040000, - "script": "76a9144560eeb7b8187c468a16b3c28cd507439a02f40788ac", - "coinbase": false, - "hash": "dadac023400aae08b1f6b25fe428f6eed1ca3f5ca4f0f71b22fc716e774e880d", - "index": 1 - }, - "script": "48304502204227e68f23bc859898cd609f4b151aaab4b34ca5a82b76eb26c632c6452e3c5f022100d2611ccc385874ee81400d5b0efff4df6412dd5188efcedf5ff76946022fb679014104967d907b6b7c60235af9f44fe35da1bf3700ba81ed5b8576157905b388d80a1635aa0a8bf8bede8d2f1a9a4af3d932a0191d200ef0665de7f7537c184e093329", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "acc3c9b54f41ee19bea0310b832128f65774cb93b68bf4514b8edaf9b3f2a7d0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97479, - "script": "76a91447b62eb9630168677473bb127a476a814185eba188ac", - "coinbase": false, - "hash": "acc3c9b54f41ee19bea0310b832128f65774cb93b68bf4514b8edaf9b3f2a7d0", - "index": 1 - }, - "script": "47304402200a3c3943a0d341bb9ea4dfa607de31031ac9eac93d9dcc9ac1ccaa428a2b7d1402201dbf0a3cce82d92a299f19e4d0567dee43b770e41911bd30aee854407956963a0141045cf90480d9fa55d3e0e95ce7a758fa805471427a9729ebf5f91828ef75fce6bbd3df1f02e54e1977c14f54e4c22ad85e8dc8b0263ab904ae10e36457f92b8e5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 89040000, - "script": "76a9145b50d85985ee891cfd7b757243608bdcdb24dead88ac" - }, - { - "value": 77479, - "script": "76a91472f5ff7d8ff495067abd06c0746114104ee160e388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "66ce17375418c740e00a847cb9672565c7ed571a91570adc3cca865fa69a8628", - "witnessHash": "66ce17375418c740e00a847cb9672565c7ed571a91570adc3cca865fa69a8628", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 40, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "45e49db7534ecfd930230ce56f57cd6346048c7542e3baccf36cf85534fe8767", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 14470000, - "script": "76a914a03bf37626d5b5aa34fd8d4843f4fcce1e32d15788ac", - "coinbase": false, - "hash": "45e49db7534ecfd930230ce56f57cd6346048c7542e3baccf36cf85534fe8767", - "index": 0 - }, - "script": "483045022100b3e5d0a7295a727abfc408f922729495e1c350cc77f5e9880776adfdf2ce85f50220443a01fe75e594b65e44fc688a45f778729511eb9e75020e23b265507f20d84b014104b2791d8512b6a32a68c60e7c431b55804ce2958f873f51615c5edf0261a993bf2772a8e7ad9a6c3963b616e27f3183fbbcc03a8b901ca4dd870e459b2ea9f50b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1602e119999f6928321a90acec4552c92813e7d2d1ab49dc6681f2a56b58d4e0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 13225737, - "script": "76a914adb0b4a10308892943c203b139b0316e89bd2cde88ac", - "coinbase": false, - "hash": "1602e119999f6928321a90acec4552c92813e7d2d1ab49dc6681f2a56b58d4e0", - "index": 1 - }, - "script": "47304402206660f49bb99477527ffb499f734e16a1b59bc13b2f35bbda3659abdc7c1d649d022064eb4dd180bef63cccd8a7b7999e435332e9fa9a4a47b4a655e95cbd3a46e6f401410432b59bd7871a9cfcde76867c89594bf8aff495bb95379971261b0686e017ca16ee45344f97766b5129980726a8e52c6f338057901e2e4ea7c143b09e3e101d3f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8567144, - "script": "76a9144516f9005d5e550bafe7f29e8f4a6ac5b37844bc88ac" - }, - { - "value": 19108593, - "script": "76a91406d77b7096db1569e1e3d5040b5d51aced6ec69b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "33be3a17a31a3896016147de05754c37d6fd35f117d2288f41d7a7e26c10a9b2", - "witnessHash": "33be3a17a31a3896016147de05754c37d6fd35f117d2288f41d7a7e26c10a9b2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 41, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 64 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 11262622, - "script": "76a914cbefc2b62522c09598e6b547efb8445c6d0f791a88ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 64 - }, - "script": "47304402206d0ee1156a39a57736b54fb8d0f11a45fa421b3e172c457013abb505b9a30fbe02203823c746d6095213a0811c6bbe129d1db3c51082cf3973ed405ca49465a674c00141044246e23b1ebbf997f47bb0423f9861c8f73cbc9ba3bdae2a703665cc5d61f01481cc44b98c09eaeecca1341091dcfa3a321476e25010da72ae58724961543cb3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f241ede8900e4ec80f5295f5a27b4fa2ea9a680780c30631dc44d99c34e60a3f", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117489, - "script": "76a91430b24c376e58206d364de5fa2000a7882b1bda5e88ac", - "coinbase": false, - "hash": "f241ede8900e4ec80f5295f5a27b4fa2ea9a680780c30631dc44d99c34e60a3f", - "index": 2 - }, - "script": "48304502202b681e8c86118f066827772da8ba0d143d6747d57af19ed6813e1c2fd8132167022100fa276754eb6a2bfe11232dd24f5cf8f2ffb025f11b77e16ea497298a7fc87e9901410429a18d8566ef8f0e6ad1cef38c8b4941381becba4eb7178455a818d328e0fd91e174d737b1eb6a764ab38120378ade236d1c860d5378544cbf9db258df97001d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11262622, - "script": "76a914cf7fe58350ecf914cb87a7f387fa298588f05d3e88ac" - }, - { - "value": 97489, - "script": "76a91429d23417ae57d7130260217a3b3fb7a18e2b59c488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e9967f13b1cff431d16c079f8199571fd5d13addf196c2e98b003e38928042f9", - "witnessHash": "e9967f13b1cff431d16c079f8199571fd5d13addf196c2e98b003e38928042f9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 42, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "529278c1c294a946d9f497e9664267cd800186f06456d9386eda1f99adb53aee", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299885, - "value": 346218, - "script": "76a91426bc4688171da6766e6f601d13582d7904068ddb88ac", - "coinbase": false, - "hash": "529278c1c294a946d9f497e9664267cd800186f06456d9386eda1f99adb53aee", - "index": 1 - }, - "script": "483045022100d7e44c975e50fb65163fd138cfcd52ed257889b9b4577b8bd4c8b93d6cadc1720220059d81e272a0d1904d84e0f4050371f9e7ede17d04140ac5a4ce1c9fbb2f8b50014104c9d9c81250efc8424049d44debd6fa6a244688146db1bcc18ce6443407a0e6921f045199475f2c395f1a2e05c50885cf7f9e2b13af26d9428f421ed132c4725c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "036382f58fa68eeda9d74c323bcbab7dccb5639bbbb28ac405f7d6f372a14d98", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914c051195cce439b98d9aa25685f43a65c8595fb0288ac", - "coinbase": false, - "hash": "036382f58fa68eeda9d74c323bcbab7dccb5639bbbb28ac405f7d6f372a14d98", - "index": 2 - }, - "script": "483045022100dcf890f9a5426eab064cb48fdca5cd80cbd158bf0e95f88ab2b185a25eab74ae02206137fc68c3b07834924a7fdd5bb54bbd7b008619321940e616361db7b355590301410439c306539d5a602627fdb20f15b91f8b42850ad235f16d9f9b14ce507708ce6e86fa384ed04f2526b5ea8bf0355b7626e1cadf7613598d0ada29db59f64bb99c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 346185, - "script": "76a9141d04fb571ea5f1d612eecd776bb3cc76aa9d06bf88ac" - }, - { - "value": 117491, - "script": "76a914f2485c052c06fd3f4f74c74deeb8eff91f2266b488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1294791082ff3656ea47ffa1eb159e25941cd6adc8074ce9f8e02de99795a71d", - "witnessHash": "1294791082ff3656ea47ffa1eb159e25941cd6adc8074ce9f8e02de99795a71d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 43, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "508e37b638044fea76be537710cf392d42db50136f40bf8b6429f46fed540537", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 232000000, - "script": "76a9146fa68e0c2ad4c1965fb485e39b5b62627d68ac7588ac", - "coinbase": false, - "hash": "508e37b638044fea76be537710cf392d42db50136f40bf8b6429f46fed540537", - "index": 1 - }, - "script": "483045022100e7f2a6e7d960206482ce277c5408cad4fa9cf7064a879ebf432e67d49a76e2f802203ea9e0f46f18ad09fb72da5bac1dd2b18e43de3b52c3cccf503269bebc8cc47a0141048b234558d7ea7cffb374331962bcd6954b26d6a3c3cc38a5c901048b1d23732a2ad5d38be1156247052e2f99e7d394cf6f5a002ccad3dca883d7c73a44fb0f49", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4b9d13bec16f0498a8cfb3e5dda2ff94b71908e0724938e0910a0e2c9af52e8", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914b3cf5d092bc679f837bddb7ae90f61f798bd691988ac", - "coinbase": false, - "hash": "b4b9d13bec16f0498a8cfb3e5dda2ff94b71908e0724938e0910a0e2c9af52e8", - "index": 2 - }, - "script": "483045022100f2b3f1f026ae8387c96e96216cb6574bb4b6f7823e4cb28b4ea0cb0f744acf6002203f9242f4432892d70adb713f9309a40a18ad66d686e87c60da1503d33b3f2b2f014104743d0448e934dd7492cb138513b9ef7c722ea69cd5aaf220514ad2a08c623cf41108a57e7ad469328bc7addac4cc18066658f784e091cd2cef1a6851b6fd00dc", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 232000000, - "script": "76a914b9e48dc888dbf6a0a2f25ac9ba159b64e666e7d788ac" - }, - { - "value": 117491, - "script": "76a914a4a64a10bdbc43082fb42b370e98c39c3a53822188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4e1f0208ad9dc68ab3834bad92ee2f1d36599f5a9a3943006ed4e5c9df9515c7", - "witnessHash": "4e1f0208ad9dc68ab3834bad92ee2f1d36599f5a9a3943006ed4e5c9df9515c7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 44, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "187c16668eafa29375f8610ceafc20e12aa8880389fc7f243e6f56471df9c791", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 200000000, - "script": "76a914a64d6d84ce1bbf15b758bc0f109af6168eb004b388ac", - "coinbase": false, - "hash": "187c16668eafa29375f8610ceafc20e12aa8880389fc7f243e6f56471df9c791", - "index": 1 - }, - "script": "4830450221008041d5918ae87bde80fbfe12b968376f3360ed899a93efe01a7b8789e3ef08c502206bb6b73052f94f4572b5f121ac2b5089dee31ad6eae34bf0cabdc7a7db027378014104cb364378b66e304c552e84df57cf252dbf1ae6317aa10d913f4cdadb1f7615d479fb2b199558563383d1384ec90dd104d65ac11f10c816cff07767bc9c5eea30", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "93a6524730922e2f933fd3006b7da9197f9353c82315515184c2c99dd48ea770", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117491, - "script": "76a9143d1d1e26316d97dd0d4fbbbfaf5f1a4abf0800c688ac", - "coinbase": false, - "hash": "93a6524730922e2f933fd3006b7da9197f9353c82315515184c2c99dd48ea770", - "index": 1 - }, - "script": "483045022100a33afe7dfead40e50bccccd091550d969e9a963f2a9e44e4e5df63c6cefc95160220519ee35c32ad0549e133331d43c30bb743ee30165ccd7779c576dab9914b5cb10141046fd96ca7e4c27777deb10cd68d0a0c43fa7cb5c85c4cea2220c097ba3fe187a17da8d72e3d38487a30eac7740c726ce349498f2f0452d1871fbd24022c7386e4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 200000000, - "script": "76a91442f9ed007ebda079e44649ba85a337080343293388ac" - }, - { - "value": 97491, - "script": "76a914223e72ccf7fc911d94c0111f0ce5bdd601f8520888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "73984e5bf188c71f064d7a6c62ec11f27eadf1a24d41fbf4f3891a4d294a8a3f", - "witnessHash": "73984e5bf188c71f064d7a6c62ec11f27eadf1a24d41fbf4f3891a4d294a8a3f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 45, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 33726590, - "script": "76a9148ba464fc759f34d43457e193ff59a0f60990f64e88ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 13 - }, - "script": "49304602210087ae98cb373418fdef00e5b3212ba3dda9f14c8eb5f5696cf0f9f063d4745f4f0221008b584d311e1b5886ef40039f13c841e6c93a1ad061e6ec3da80df46ad513fd010141046bc5056486cbb5a051aefc45a05426d58e46768e0ca40e06b91ce6f6938e2a752c9a4131ea9bfc211b362b1bcd027d8358573553248b8ce4434e34c3807efc5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d7539b38047b1f3343977bf0ed1a1de1945c777ae5698559259f001023dccbc7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914714459dea170631a3d926f630141e4aeba131d3088ac", - "coinbase": false, - "hash": "d7539b38047b1f3343977bf0ed1a1de1945c777ae5698559259f001023dccbc7", - "index": 1 - }, - "script": "4730440220734233bfe2bb0362be8bfacdd57920c63e06e11d001284705afadf738feb180402204e0d2276196918f62f34c7f549078367af0c90afb6070faded4993c6bd8b55c201410489fb62544a7ad92ac293ea5d697c2412c77c3889d259c44da74090941457a89e217cb30c9145a2b1f588b51bf9f8fd6e8f1bb23a1daeb54bf4a1b9b303bab718", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 33726590, - "script": "76a914ec78abbe9f01be9e818c9274323f481ce285f78d88ac" - }, - { - "value": 117491, - "script": "76a9147b44655ed5be4e589cb21de517a2265e7133b0d888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f1e6575a154a2671cecf3f13d9adbd84407869848f7efc49a83ac4017db214c6", - "witnessHash": "f1e6575a154a2671cecf3f13d9adbd84407869848f7efc49a83ac4017db214c6", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 46, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 121 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 25118112, - "script": "76a914b78c41ac587ed520b3eb6c11a923cdd0e1e17d0988ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 121 - }, - "script": "4830450220602edcb21a9df0fc9b64d659fc5c764f94cbce8f678977f1edbe0738483d3ef2022100b3b0a39cdf050e6b44de949cdb21dfbd299ec57ddffdbf3a03225d6bb39318f3014104495c66ec300f9444740bb7f2fe785845a59bd535b0a21053b1c4e6f591a17d4a09a388f606f589bc41b35ca029e4a8a9a4e251c47a70b60b5332c9f5a6cc50d6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "404dc1a3add224a38afff092550d045a846d20d4c3bc7a89add799692e95db30", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77491, - "script": "76a91491d828b45ec0497ab900f30f42e3ddb88dcf73fb88ac", - "coinbase": false, - "hash": "404dc1a3add224a38afff092550d045a846d20d4c3bc7a89add799692e95db30", - "index": 2 - }, - "script": "483045022100ea2e30701e13a12c6ae359363980c21558796adc38d218c88d2ea6d00d7b547402201063813e74fe1873aab66d762f16143f77f2cf8da77e0c2ef4e753ebec200308014104e6ff57be8cdde73a09b607d8e97f47e1edb2ba4b93bc08e5d6072cca0884bd3860fa552d85d5130a432483a888abaf021d2638b64d1f73e67df6fe12e77a5e17", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 25118112, - "script": "76a914e3543f637a75de57cc02cbc382f9845065e65fc188ac" - }, - { - "value": 57491, - "script": "76a9147e58ba36e5ee9de935a44ca38cc1eac72780cbf788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3c63bf912d2ef5ff5135e4187dd6d4cb6d1dd372a87022165d28397c9b7e791d", - "witnessHash": "3c63bf912d2ef5ff5135e4187dd6d4cb6d1dd372a87022165d28397c9b7e791d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 47, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 112 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10146511, - "script": "76a9143a2b8d5a50a278ef1f43cc07f1885a9459d6c1d988ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 112 - }, - "script": "493046022100ebf303fa9fba915434688aae5e7614e4b644be47e8fa6e949d789c9d9ac49075022100a200a66545d9b5f3922bc896586d6a6dfb23a93b247f77b7b902939cecae9972014104abe2db9fe83b335d23b584eea097bf11577ec6b8f00cd7e3d4c33ed637d4b3a2ed00719bfb1f0e2c8cca394304fcbeab73b67cd3a38a7f41d32f2287526851f2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bca20a7412d448bf5f85acd88b270f87ff297d1cb3b0021be6d09cf3dfc19077", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 57479, - "script": "76a914e3f8e9786220015654edb1e8e7988c7f9600292188ac", - "coinbase": false, - "hash": "bca20a7412d448bf5f85acd88b270f87ff297d1cb3b0021be6d09cf3dfc19077", - "index": 1 - }, - "script": "473044022065ebb76922fb302b270493662f36054fc800ae0486da1e789809bb637103dd6802205f6061a8669a4b3bab7663f6274dd1d6e818d538545809e673f0798737d6c94d01410492d04d94877ef6ee6f7f9df3b75b16ad703a2f776bf1c90e1f293a4cdfd0cef1970a9a87e945eb6c74474dabad3906c999aa27e61c343bce0f3d9f8377f1a45d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10146511, - "script": "76a9142d62d086659652a9aefad3d0d986b27cd394813988ac" - }, - { - "value": 37479, - "script": "76a914d8d41b41c4ec763c773417bedc718613cb2667e788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "77593041faf065bdd974ced64ce6b435a488e58f2efa7d5dfcaf467ea6a4d041", - "witnessHash": "77593041faf065bdd974ced64ce6b435a488e58f2efa7d5dfcaf467ea6a4d041", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 48, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0fc3170c023676eeb77ef9ac453b26c5aee0a0fb249f2d6b247c7de439bf847e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 426300, - "script": "76a9147d13586d6f7aed481ea74774121dd1ab50535a9c88ac", - "coinbase": false, - "hash": "0fc3170c023676eeb77ef9ac453b26c5aee0a0fb249f2d6b247c7de439bf847e", - "index": 0 - }, - "script": "493046022100e816dbe71e4c397ea96c298471e62f16dff61f8ea973d0d81b47210ce96d0a91022100827d66f693791000c77c95b971f3700d6b9e4fb3294bbda8c06254cf58dc57e7014104f1ca2dd4375123b679f89deaddf740bc04ffd8a2dcacb5d6f3945f9bbb749d28545ae2506546bfeda3183b341383331f18b1bb02fc4b90a1783cc16a73c6bfd6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "aa67187e2e2037982281bdb24d3a3c566ce415ac8a343f1612db06521369f52c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137489, - "script": "76a91443e88e82000be8298bcb35a684e6ab8e38f4e32188ac", - "coinbase": false, - "hash": "aa67187e2e2037982281bdb24d3a3c566ce415ac8a343f1612db06521369f52c", - "index": 1 - }, - "script": "473044022003a5d1d74ea3448f8b42fd0d27c0e854b123c5fe275b84a9b328f92b63c2b914022079cbc8ed1a1c71c5fdb3a001a4801c5a085e006c0f8cab7235399c59669fc078014104442340725b2b462341f85e6c7c684007ec25d11894c7816328780a0b67974198d595b56d45e79d05be700e77d64383ab5d60cef277bb0c8a5e384b71ae602d95", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 426300, - "script": "76a914c8a1d35b64b6a3fa74b2ecaa1ff7f7f63c1fb48288ac" - }, - { - "value": 117489, - "script": "76a914a5dea3ce9f4421f5cd131080c3c6a4391cc9d79888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9b58787ddc94e5dbaafef3419e9ad1044b43d3ce52e26b8cb7229ce86c1d12ad", - "witnessHash": "9b58787ddc94e5dbaafef3419e9ad1044b43d3ce52e26b8cb7229ce86c1d12ad", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 49, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e3ec0f4a16866cf46c32e7d16a290d4aea76cf2498bdbec13eabaf672ce77b1a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297445, - "value": 10756, - "script": "76a9149f2ea73177c3abf5ff5e59405fddcb80cf9b6c5a88ac", - "coinbase": false, - "hash": "e3ec0f4a16866cf46c32e7d16a290d4aea76cf2498bdbec13eabaf672ce77b1a", - "index": 1 - }, - "script": "493046022100fe922b4649c4a144483c00ae0bf6d672d73dff793dd204abdc41ab1013b3b62a022100b32e997b943201821780ca4cebc0e8311f62526d990690827f87ac97b5f7de6f014104dfc9eee39815c8cdab77bb11a648eab14586b6a94218edf1cf4ee3d00d4c745e7588639bec0a2a63f8d3cbae0e18b3e8fdb866eef49179397e29d6aa71674e3e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fa43a736b4f4dc53588d47c62e2321f87e81d4c82daa02c30d49e77fe32db7b2", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77491, - "script": "76a914e4ad7c9ebffe25acc7b475953d8d7fe03b5d99f188ac", - "coinbase": false, - "hash": "fa43a736b4f4dc53588d47c62e2321f87e81d4c82daa02c30d49e77fe32db7b2", - "index": 2 - }, - "script": "4830450220040d6f7b421ebc66e12c6ed6c7f75ed61916992b1777f57274cdd180da9fe382022100a923b105ed9cf9dc4b05f5ceebd3c5c0c96f786d56ee979235784830af6e611f014104d2ba5dbc7fe2dac20104f5d7dfedaf32acfd4ee983e80f16b41ae17a5439338d8c0341343b96fa8a135b5304817e527a41fade4913f79db3663ccd47f406d1da", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10755, - "script": "76a91413a9638b2bc3da07180bb8be7a14567d46fc2f5b88ac" - }, - { - "value": 57491, - "script": "76a914dfc56300f409f74d12330a9d927728a8218793c588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2addec28dc17625879eaeb997b6b3ed9326b62a5a1e0d7c759ff35093f0f0e94", - "witnessHash": "2addec28dc17625879eaeb997b6b3ed9326b62a5a1e0d7c759ff35093f0f0e94", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 50, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6c9992b6640cb8124984d8d7f05deb389ad1a642c1ae9f73e7a6546f371f12a8", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 70124127, - "script": "76a9148a63b89a1e98d70163dd7bfeddfc7ddd922b1b8088ac", - "coinbase": false, - "hash": "6c9992b6640cb8124984d8d7f05deb389ad1a642c1ae9f73e7a6546f371f12a8", - "index": 1 - }, - "script": "493046022100ec2a4c3ed1ba43473b001b4abc3026a91ae11a0d617f1a59b7e0dc9a9771c0aa022100c002c0c1e0a3d42e646e26b6b76980a04215cd12d9f680b45f400462cb429705014104f6a4ea936fc3650f801fa38038b2accdbfe7f0dddeb094cc3e16f291b324d7a94213f395f1e919e7012b8cb1ca11a9deb2eac70d3748088d158b9387074dc91c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "be6749a1573a70313ea6649dd524757e97e1e6de7eee102411e5e2f2e2634bb6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117489, - "script": "76a914c5eadb044b8c02ed9fdacd012b38b440fc40268388ac", - "coinbase": false, - "hash": "be6749a1573a70313ea6649dd524757e97e1e6de7eee102411e5e2f2e2634bb6", - "index": 1 - }, - "script": "4830450220268ae9f2013c705bd330421270fe5429c36092d078d822926661d11ad1e2f7bc0221009778d811ebeb15cb59f9e037f59688e2e57515843f12d8afec15ca604f27990d0141049bc6289cc43ff94b965ab159adc7555a145127fcd7069773e6dc1bb7a4e027126cb9f6e2a3a4bb7086bfd46f9a7fae9af46f59853ef1078f1b2f83d4065268c2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 70124127, - "script": "76a91431d9533e6e8f5f325bf07f5fabab09bae90c535088ac" - }, - { - "value": 97489, - "script": "76a91433279f15dbb3270cc5034c3b323fccf0d7f5ab3688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c55a8e969adf6a2ac79b8454720be29cd3ee417a1da8038ec951da8cfcb8efaa", - "witnessHash": "c55a8e969adf6a2ac79b8454720be29cd3ee417a1da8038ec951da8cfcb8efaa", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 51, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e9967f13b1cff431d16c079f8199571fd5d13addf196c2e98b003e38928042f9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 346185, - "script": "76a9141d04fb571ea5f1d612eecd776bb3cc76aa9d06bf88ac", - "coinbase": false, - "hash": "e9967f13b1cff431d16c079f8199571fd5d13addf196c2e98b003e38928042f9", - "index": 0 - }, - "script": "483045022100cd8e8aff6b8e349302292be7ca845434961bf3ade81ee0fd6f53d9ae3700f4f002200d4836bb32266aa5a0ef45c71fc5415f0eb77a3b37cedb71770927c38599553f014104c42dbc1053e96a4f9cf202fdeaf7319715391989042f6e41352b5707f880ad9fb9ca64f965148a871c8d87feddf85a370bcf0e6eff36dffc6d50cc0b001bf0fa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6d5c6df7481906b61bc0528c473510374b1fad4cec3c03486a8f8a257e7b037b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914b0193895baeedefac49a277781e12e3f5887e11b88ac", - "coinbase": false, - "hash": "6d5c6df7481906b61bc0528c473510374b1fad4cec3c03486a8f8a257e7b037b", - "index": 1 - }, - "script": "493046022100c0efa33e53908bc166a16e3abe8f0d9bec2ef84632985bb33ddb8396257c03840221009755ac747cca0ad45785a38d3a767bd619876b70dd44de1f00be7a2c4b9e43b201410440cfde1d8e0c3a9fedc5272dd9f2951cba221a6d66ded38f5b87fc75a61a0fcb6d8367f1c1a17ba66e41d2d2032d2d7794b1671040fb932c96e57811f84062c9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 346185, - "script": "76a91435b81e880d3a016d5404edd5ba2dcf1e735934d288ac" - }, - { - "value": 117491, - "script": "76a9149f5ffb47c69466009172d952e15213cd6ffe09ee88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5d15cd4ba37ec7fd3b55d622343bb889bbeea9601931b8025483c4daef6743df", - "witnessHash": "5d15cd4ba37ec7fd3b55d622343bb889bbeea9601931b8025483c4daef6743df", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 52, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "aebf5e0bdc9b36469539b9586f802310fba8c621cd4e0c066f5792701253b976", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299650, - "value": 20000000, - "script": "76a91443ca2c1fce5f0874208642632e7e6c015053cfda88ac", - "coinbase": false, - "hash": "aebf5e0bdc9b36469539b9586f802310fba8c621cd4e0c066f5792701253b976", - "index": 1 - }, - "script": "483045022100965e623cdb176fd3c9821fd6a5fccab825165f3fe8da86ba1fdc8dc6d6a96eb302205f0bb30ee1a85a56f911cec1fef4944cb25d88b2113931ffc40dd64387bd907a014104962a5af289a5b70e7bf9e01c843702a26fe36d9a82b7f4bb07107e49c51803448488f6204f116a178303eb7f5233eae9621345259cc79bc99ee023619bc97720", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 19990000, - "script": "76a914b1c7f94615b1a972325d3e0fe0fbf3b62b997f2e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "614e9b36b639d1d4471eb041b835b42cc20b549880e4e302176b7e13bbd5899f", - "witnessHash": "614e9b36b639d1d4471eb041b835b42cc20b549880e4e302176b7e13bbd5899f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 53, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e24f431af8c053e9212bf98b7d22b100273cd0ca7e4f915d91820d862e07ce2c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299881, - "value": 5990000, - "script": "76a9145d1cfff68ca3ab21b56d13bba9aacb293baf94a188ac", - "coinbase": false, - "hash": "e24f431af8c053e9212bf98b7d22b100273cd0ca7e4f915d91820d862e07ce2c", - "index": 1 - }, - "script": "48304502210088b5cfc9e9e7a4dc2384801d4efbe1449f63e4ec81947f1c5efbcf3cc382be9402206165c2ef4416efd3f6e372c1d12923e02c38f724955dcd284573da020887707801410434497a8c7168b3c6fe62134a5f45f19c80f827558ae0746fd16b1f63071be724a26bb13146adadbe264be512a93e0ce3512021477f7cb99dc38b1c72d42ad7e4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5980000, - "script": "76a914b23da4f639bdd84ffe35ab9adb6af0d13355125a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "078e56ffe6ba3d15725f097dc25af8104e455ce161e91dfe1e6cfd57b901a17e", - "witnessHash": "078e56ffe6ba3d15725f097dc25af8104e455ce161e91dfe1e6cfd57b901a17e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 54, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "eb154bd5cd546954605bc468250d34b81d70efc1c228656a59826aecee0fe3f2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 489990000, - "script": "76a9149625cabe99bd6429620a04c0be55e8786fc8207988ac", - "coinbase": false, - "hash": "eb154bd5cd546954605bc468250d34b81d70efc1c228656a59826aecee0fe3f2", - "index": 0 - }, - "script": "483045022100b041775df0f46b7ed12742020b82347fce3fc428d9a6ebeb5c676b6efc6aa0c0022025edf1ebc6813884d497120d87bb01434e66b9902e529bc94e716a7e38909be201410427b89be01f4364405a43cc161e72decf8e0cc8138f5cda8fc47e3237841777f2f5620757071b81667514169f9e4965d9fc51cb68ad68343d1505596ae45db4e5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 489980000, - "script": "76a9146fe0399227a04acc813420e65b94d602bf8772da88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8d971b147f3c7bbd4d4fdd1b9f8f7fe8ab23925f09bef14d038f2100420f2d89", - "witnessHash": "8d971b147f3c7bbd4d4fdd1b9f8f7fe8ab23925f09bef14d038f2100420f2d89", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 55, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d1a156c5d8cadabf2d0fac9fff12c7d919a401ae54477ee8346694c1bec806b2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 34990000, - "script": "76a914a0ce926e819ddd3e64ddf1629f0ec6dc88a724d088ac", - "coinbase": false, - "hash": "d1a156c5d8cadabf2d0fac9fff12c7d919a401ae54477ee8346694c1bec806b2", - "index": 0 - }, - "script": "4830450220227727f5b7fcf73607a5fbccb4d25f5a64a6813f64493fb10920810da7b18ade022100d6f2229552f233266f9514c64ea8371d3fa3a446105f132616ec10d2c7b024ec0141040e2391382f9654cedd09a7f18db270729b3fe692b8ceea6fe69673d4706ae413ce4365a9aba23cfb9910d937de9101bbe41d441f594877680b3037d6db07c013", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 34980000, - "script": "76a914519e84489eb8bf6df05b669f0fb13526877682f488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8e037f68e3d915a3f7ad05359f4f9a03e6c069eac875414a6c9a7eec0a1cd383", - "witnessHash": "8e037f68e3d915a3f7ad05359f4f9a03e6c069eac875414a6c9a7eec0a1cd383", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 56, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c3745da12cb1735fb6eb67646011de07b9400d034b4dc8dd09bf2cb01ba7b77f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 11434147, - "script": "76a914b57b535acba60c09ab04b1efd0033f375da1eaa988ac", - "coinbase": false, - "hash": "c3745da12cb1735fb6eb67646011de07b9400d034b4dc8dd09bf2cb01ba7b77f", - "index": 0 - }, - "script": "483045022100af0539963f6ce43ccadd56ad304449001a944e5cf3690ef8a041d72fad8a1522022056b5d09e98ec744a9edef3ea5d54de9c2edec830ff72a0a61b411ebe0b2f9ea6014104eecd80b02bba2976262e84fc6f012d26437b3f89b9bd4b6561007f66ea1ea4d56e8af59f6f5e1d7ef9a620bfdfa1e2cdc83c76085a42a121da344c22fbdd0fe0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11424147, - "script": "76a914f660a280888d2738db5ddc0318494ff9d430b88188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6170432711a9324551f57fc837f13fb30556bf32e2c757124f0fabf38c6012f5", - "witnessHash": "6170432711a9324551f57fc837f13fb30556bf32e2c757124f0fabf38c6012f5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 57, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "132b274f2f68848bf437acf95a0d64a6324f191f2c4939907cc93c94d33268e6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6465208, - "script": "76a914335b44ad357ca91ee55fa236897f1c9e7ca79c0c88ac", - "coinbase": false, - "hash": "132b274f2f68848bf437acf95a0d64a6324f191f2c4939907cc93c94d33268e6", - "index": 1 - }, - "script": "48304502203e82bfa3bb8301726d18c8f8c99514b4043bd2951b4817445b5dc9771f724b1d022100ea69217b0350d97c148e17344d7778e221e1a44bef832633d76f36fc10b501c5014104b687f4ea628fc933139b8f4ea77fb6ddabbef6d6aa0c42475565101803629e897b5c5a016a80054909a9701a55b75156e4d64b78e58eeb21d24ba6445856ad7b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6455208, - "script": "76a9144759eae25ff79a1697fd0d87938a286261ff980a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "edafcf87716fe81a4399fb5e2be90f14b954c40cfc4392721ebc3fcea7c9c913", - "witnessHash": "edafcf87716fe81a4399fb5e2be90f14b954c40cfc4392721ebc3fcea7c9c913", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 58, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b43774d68b1143f0268759257960aae4e6c1ca9690884747de7808851252d493", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 500000, - "script": "76a9140946ba52b1e7a3b2e8e8baf0260b411e4377606788ac", - "coinbase": false, - "hash": "b43774d68b1143f0268759257960aae4e6c1ca9690884747de7808851252d493", - "index": 0 - }, - "script": "483045022042f7b8e620bf676e63ad56cd2c6eb3391c9d16ba823fe328305f0e0a08ad368d022100c91779661ea3af2567f2940bd370c62bfca0229d1ba8692f280d2210c37e69770141042a00a0aea192dba8a936534cff8d147f58e0e22f11ac8b8c6f95e0726b7464e1c2a6b63a884dbfd929b286dd3ad1fd4098be80e2ef69030519f3c57cc1e95e03", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 490000, - "script": "76a914d4c31a83d5841bac7c87e05a2c62b419529c984088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a662d5d92a5d127efc5c72866ce3a1064f6462837c4c1aa9c1c84c2c80d0dd1b", - "witnessHash": "a662d5d92a5d127efc5c72866ce3a1064f6462837c4c1aa9c1c84c2c80d0dd1b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 59, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "04c3e2a0d117e3680874119c4275fd1cb6916307172f632def667a1232df2b56", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299043, - "value": 410655000, - "script": "76a91438fc5a9ac96d66706f0da3e3827a140e59e170f388ac", - "coinbase": false, - "hash": "04c3e2a0d117e3680874119c4275fd1cb6916307172f632def667a1232df2b56", - "index": 0 - }, - "script": "47304402205629b05041777d2d80b0650da1b4cfe9a28052cf187ea98f11ec76c0fb5901f302204e5cac33fcbf3f410a830085d2a3cdb4c5a902506fee61010c3dcc6573ef476c012103e4e15e76dae6c5f5c99857d9a0020a6986c352ba219531ec9ff0d3ae5eeebd33", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 149000000, - "script": "76a914c4b65b5ae5492fb89cf2ef0af8272fc857ec255388ac" - }, - { - "value": 261645000, - "script": "76a9147fcb5b04101f759b1eedcd61a8f77df680c3515588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "609cf357a3b1f9a145ae443293deb29b40cb5e32fa4dc504d2922e96ffbca7a2", - "witnessHash": "609cf357a3b1f9a145ae443293deb29b40cb5e32fa4dc504d2922e96ffbca7a2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 60, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7b448ad5ff1b49728e1be18e0bf8386b37bcd8f9e2c188592c4f2ba639733d48", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299867, - "value": 2213971009, - "script": "76a914c8110dd797f6c7bf73f6b1f04ae845448ea99aec88ac", - "coinbase": false, - "hash": "7b448ad5ff1b49728e1be18e0bf8386b37bcd8f9e2c188592c4f2ba639733d48", - "index": 0 - }, - "script": "473044022001c10474a4bf3aaceee0639240b26c1f58eb714929cecffceae0e8421945ac4502202ed5d56518dc0a05a4221c607f03beaf3df465bd76dd57faf80ea796d360970c0121033d159d3e8999b9e9d21ba0a73a606c0075db4c04e6a3e9112aab0ee9fba03b3c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2200000000, - "script": "76a9145b585bda447f9729ab2669f7808ad30d9d70aef588ac" - }, - { - "value": 13961009, - "script": "76a914ec55801d75b67041df7f595be08442224b62546a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cbbdfd11a852f3d012e222cb970fa8b8171722610f276607936f60e922b5abcd", - "witnessHash": "cbbdfd11a852f3d012e222cb970fa8b8171722610f276607936f60e922b5abcd", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 61, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d6194a3a1a136ab791d584580c55368f92a7b1fdfbfa422e997c17c38d1e4766", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299855, - "value": 1818929063, - "script": "76a91489f26f4b7fde36104a4d9522d94defd5c1eb402f88ac", - "coinbase": false, - "hash": "d6194a3a1a136ab791d584580c55368f92a7b1fdfbfa422e997c17c38d1e4766", - "index": 1 - }, - "script": "473044022003235fe88d4cad873513c3a3cafe938ca5ffbb6baeb38c820878f54ea672bca60220525bad062c296cd2132c4dd8f18299a9666c594c49e72849bca22fc1b25e5f49012103aceef40403f3f80c9bedf7848ecbd3dcb47d2e9682f61a44f879a5a9c99d5f49", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1668919063, - "script": "76a9140a175753d29bb03a85e14d1b99806d3bffe1034a88ac" - }, - { - "value": 150000000, - "script": "76a914f1e06c765628b6ab850682adf4d15908a54bae3488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8f91fc29f5bfa3e931cc5725420fb69460a804666ddb880be1d67d0ad6c9f6c7", - "witnessHash": "8f91fc29f5bfa3e931cc5725420fb69460a804666ddb880be1d67d0ad6c9f6c7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 62, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e5a4ef6f62115597b4249223dd13a18e10ef2024fa2cc08aed9c6c349a8456d1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298458, - "value": 170555000, - "script": "76a91438fc5a9ac96d66706f0da3e3827a140e59e170f388ac", - "coinbase": false, - "hash": "e5a4ef6f62115597b4249223dd13a18e10ef2024fa2cc08aed9c6c349a8456d1", - "index": 1 - }, - "script": "473044022073e2efd6cbb450a8a8ac8acba9c5a49c1c31cb8c5cbb4cdbf9ad96fbacc3a5b302202c3334f1fb329a5f23ad60327204309d4b14ef7a9118e484653823eb1e7bbd95012103e4e15e76dae6c5f5c99857d9a0020a6986c352ba219531ec9ff0d3ae5eeebd33", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 154000000, - "script": "76a914c4b65b5ae5492fb89cf2ef0af8272fc857ec255388ac" - }, - { - "value": 16545000, - "script": "76a914e2eef2c68092878f6523bb22f06c46e932dcdd1388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "22bf81c758e476271e6400d8b8e4de5874ffb156c1a62655c19ac67c78bdcb95", - "witnessHash": "22bf81c758e476271e6400d8b8e4de5874ffb156c1a62655c19ac67c78bdcb95", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 63, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a37e0c28faf8b2988caa60d5447230d1cb6dad0ab395dddc77973c00b0d62cac", - "index": 0 - }, - "coin": { - "version": 1, - "height": 294115, - "value": 19890000, - "script": "76a914b8b6a98262d07132736d57dee38831c1459f318b88ac", - "coinbase": false, - "hash": "a37e0c28faf8b2988caa60d5447230d1cb6dad0ab395dddc77973c00b0d62cac", - "index": 0 - }, - "script": "47304402204e830d6a7f1d3c260f114565e02c16a5608462217a10346068ed0225c7c61c1f022000e11e3a1f0b61b94260f45723f5ea90cdb2dec5fe5266498dfeedc367825a850121038b0d1627927067ecf182134406aeeea40816e008bf2aef87ac0ae9b3818a3dfc", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4403278, - "script": "76a914cf0d997c04f8ffb3f4864849bcdf32eabb97715a88ac" - }, - { - "value": 15476722, - "script": "76a91472b41913fd448d68d9533e5faa8944418157dd6b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0767b259263fb62ff2361a56d08b07c7a62c4cb16db4682b51fb1e7194af24a6", - "witnessHash": "0767b259263fb62ff2361a56d08b07c7a62c4cb16db4682b51fb1e7194af24a6", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 64, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1a613140a44f0a6c6e9c8594e5b0979fae9615ae78f25531668a5734cd547e84", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299394, - "value": 13982800, - "script": "76a914a944b6c77ceddb636a8305c90d4f53c5423e217488ac", - "coinbase": false, - "hash": "1a613140a44f0a6c6e9c8594e5b0979fae9615ae78f25531668a5734cd547e84", - "index": 0 - }, - "script": "47304402202a68c26d67ecc8a1b81c3d285271c9a92be2d4d3d5d282a98f675be9d2ef351e0220742a66b083ccbe5af7a12cd0bba628514c2f4a1ea097aeb24e17244891a9a2a9012103d1ed92ff3929322c620beb1db0dc5b596028a583b5397202098587b9f8223bd8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1450000, - "script": "76a9141b98cfbdbb22a17e48f8a873396804b56c1bfdb188ac" - }, - { - "value": 12522800, - "script": "76a914a944b6c77ceddb636a8305c90d4f53c5423e217488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f700c4eff50b50731c0613989f70cff32b59e92df2c560fbb1f58bef83061b7e", - "witnessHash": "f700c4eff50b50731c0613989f70cff32b59e92df2c560fbb1f58bef83061b7e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 65, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dd38c33e990908f7fe4d1ea3b08a0750b1cd6becaa4fb367a4932f2a3f1e4e55", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299879, - "value": 52921295, - "script": "76a91444d927a021bc0ceff901bc70f5bb3e2ecfea468c88ac", - "coinbase": false, - "hash": "dd38c33e990908f7fe4d1ea3b08a0750b1cd6becaa4fb367a4932f2a3f1e4e55", - "index": 0 - }, - "script": "47304402206777497c64db4f4e5e205b8b234b750c2a7572d8b127f7d9bc99c8a0b178e43f02207e35b5388d2a58dfbdb9a7dbff74624757b94b75c830ee31fc7cf636064d85e201210283049b46570f7b1acced2a4025aa76c2625a8ae4e5b6f4d038eee6b98c8b174c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 29559056, - "script": "76a91462e70e18b5d700ad4e8ce59410a43f2f747a5d4288ac" - }, - { - "value": 23352239, - "script": "76a9145988e80fd7ac0be47a70dc34d33f9a6a761ffaed88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "629c67898e6cda2c32d3126389398adc030cedbab09b3f60a8611fea925e88c7", - "witnessHash": "629c67898e6cda2c32d3126389398adc030cedbab09b3f60a8611fea925e88c7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 66, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6f973c550cc7bc41e263aa196bb0c8e77838dd342944b37d1b26c5d0fc8b5a9e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 961716265, - "script": "76a914feb3fdd8671444e17f3207d90c54cad86be245d788ac", - "coinbase": false, - "hash": "6f973c550cc7bc41e263aa196bb0c8e77838dd342944b37d1b26c5d0fc8b5a9e", - "index": 1 - }, - "script": "473044022075c2f26b1e3e058333576324e6d1f83f5e7c1f97986a3f8326fe64350c5611c502203035dc36d278bf41f6481bb1727e183df05939d52148846a80cb83d778b0fab0012102c782d28542991f48f2178390445c5a684f84704b66cfd78855db9b1d3c28d58d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 26715000, - "script": "76a914bcdbeb79a75d6fce16fd828bc4dac8c36516143e88ac" - }, - { - "value": 934991265, - "script": "76a91414b2a59703e261eeaf68ad9c2bec8cd1486704cb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ce26a3427345db1d8655009a543a56ec7e28fa2ed363d73d626144918d671391", - "witnessHash": "ce26a3427345db1d8655009a543a56ec7e28fa2ed363d73d626144918d671391", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 67, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c2ef373a0c5fed784a7f48a4d70e8c85a2206737dea33c8a5e610094b20b867e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299882, - "value": 13158100, - "script": "76a914c940598b7b3a71a570a5bebeaf6a8be134476d2a88ac", - "coinbase": false, - "hash": "c2ef373a0c5fed784a7f48a4d70e8c85a2206737dea33c8a5e610094b20b867e", - "index": 1 - }, - "script": "47304402202ffefd08e8156ede0d359e987017e25061f77f0a8755fef70fbb7a776bf9bb0c02204c11992d48542a95c0dcb8351493c7af9b35e49496969260a0a1c96eaa8885bb01210381a088d3136dafb3eccf409f87141a33216628509a782fd1e0b82a9717d79127", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4576700, - "script": "76a91497521a236277cd19ac3d121452758cf5a7036bd488ac" - }, - { - "value": 8571400, - "script": "76a914c940598b7b3a71a570a5bebeaf6a8be134476d2a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cf5a5bfc6aac203f881918eca090e82ab1a6149660831f05a05d3c9f9ef2d386", - "witnessHash": "cf5a5bfc6aac203f881918eca090e82ab1a6149660831f05a05d3c9f9ef2d386", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 68, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d92537e171ca0d128554ba64d07fd2f7d48a5936e3d0939597d17f25664d2e72", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 56333994, - "script": "76a914a92e419d402f3152cff2a9a356048810e806b24988ac", - "coinbase": false, - "hash": "d92537e171ca0d128554ba64d07fd2f7d48a5936e3d0939597d17f25664d2e72", - "index": 0 - }, - "script": "473044022073624d9fe4934a3acd4a0bcf1db398b54efc661623847ff7bf4e645726a69280022021aad2854b2535ec270fdbf1e133506a531b6b2d2ef8de8026a86fccf52eb6420121027978ac01db2fbfe81fea0e627e7ed4d20d3e95f61e62dfc8047ba1eb4bd2e9bb", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 15003469, - "script": "76a914dd89c81e176a861ddbc456f36d53d9951c946bc488ac" - }, - { - "value": 41320525, - "script": "76a9146a03478c20390959f513be39dad893a1926d28e188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "205751ff10c189df5821aea53a1957a11d88a205ad3a6970fdfdde7289d49505", - "witnessHash": "205751ff10c189df5821aea53a1957a11d88a205ad3a6970fdfdde7289d49505", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 69, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "928869ae89572a3dc00a19f74f67c10762f8cfc0b06aa0e634ebd1784c4e35c4", - "index": 16 - }, - "coin": { - "version": 1, - "height": 299856, - "value": 5000000, - "script": "76a914dfba28dc856c9a949fb67a55b234adb957416dfe88ac", - "coinbase": false, - "hash": "928869ae89572a3dc00a19f74f67c10762f8cfc0b06aa0e634ebd1784c4e35c4", - "index": 16 - }, - "script": "47304402203c3214fb4004c195eb6abdd53b47aafca79ab0df3817b1e92980796a6de4df7c022024695cbaf5528c24a23f6b61a21ef64aadba502019f31f29e1bde5592bcfe3bd0121020d2ff52a029a282a5e641c061588a1f1461a1d5403b6e6972f16b6a10fb6830d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 500141, - "script": "76a914ec6218d53a9b1e133c3da3765f3a24cc7ad0393188ac" - }, - { - "value": 4489859, - "script": "76a914dfba28dc856c9a949fb67a55b234adb957416dfe88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4b48bb45bce87a6bd989cf8f7e9a96ff41da755b4c618209a3a2ef8fd4fc23c5", - "witnessHash": "4b48bb45bce87a6bd989cf8f7e9a96ff41da755b4c618209a3a2ef8fd4fc23c5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 70, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "86b68604a2067c749dfbdd8e9ec2da0edc8c606e700b6949b3d1abe783b168a1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 342903700, - "script": "76a914f33a8b320d03431748e5bc1f9433e5efbb1b0cec88ac", - "coinbase": false, - "hash": "86b68604a2067c749dfbdd8e9ec2da0edc8c606e700b6949b3d1abe783b168a1", - "index": 0 - }, - "script": "473044022054fdbfaeef2cafdf405cb26e3f178e979637304285c9c4980b25d6affd6229ec022019d9e62a074f1dfc577667ebe4121aa3f3969127e693bd01b671ed7f7a944dc00121023830cb5eea0581d1a2ea7dd5f37ed7a437d843b86bc533c2c15dda5274440fd3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 980000, - "script": "76a91479b35f1da74c1b9b4736dc6fd45cc2808bdc952388ac" - }, - { - "value": 341913700, - "script": "76a9149d09cdcf5fe32918959617d7a8b521f1986bf35f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e129bc5e48001deb054a16f633ded73ed0053df932215ffa40b1aa97ff1e477a", - "witnessHash": "e129bc5e48001deb054a16f633ded73ed0053df932215ffa40b1aa97ff1e477a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 71, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2a34587944e2adc6ae2ee45a6f8dd7ddbe90836436988d8fd973a39e614b9748", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300008, - "value": 38000000, - "script": "76a914425caa88f502d34d1afc93508713a5d4d9d793aa88ac", - "coinbase": false, - "hash": "2a34587944e2adc6ae2ee45a6f8dd7ddbe90836436988d8fd973a39e614b9748", - "index": 1 - }, - "script": "47304402201e79e1299ab89a7718d2446e859b861d13769404254b58eabfab579cdf49d7fe022022b5e719f9548c6a0a92a45059da254ccd156bb75c5d3aa68e34ecacdcb6acea0121036bf18252cefb261bcf59b363697cd90c46dd69e9d5d7522a1c58b760cd4e4cac", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 19000000, - "script": "76a91493e7401ccedccda6b06c4b51eafa4ee600d63da688ac" - }, - { - "value": 18990000, - "script": "76a914425caa88f502d34d1afc93508713a5d4d9d793aa88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1024430301c78c3b844b80c6b44e24b8b6efa41d4a4b1d203aa889ad5c1489fb", - "witnessHash": "1024430301c78c3b844b80c6b44e24b8b6efa41d4a4b1d203aa889ad5c1489fb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 72, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "92f115064be912be1e89d0bcda6d8d0320710fd696b92281a268763a2c63a9ec", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300003, - "value": 28677000, - "script": "76a9146e53bf9b4ce2da2a825ec35b733344f8a84bd53588ac", - "coinbase": false, - "hash": "92f115064be912be1e89d0bcda6d8d0320710fd696b92281a268763a2c63a9ec", - "index": 0 - }, - "script": "473044022057b183511122e564d6ce5814c2de819603deb53f64e7200c7a4e9bae9b7eff17022026f9e9d93b3c620cca5a1fd0f94df631d14e5a5910424e802e051e08b7cce8ae012103d6a329d6f4b17d575c7c1877537aefd3e2101ad16494042fdc5d5c6fc6e0a9b1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7977000, - "script": "76a91435ea01906975d6490ffd15f7abf19ccef86a421c88ac" - }, - { - "value": 20690000, - "script": "76a914087a1e8e97612bbe660ab6abbb5cd533c77e40df88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5f6ee4bb9613ed091f5af458291d5776106d314a48c1ac45fc9a6fbb31dc7b5d", - "witnessHash": "5f6ee4bb9613ed091f5af458291d5776106d314a48c1ac45fc9a6fbb31dc7b5d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 73, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8401f78c4a02bd65a8a83efac15fa07c1b68e3560700c7be0310b330c5b0135a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299901, - "value": 5054175, - "script": "76a91440eea1ecacfb2598aa089e1cfe738ae4502f5bb688ac", - "coinbase": false, - "hash": "8401f78c4a02bd65a8a83efac15fa07c1b68e3560700c7be0310b330c5b0135a", - "index": 1 - }, - "script": "47304402207574f6a292f72a3b7d102e49e71830218edb764293fd7d82a4c771abad9f735c02207f7f351e763fc3511a17f70adb96a2bcfbceb3d576d69018d7db09a36da33505012103c9991c62e6c3f383efdbf6b240c0906d2a4d0e7b5e38166bfd27344ab13b4558", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 225000, - "script": "76a91411c2fbf79e10e5d643e52647a763090ed5e7fc9688ac" - }, - { - "value": 4819175, - "script": "76a9144ea7f3876b0a8bc66001f32e3e3df3bc5dab6b9d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b8fd984ec0297fa2a90228056c52dd8a214e81ee839c50e0fe41e82cdf26c685", - "witnessHash": "b8fd984ec0297fa2a90228056c52dd8a214e81ee839c50e0fe41e82cdf26c685", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 74, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "90bcb36eb03399850a1c8002b28c0d3c101267b918d5b7da2aa7aa6336c9057a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 608165104, - "script": "76a914153b8bfd098edd5ca4e7150b78eb6444de0f270d88ac", - "coinbase": false, - "hash": "90bcb36eb03399850a1c8002b28c0d3c101267b918d5b7da2aa7aa6336c9057a", - "index": 1 - }, - "script": "473044022047d3ae3483c8c9377378b25c0a9b35b1877284263d3e58f70677a01c37922ffd0220570e443a74d703b49bed7928638116209c1d0c4bdc19a3df5fa5bc1926d1665a0121038115524ba52d3044ff4b6c188033ffff069a2ad75608d78f7e5fe3691bb15b3c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 152730000, - "script": "76a914c6615ebc7cf067d14581b70a4c3449e9d424c2c488ac" - }, - { - "value": 455425104, - "script": "76a91433fc482aad43bf51f13c10ad82507908ebb0466f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "376a743d26ab09424021c56228b8c7a5d7948dd8a2dcece68f4657bd59aed960", - "witnessHash": "376a743d26ab09424021c56228b8c7a5d7948dd8a2dcece68f4657bd59aed960", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 75, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9f449c52d16bb422defa06c7b4ce3130a7ef79571c8a18077e22439c4b788efd", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300022, - "value": 199920000, - "script": "76a91416c9ac3637fa00f7b4e274e815a15b545b54f6d188ac", - "coinbase": false, - "hash": "9f449c52d16bb422defa06c7b4ce3130a7ef79571c8a18077e22439c4b788efd", - "index": 1 - }, - "script": "473044022034ec4a12c68b0eb967816a7f1d74dabb96281137ae81eb2cec38acdc99f03a48022055b12a8605b31b248b9308d80dbce0caeee4189da71a341ac9d2c0179483cc0d0121031294e51751731a5e92bcf325f805d25e0fef449b162f5af8078b9f00fe641cc6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 35360000, - "script": "76a914b2ff6025145c0ae90ce0c4c94c790312608fbaee88ac" - }, - { - "value": 164550000, - "script": "76a914107d0497c6ef84e169a2eaad2814230ccdfaf00188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "30c7f611e932e4cbc6fb0f6049ace1a287a945c0c2372795372c4dfb19e5adfa", - "witnessHash": "30c7f611e932e4cbc6fb0f6049ace1a287a945c0c2372795372c4dfb19e5adfa", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 76, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4503ab957600a6219f8ae8559588ca3907af6aac984313b80763efb48b5f2343", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 597424000, - "script": "76a91406ab9c45f8f067e93a2c73a1438f2e4c8f0575a588ac", - "coinbase": false, - "hash": "4503ab957600a6219f8ae8559588ca3907af6aac984313b80763efb48b5f2343", - "index": 0 - }, - "script": "473044022079d91c7f4ba556879ebc7e219402bd2ec5c7345c94e7a5fddb6f706a03c0504f0220014add8af2bcd1cca850278a0001abdf3006c22344cf3b690c3571a13435a96301210361c7855ddb770d368db5939724846616b4ea4a8ee51d5f1847a5ffa63c023e1f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 591569000, - "script": "76a91407ca4d940458922b49d5009aa1fb978a5b88682288ac" - }, - { - "value": 5845000, - "script": "76a9146a4e76dc2775d85971665a573c1e6371c238684a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7a97e28deddec43c665033b70bb50541667a588677200f43266fa53257a34956", - "witnessHash": "7a97e28deddec43c665033b70bb50541667a588677200f43266fa53257a34956", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 77, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0e7d6bc6a375e3586b84efcbaccb4b43d6c208561619b0ee0a328986f8669afa", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300022, - "value": 149830000, - "script": "76a91479e54b5acdbc31d49ab17a6812c73f1e5ee88b0b88ac", - "coinbase": false, - "hash": "0e7d6bc6a375e3586b84efcbaccb4b43d6c208561619b0ee0a328986f8669afa", - "index": 1 - }, - "script": "47304402202deb30d28555b9add60fe9958dc6fb2fb3717b66f9edc3d55ed82fb88e0d89fd022008f925bcab50da399a5926b12a76c6b11af751ce9e58791ceff3f1b99925763a012102b8961b996de6ca26ed07f3599f2bc5dd7cfd1516b2714dc46d55b68258f065bb", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 98700000, - "script": "76a9149485d636997ec22b79d4b53862a66bb713bdc9c388ac" - }, - { - "value": 51120000, - "script": "76a9147b7c800d94bda5d6f52b16277f394b3a44e9492988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2c1e4e9677c1f3cb9fadf67d4433a4745e63a19c0a1ed45288b390c400496fa9", - "witnessHash": "2c1e4e9677c1f3cb9fadf67d4433a4745e63a19c0a1ed45288b390c400496fa9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 78, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "44312822ffde37997cf6061394031439ec36397f58f665361b2573d3560e8ba2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 175010000, - "script": "76a914c645124a68c6cd7e3aacc00e42a7082a4e48b3b588ac", - "coinbase": false, - "hash": "44312822ffde37997cf6061394031439ec36397f58f665361b2573d3560e8ba2", - "index": 1 - }, - "script": "47304402207af5e1d18a6d201d9a0df89a181b629569b87c75dcf6bbcf1373bf14d1e0989802202fd73e1a66ef69e28fc38cd448d799666829849be4b2a653b3766b061c23768501210220ee63138138ee844f5b01036438276d0fb669ef73ede6ecc70a28264176c485", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 174970000, - "script": "76a914588d4ff71d79412a456e9bc7a3f8ab81af361b4188ac" - }, - { - "value": 30000, - "script": "76a914ad31cc8abedb4e2b7a67c17fe9f3bfb11d8a0ead88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d6200701dec406bd6be9436ff49ddb2c170e187b0cfebc0080c095127925356d", - "witnessHash": "d6200701dec406bd6be9436ff49ddb2c170e187b0cfebc0080c095127925356d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 79, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "05e06a8ddc27fc91bed57df6e607fb8c19cbae8ce8ac25c6bc73e5c6c5212c63", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300006, - "value": 14331996, - "script": "76a914cf9a58af9a735e49ba1b37ef08a7ffc131a128c888ac", - "coinbase": false, - "hash": "05e06a8ddc27fc91bed57df6e607fb8c19cbae8ce8ac25c6bc73e5c6c5212c63", - "index": 0 - }, - "script": "473044022065205dd5b9e52f2acf7d0e5c6ac4688436493604b79903737fb4a1f74403f8670220437658be3362f70823514e15d8c2cd86f3d821ab548960a4f2ca5bba682f921c0121029cae53000f967aa98ccc3c556f8dd894c2e1ec7400ac9a96bbb50f30f21ac56c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4321996, - "script": "76a9149c9474d73ca0979368cc482963f98ae93feb054788ac" - }, - { - "value": 10000000, - "script": "76a9143ce20975bc2cf605196c5e5959ddfa945abadd5088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f724074120a5527cbf4b063f0fd4437a2d11f2fc8a70e6041bd853f14d2a01b7", - "witnessHash": "f724074120a5527cbf4b063f0fd4437a2d11f2fc8a70e6041bd853f14d2a01b7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 80, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a38fdbffec144e5853103185dcc6bab69b05e2f7431ef62e6aeb0b14380b6b65", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 240029509, - "script": "76a9147a1b8da395daa85e92d225af39be2e96a46c645988ac", - "coinbase": false, - "hash": "a38fdbffec144e5853103185dcc6bab69b05e2f7431ef62e6aeb0b14380b6b65", - "index": 1 - }, - "script": "47304402207f7dd0768ba4ae5153efc7d92418f313846385b4c36e4983dfbf3ea27250145802203d9e8059737d3fc248410f0290a4a27272750643f2661fad0748adecd894de3b012103d249955fa9827fc4e4042841b28458c7dc2e73360cc32e15369798deb29c74df", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000000, - "script": "76a914d6b99d8113341d1adeda340660002392c1d4b3c588ac" - }, - { - "value": 230019509, - "script": "76a9147a1b8da395daa85e92d225af39be2e96a46c645988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7a331298363eed11e071ababda06efb0fcabcfbe21fe4b62c44920698305a8ca", - "witnessHash": "7a331298363eed11e071ababda06efb0fcabcfbe21fe4b62c44920698305a8ca", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 81, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5fb09b42604b9900a452322945fc910185869ff6cd7e6eef849b14b55588cce2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 6900000, - "script": "76a9145fc5ec0a7e2143d4a5a6da29077d5242e28921a488ac", - "coinbase": false, - "hash": "5fb09b42604b9900a452322945fc910185869ff6cd7e6eef849b14b55588cce2", - "index": 0 - }, - "script": "473044022078f722ebb6c96b3fdd46d7b70af566b0d20a65fc9fe738d138367d61641f7a500220702a8b576d73b17581d2b7c1c56ec02e10ad922bd1bd19641e81baf768ceefe6012103c98f9cfd900c3d84935b4d4920ab1a8dbacc776b60b925218828840774e41c37", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2490000, - "script": "76a9147a1b8da395daa85e92d225af39be2e96a46c645988ac" - }, - { - "value": 4400000, - "script": "76a914c7c1800d0972a32d7c124b777196bdfad48dfd0588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ab9a5f1c1cc82eff1f64b8438bfe6b8921b40fad329a5949df6aea0ba3d21736", - "witnessHash": "ab9a5f1c1cc82eff1f64b8438bfe6b8921b40fad329a5949df6aea0ba3d21736", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 82, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4a977af175e6390e5a02fc49abb3aee67a529b18994ba09464b7c797fd0e5840", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 116560971, - "script": "76a914557f48eee8e96c7cd803a6bc2be5b9f8b8999a1d88ac", - "coinbase": false, - "hash": "4a977af175e6390e5a02fc49abb3aee67a529b18994ba09464b7c797fd0e5840", - "index": 1 - }, - "script": "473044022051c700056ba5ba0ebc75106a2fbe590561bffd9bd750900dc6994cd46ae8deef02204b55954ed352eb26cc39ae813dbe132a9896daf15c85e839cb72f4e8f8a5e474012102a26edebfb404cda01c8b39554028357ed08e5b9de9bd9bb3b57ef954e55cedee", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 34240000, - "script": "76a91416609637ae5d6166ba1b039c566da5dc2718d82688ac" - }, - { - "value": 82310971, - "script": "76a9149dc8be4535f4dab7bebfa0da12d0735de497ff8c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fbadb361a0d96738184659e802a9b2c64579bca34394d5fd9d5457822690980c", - "witnessHash": "fbadb361a0d96738184659e802a9b2c64579bca34394d5fd9d5457822690980c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 83, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "987e73683b1fa5a62b1e31e9b6ad5395ad4fea781f1e9acc960b7aabd7bad3a6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 390000, - "script": "76a9144f2d8082ca48ed2f8cb5e8417c1bd17756796a5288ac", - "coinbase": false, - "hash": "987e73683b1fa5a62b1e31e9b6ad5395ad4fea781f1e9acc960b7aabd7bad3a6", - "index": 1 - }, - "script": "47304402201b32e3c41ca4e76e487996f9d6f7705f79ea405794cb46fe8341e7641805b25e0220060a9dac0a55cde1ec2fd8a54922f678e0eb3ee4bc193b35073c06e1578f703d0121029acd9b5b18f2abfbe3760c6a2d6f6ab544e13f1a315dc8b1aa76e01ec2c74343", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 200000, - "script": "76a914da5dde8abec4f3b67561bcd06aaf28b790cff75588ac" - }, - { - "value": 180000, - "script": "76a91489632368cd5145406b32f7af02e97b51966f48e988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "700666230b80f59dc87f3ad8a53476c441c6119ab89490a90d817ed693579a4f", - "witnessHash": "700666230b80f59dc87f3ad8a53476c441c6119ab89490a90d817ed693579a4f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 84, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d1294941743b81f6b5c66d2173bc20617b8f68fa75e9af6efea61c8220ce45eb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 50762016, - "script": "76a91484b04c09a2065b20adc4cf54f2cb47e975fadb6c88ac", - "coinbase": false, - "hash": "d1294941743b81f6b5c66d2173bc20617b8f68fa75e9af6efea61c8220ce45eb", - "index": 0 - }, - "script": "473044022051f1329f4d6dc0ef70a728b50c6246c01e0c79cf9853ddb8acca96c8f1dab5f6022046dbf29c0965fe50d0a82811c77eb08daedebfedd1c98966f4def4962c240a2e01210258c6288b432382daaf88e377c4a4d728c12fcae258be79f843d8bee45776dad4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2925000, - "script": "76a914be23007ebb9232f84a3f8d4b0c16fbab0182550088ac" - }, - { - "value": 47827016, - "script": "76a9141f2e83e7e88348b8265be26977324dc10c05e40f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2ffa6ff6eb34bec59a51c327c49b148ee756e1cc5a7cfd17e55626042f1ff1a2", - "witnessHash": "2ffa6ff6eb34bec59a51c327c49b148ee756e1cc5a7cfd17e55626042f1ff1a2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 85, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "31ef8708c94730a676961ddc89fbfcf62c6fe6d52f1f1779957197cc457b0885", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 48374028, - "script": "76a9145ccd2619098e61398ce73913b0fe27abc7bd70d488ac", - "coinbase": false, - "hash": "31ef8708c94730a676961ddc89fbfcf62c6fe6d52f1f1779957197cc457b0885", - "index": 1 - }, - "script": "473044022024685c9ed369a1659af21fe459be3abed2929ca35c86cd94b214f14ba570eef9022025a03441fb81b3c53ee8a2071937777b7cacea5e7267a0b658cfaa4baa5fdedd012102e53cebc4d684de368baea63a42403de9b5d800881bd7ea2ae1e8965c90c2e070", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 26774028, - "script": "76a9149917895610260d606f595d7e14b896b6a65e8a4388ac" - }, - { - "value": 21590000, - "script": "76a9142eb6d8929ea4ebb21d3eeef4ed599b2f57916fb088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dab4add20e9e8b09ef355cf7060dd88d189156859dc87c44fe4a5203fa644ee7", - "witnessHash": "dab4add20e9e8b09ef355cf7060dd88d189156859dc87c44fe4a5203fa644ee7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 86, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ea979aac3fcba582b6f4a13d8309bc0396934e28ac4c59c9fc098376ac5e5361", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 44297698, - "script": "76a914f55463d36d442c9c5eee22de6c012e0e0eb8cc9888ac", - "coinbase": false, - "hash": "ea979aac3fcba582b6f4a13d8309bc0396934e28ac4c59c9fc098376ac5e5361", - "index": 1 - }, - "script": "4730440220729515adad0f7c3c31d5f98059aea4a3a4f977ae1b1738b9e6287f2a0e948f0f02202f31382f142646023c59c8c7ba909861be380134129508416585b759dbbff115012103465501a4cafd4214a88cd543dda88039977607800fc80646a6b57b7b9eac6f9d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 25000000, - "script": "76a914bb3612312c465a438d0c86fcfdea513164604f2088ac" - }, - { - "value": 19287698, - "script": "76a914836d957cea44cea915c093cfd5d9e19c008fa2da88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3580d397129722f68da349e0dcd6e3d9988d247e58da27cc16b7ac7dd1bdf96c", - "witnessHash": "3580d397129722f68da349e0dcd6e3d9988d247e58da27cc16b7ac7dd1bdf96c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 87, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fcaa773d66d90f0509375bf9fd47fdb665b215959095b140d30ebc07435f6672", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 3100000, - "script": "76a914c3cbce21568909ce6af06f70b37e914b47c8070188ac", - "coinbase": false, - "hash": "fcaa773d66d90f0509375bf9fd47fdb665b215959095b140d30ebc07435f6672", - "index": 0 - }, - "script": "473044022015c4ce7351c426fbc3252881efd5b34469ec4400d0769fbb7f741979a8f20853022060163bd911eb479d45b767a03f6d6db3b91f26e39fa433fe7ff2f499f82a9fdb012102b360f50aefeb645ded270cfc766e8f0351be069da58b354794920ffa4271a1e6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1760000, - "script": "76a9146229f59192c321b0ce0ea4049ec5f14be0bb669488ac" - }, - { - "value": 1330000, - "script": "76a9147e794c8cebb54f245e3a0fee3d07418f44b65e4788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "054fb024109511a90f37be3316d709c21358fe4f0b3587e4647f8d0fcb4c3cd3", - "witnessHash": "054fb024109511a90f37be3316d709c21358fe4f0b3587e4647f8d0fcb4c3cd3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 88, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b880048c3dcc549b977b81c33b55efa0fe0b74bcf1c8e38035c8a0afc89874c5", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 66219932, - "script": "76a9145da3d17c6d9255b27c4cafbd13835362b31c06cc88ac", - "coinbase": false, - "hash": "b880048c3dcc549b977b81c33b55efa0fe0b74bcf1c8e38035c8a0afc89874c5", - "index": 1 - }, - "script": "47304402207568d5f890595056c2f833e9b4d358e6b42c69b9d1eca27014152605a1540da202202e0335e673c0f9c891e27d7fb3b90a814061ffb072bd62c274304de4c7646c2e01210369c1aabafd97957275ee8ed23105f3d402fde1d8eda0672f4f813c68b9224905", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 66200000, - "script": "76a91448c68bc667ce0d74860dda6fd9aa6676677bdf4088ac" - }, - { - "value": 9932, - "script": "76a9140dc9eff0a80b51d0551f26d3d183fdcdcee9b4d288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "50a6b1716559fcc6415c5951a2ddc8bdb2e58c9749c3d340d7dc01519554ab25", - "witnessHash": "50a6b1716559fcc6415c5951a2ddc8bdb2e58c9749c3d340d7dc01519554ab25", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 89, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "50ee9c8a6ec58473192a88262dfbc0ba8ccd0d56c621e79963adf7da8f485002", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 30126065, - "script": "76a9144b6e6cab227ee14166336a1161cedd000594879788ac", - "coinbase": false, - "hash": "50ee9c8a6ec58473192a88262dfbc0ba8ccd0d56c621e79963adf7da8f485002", - "index": 0 - }, - "script": "473044022058b28c7ecbd8a1a155480a8905f3c00e2c30ff98542ee0a1da08ca13135a0aa202205f8c308b142186dfece10d1ad3db119c55674834f31f59a1e0625694d491d554012103bcbb2d4fbc13072dd51c4cf4ef9fab8b24f9ac454515abd6f3108534cc817bc8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 30000000, - "script": "76a9141d2d60b4be51b4450ac6d95186a1614d101d93f788ac" - }, - { - "value": 116065, - "script": "76a9144b6e6cab227ee14166336a1161cedd000594879788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "87b35953f5507029f7aad06936cb6c2d600b7be55f5360e8c038410502af9a81", - "witnessHash": "87b35953f5507029f7aad06936cb6c2d600b7be55f5360e8c038410502af9a81", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 90, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "353b9b4f569c96cd489cf97f24d0d4be03825dac56186e6b8b7200eba4e68a5b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300006, - "value": 3134280, - "script": "76a91448abe414fb9e14e15b1c7dbcb140fad1d7db948188ac", - "coinbase": false, - "hash": "353b9b4f569c96cd489cf97f24d0d4be03825dac56186e6b8b7200eba4e68a5b", - "index": 0 - }, - "script": "47304402205ee0e2f68abcd649faf199c75d95c82fe7cbc2b6a35d136aee0798615c92c377022052d9331459ad6f5a60962c94878eb0dc033d63ff50deac0487b837ae17de2269012103b021fe510ed3a1cd2eed8e1065c289eb63f79eda66bda39d7ef33f4de4a94718", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2321780, - "script": "76a9143ccd638ec45571070e9a49cf91961e40bb56365088ac" - }, - { - "value": 802500, - "script": "76a914a48c35e18e369168a18029a75ceb84705b1c87b088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "48e960f022a554ac70bdaa4e9364b5fe8c1b0d9f8715cdde0f56bd30652ff7ef", - "witnessHash": "48e960f022a554ac70bdaa4e9364b5fe8c1b0d9f8715cdde0f56bd30652ff7ef", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 91, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0b6b72e182d292c992b8c099c317a8831700f426835cacb1c04991bb293087c1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 40666646, - "script": "76a9149601092669928f9d6980354af6ecfafc7048a3fa88ac", - "coinbase": false, - "hash": "0b6b72e182d292c992b8c099c317a8831700f426835cacb1c04991bb293087c1", - "index": 0 - }, - "script": "4730440220168d44341308174fedd8de17638e5b8585dfd0d3ad84d2439d225e0ec2a709550220252d57345e133e5cbfb2bfcd4f883e6eb093a1cb692d2f00f71d6943a99673b6012103b8c9b49cc603861b0e1ff0193fb08ff37baa79f966d9e112d1ed14d7837b94e1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 13600000, - "script": "76a914bc73e5aa1d8ad3a50e5ddd7db9a2be76d7a651bc88ac" - }, - { - "value": 27056646, - "script": "76a9141c52f47458b2e0c65a9f686b8c5fb0020ba0e2eb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "354bf62c01c4089137547857d0b2f7ec6827d7fca305dd6618cb605d65f4e4e7", - "witnessHash": "354bf62c01c4089137547857d0b2f7ec6827d7fca305dd6618cb605d65f4e4e7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 92, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ee9f94c3eb764e23399bcff6d3e9f9c6804c01d2aa44bda447fa702a588be8ed", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 17350000, - "script": "76a9148e1e0cfa8e76901de9647f3c1feb10b214ffb96088ac", - "coinbase": false, - "hash": "ee9f94c3eb764e23399bcff6d3e9f9c6804c01d2aa44bda447fa702a588be8ed", - "index": 1 - }, - "script": "4730440220560763fa7b4dd607334ed25ef2ee6bbb97503caf7160c6859b3877ab9d66a8a602200728a8b1564308a2f526eafdaca005b6abb411d208029eeafcccba26573df7a9012103c83a3696295b05bb6ec8a5c54264de00413ed9c9a7b08faeac1a1e29054e919c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3520000, - "script": "76a914fe59d387308bedfdd0f37b1e2bd0869275b3451488ac" - }, - { - "value": 13820000, - "script": "76a914262403b92d1494d1187c21914d9a4764a067b9b588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9c9e3d830e86b53e782c1fb74b128f682d7b6fb6e5796a5763bcb22c01e7d933", - "witnessHash": "9c9e3d830e86b53e782c1fb74b128f682d7b6fb6e5796a5763bcb22c01e7d933", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 93, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1e3eec7a6d024e136c9fbbdcd81d7dcecbcd660933585ae55b8b18cb9694aea9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 740000, - "script": "76a914a9f62240af9d0be8f70f1a6e926c9a85c10e74c688ac", - "coinbase": false, - "hash": "1e3eec7a6d024e136c9fbbdcd81d7dcecbcd660933585ae55b8b18cb9694aea9", - "index": 0 - }, - "script": "47304402205f7f4d32cc2cca06762d95181f48e248893e3c75cb5a6fa127092bfcc0c14bcd02205e55a6bb5cc4d220ebb523f41cb55d303b0d510dd42634fbfe06623c88147ee8012102fae2cdb83c84a13fe54a3ae540696059ddc6bfeef161264b1594fbbf4da5e15d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 500000, - "script": "76a914fbe6e9e96ef861f3f93c34848a4cb554c749310488ac" - }, - { - "value": 230000, - "script": "76a914a9f62240af9d0be8f70f1a6e926c9a85c10e74c688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c141d050c7faf55bfb044535f8e60f1169f75b00a8becf66ad4fdd00bb0ef821", - "witnessHash": "c141d050c7faf55bfb044535f8e60f1169f75b00a8becf66ad4fdd00bb0ef821", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 94, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1ef1c8dd3753aa8e0ee67a2ac03e059abc0c4da29712e0f93be0b481d49a7856", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 6905454, - "script": "76a914b4084daea798e7cbebfc9ca011f220c8ba587b4488ac", - "coinbase": false, - "hash": "1ef1c8dd3753aa8e0ee67a2ac03e059abc0c4da29712e0f93be0b481d49a7856", - "index": 0 - }, - "script": "473044022075c5e922360432cad5e55b7ae861aab0b70b5674bd8481402084e0b37961fef002203014b106e75df4f998f2b03de872c937a685211fc250fc15a4ea21a774802fb30121036e6d66423da3b704f540b6c55cd3c3674e52326c6f4de34632ff227740c18a9b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4995454, - "script": "76a914580f29765a8e34d515d061096f31a8d3524045a788ac" - }, - { - "value": 1900000, - "script": "76a914ae59f86f8e962681d6b9e2d51b5b269aaed2ba0e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ac2ee8275091aa876086fe53d2c76f527a793ad77ca574e711ac2a6ecd4394ab", - "witnessHash": "ac2ee8275091aa876086fe53d2c76f527a793ad77ca574e711ac2a6ecd4394ab", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 95, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f2c3e5b5982a84b999f8614669ff6de4edd36a0bb1408e788cbeeb7c132347b1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 9990000, - "script": "76a9148e434b430d736c63529946031b25a0c058ef71fd88ac", - "coinbase": false, - "hash": "f2c3e5b5982a84b999f8614669ff6de4edd36a0bb1408e788cbeeb7c132347b1", - "index": 0 - }, - "script": "4930460221009874cb1f3c8523f15b5db0571e7f86e224844bc72bcb00c4dd110fc036a018360221008b8947c6e207a418cf1966d993d23d8528f28276909d77a6b757f00e4f99774e014104d81a72d5a6d6c51f6f64b20fa7bfb807f4c5726ba0066ac485898854dbb35b4b9f113a98ccf58f5e411212caecc6f3033b36a0af4d69fdae5d7a466951943176", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9980000, - "script": "76a9146fe0399227a04acc813420e65b94d602bf8772da88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "78fc74e3759105cde81aa9bd8b0972c9c1fd241fe81df5ca82b78191a1bf6cdb", - "witnessHash": "78fc74e3759105cde81aa9bd8b0972c9c1fd241fe81df5ca82b78191a1bf6cdb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 96, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "232ba69eeb904f5a753ee71ff504d756965271865122a41fbacecd37c13eef87", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4404801, - "script": "76a9149fca6ea9d2c36317f10317e13cee886249df99a588ac", - "coinbase": false, - "hash": "232ba69eeb904f5a753ee71ff504d756965271865122a41fbacecd37c13eef87", - "index": 1 - }, - "script": "493046022100a6716dd213a715c1c253837b7548a6b5ff1ac67746f6315bb47c579fd834d387022100d58add59b608c4d75b498f461e464df6357a74cee23ab3e9a7f4451db0b08d6e0141043f4d39e95e2ab5b5f0f2521d8d6a78a81845811013b0d2b142b1a1342e7fee1586b68f25f9d993c4d8e77dd7a39349ebb1c9fc0ce7bcc2cfabc9d06fca72d4f3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4394801, - "script": "76a914fe5b2dbac47ed1bf8d291fd73e134ae63ff68c6888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "efedb9f2e8e28c70d4804b10a58894158dc91128afc93cbf7bb583a49b0cab17", - "witnessHash": "efedb9f2e8e28c70d4804b10a58894158dc91128afc93cbf7bb583a49b0cab17", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 97, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d150ccd78a8a19a9dca9d7391e3298ebb8bbed9ecd6520d23da58e002d2ebc07", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3499259, - "script": "76a91424f08d2bd989b1e6a614604612c333a9cc8ef88288ac", - "coinbase": false, - "hash": "d150ccd78a8a19a9dca9d7391e3298ebb8bbed9ecd6520d23da58e002d2ebc07", - "index": 0 - }, - "script": "4730440220527f1fce6864507c04c71a3038bb35c390e89517aa2e9a13f43c623e9c76ce5102202f79011e134f3723948cbabeae8383ec0ed3f7d2ebcdda97dd8de0e416c64454012102b22d59847a1b3f06e69ced8b051589d7fe420183575a4756a76a8c2231b1fb45", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 33170, - "script": "76a91428063fd6a320ec9249a184bfd18224e8037825f688ac" - }, - { - "value": 3456089, - "script": "76a914c9d05c29acacdc725dc9023e992215337bb3131f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "41b2fe993e1e59e500739c023e0ae7f1f860b9b34174f513d62b04e00348eba4", - "witnessHash": "41b2fe993e1e59e500739c023e0ae7f1f860b9b34174f513d62b04e00348eba4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 98, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "34e762c639d84a98c2cbde51f2647c105ecc278b79d7a222c8308adfa8a14521", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6536994, - "script": "76a914ed871ee49768c4ab8bcbf6c5f99ef6883f5244ca88ac", - "coinbase": false, - "hash": "34e762c639d84a98c2cbde51f2647c105ecc278b79d7a222c8308adfa8a14521", - "index": 0 - }, - "script": "4730440220402eafc6004b7f043c3f7f8ff0e9992f1ee3e04a7f9468c8a77e21332e11c28302201c36f0bce67a3d75dfe482a7ca885c64a9b2edc1ebe19e9a94052f388f6e191f01210248f4401d42148dbdf4da3600642e293de1014f88c35485ea3fa8ea5a30806210", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6376794, - "script": "76a914d5fa15173be347ef5a7202af50670c859f8283c888ac" - }, - { - "value": 150200, - "script": "76a9145c84ebab10bdf995178e972e5aac94c6b1c5405688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0777af11126121598a0bf7295c16a9703b6556db052ddcdd9ae407bc37d516c8", - "witnessHash": "0777af11126121598a0bf7295c16a9703b6556db052ddcdd9ae407bc37d516c8", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 99, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bdc7565ce1fb21dff1c2712897b93e30b8ceae9ae239cae2f8631f2b5c288122", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2827450, - "script": "76a91408be6cf3931d7279f4e30eac6dcd91560e55cce788ac", - "coinbase": false, - "hash": "bdc7565ce1fb21dff1c2712897b93e30b8ceae9ae239cae2f8631f2b5c288122", - "index": 0 - }, - "script": "47304402202db1290c0e8184da9054c33f32fc13715fd3be70340acda2e1e7bfa3d8c360ba022062d70790ba8e5681a435950d6823832a7039bc2a7272ccc821a4b9ab4880d28301210244a91ccb4ae96fe214e34b4da721908a48a13fc183d57229b698292a90d6dfdf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1101370, - "script": "76a9143addb60a01267df715a36653c1a654a73a16e14188ac" - }, - { - "value": 1716080, - "script": "76a91408be6cf3931d7279f4e30eac6dcd91560e55cce788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "37b7f95affd69f589ba6864c295eed72a3abb11b132ba36f5a23548b33cdc044", - "witnessHash": "37b7f95affd69f589ba6864c295eed72a3abb11b132ba36f5a23548b33cdc044", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 100, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0106703f4510199beec1352ea385d0d1302a9ca2498b502722c83d1f22fb1cdf", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2025895, - "script": "76a914f90c134a99f369e5305bf3472e251d751d0c1a5388ac", - "coinbase": false, - "hash": "0106703f4510199beec1352ea385d0d1302a9ca2498b502722c83d1f22fb1cdf", - "index": 1 - }, - "script": "473044022014f63a962491ac90448967ce964bbff17cf51a6c1f8a895d2016999c6e908bff02200c718205f28fd7fd62e7c9cae0b8a4da74c5796d1bafce31cb68930608dc4054012102d8cff3829a5557adb705f5911cf3577a034e3c824a9894fc5e056917f67ee48c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1215395, - "script": "76a91400346e60a649683932555ccbae4293113586afd488ac" - }, - { - "value": 800500, - "script": "76a9147784eafe2c4cea0076e60219d492a1d46feb2f8c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "367c1c3a0ec8c3d8bbf8213d42202450a2157076202e998ef33721bdb280fd67", - "witnessHash": "367c1c3a0ec8c3d8bbf8213d42202450a2157076202e998ef33721bdb280fd67", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 101, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c521b0056bb58cc318df65833d4d698158238b209e1009ea59671a00d967df93", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1444951, - "script": "76a914cfc54a78492d8841a1ec3c4cb348466dd82828c588ac", - "coinbase": false, - "hash": "c521b0056bb58cc318df65833d4d698158238b209e1009ea59671a00d967df93", - "index": 0 - }, - "script": "473044022033dddcea22e24dc8e9496ec1626f1bad41b7c98de53df8b40e9b843715a7a3d202206058b2d99836d411dd36777ad3f0773b7028ed1378b3763a6a198121ee51733601210209c69af344da797855b812a3fe0084ac660aaa82f1df5e579bb3f6ba280506b7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 50000, - "script": "76a91471045f0ebc56873501033435df2931de7867277988ac" - }, - { - "value": 1384951, - "script": "76a914ce2d554e04f8917b13a44fd622b3c07f2e89be3488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6e1ec4e54d6699636ebf21c665cdb291ee545a3af6651a4098e8b0d94247c251", - "witnessHash": "6e1ec4e54d6699636ebf21c665cdb291ee545a3af6651a4098e8b0d94247c251", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 102, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "efedb9f2e8e28c70d4804b10a58894158dc91128afc93cbf7bb583a49b0cab17", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3456089, - "script": "76a914c9d05c29acacdc725dc9023e992215337bb3131f88ac", - "coinbase": false, - "hash": "efedb9f2e8e28c70d4804b10a58894158dc91128afc93cbf7bb583a49b0cab17", - "index": 1 - }, - "script": "473044022036bab2cbe023dac7efc9712dd07210d32c355a1d932328828b661874bf2ee21a02202c1b44866d46924900de0d905d2d48e1a9ef3edaa0248fa87a0e5b8a746af8db0121030066c5bed0fbc4a94efdbc57e1e5c1a4e868c52d2de229946b30d85c0d8bb03a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3412919, - "script": "76a9149b50e4718c4d7cc4554443e40d34bf6306e53daf88ac" - }, - { - "value": 33170, - "script": "76a91499c5ef32afa5cde9567ab33e59966bb72943494188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ffd03ba45678f8bb0941b131b2b9ef71103c1653d69f67f9a64d77b6acf359a5", - "witnessHash": "ffd03ba45678f8bb0941b131b2b9ef71103c1653d69f67f9a64d77b6acf359a5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 103, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7e09d4de22eb172b846b55d24ab57a191e4c90922fab27ca90355662a0ce4b03", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299617, - "value": 3000000000, - "script": "76a914020908d6834fa490da2f561ac21f00d4d2f13f8788ac", - "coinbase": false, - "hash": "7e09d4de22eb172b846b55d24ab57a191e4c90922fab27ca90355662a0ce4b03", - "index": 0 - }, - "script": "483045022031b275999404d138f01d6596d856942a645a44e97cdf410a3a2038eaaa8513c9022100a766f87c17f7ae7266188629b8fa2fd44db4077a58eb476407474e063b5fb39d0121033d190b483f8670c1b1078894e267c8087fa4a82aa8d2195a13c0f091e3137ea9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2824959625, - "script": "76a914d905632fe36392b14d43f2deee2796c06a73402f88ac" - }, - { - "value": 175030375, - "script": "76a914e6a95791cd3573b5ab3243771ad40cc2f04a06a588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6a35e64848fe1e1e648d9e807be052dd7c2961fa0f0b5c5cc67cc30a661f999b", - "witnessHash": "6a35e64848fe1e1e648d9e807be052dd7c2961fa0f0b5c5cc67cc30a661f999b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 104, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "106f0179ed78e09c1585893ce9c18106570b42cd91d173f616e67807aaf6ee84", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 97802780148, - "script": "76a914f9a2146b89b908d9ccdd42270bc8544789a630ba88ac", - "coinbase": false, - "hash": "106f0179ed78e09c1585893ce9c18106570b42cd91d173f616e67807aaf6ee84", - "index": 1 - }, - "script": "483045022014655f8862fc8a6652fe9ae284dfd5acaa3c5cd3c2562f8aa272d3a363fb27f5022100d6126cbf03a3bf8c12d6eb001b1701ee656e56cbe95a0305273a6ba286f97261012102a74a4150e024bbe78c38b07b53d447586fb987eca72d80842fbd4d219600b2d2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 222750000, - "script": "76a91426418367d9ce90dbc52755a8d2e98b6c49f72f6288ac" - }, - { - "value": 97580020148, - "script": "76a91447c141e9c8e692e2b2bb8e598ce59dc3694e0e2788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "72703ba6663c30e9550bf68d2dd8a52abc45c2a1d4b431e710aedbfe9301e9d5", - "witnessHash": "72703ba6663c30e9550bf68d2dd8a52abc45c2a1d4b431e710aedbfe9301e9d5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 105, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a466c80fd65dce6e365df2d0d720b73da9bf6f51948c8a5e6f014238aa58775a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299892, - "value": 922386000, - "script": "76a914ffcd9e9bffc532e0ce60f6ca108f89583c51175988ac", - "coinbase": false, - "hash": "a466c80fd65dce6e365df2d0d720b73da9bf6f51948c8a5e6f014238aa58775a", - "index": 0 - }, - "script": "48304502203aa280157cf70178e6ee9c11d4a7f40957310e663729d20375ac1fb522349015022100968081674cb91d63d098f790fae61f41f3a6e27711eb8d073f9211e64eb2c38d0121034c921ab6c336cc35f9998c75fbd1691d947bd103b964a1ac844ee57ac45b54b6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 901429000, - "script": "76a91450a62335fb18760906f27934895e1abba41ee4a788ac" - }, - { - "value": 20947000, - "script": "76a9141abcc01caddb34e637e6ef3b1e935dd7f1f512e188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a030141b91f410593b3d5f2943079a952277af54d332044e870f65ca53d30170", - "witnessHash": "a030141b91f410593b3d5f2943079a952277af54d332044e870f65ca53d30170", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 106, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8cf93565618a6233f578b919dccd09bd67ab595fd8bb060ee4244395ce8a8309", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299732, - "value": 343520000, - "script": "76a91404f19e5871b8c60c0189bee8bd7c645ba243218f88ac", - "coinbase": false, - "hash": "8cf93565618a6233f578b919dccd09bd67ab595fd8bb060ee4244395ce8a8309", - "index": 0 - }, - "script": "48304502210091b755f1a13bb86bcda908acd7c34cefa0570696a21d2b6f757a82135a31786d0220214ed21f448012d56f4237f3b3b585e6013f030e19c6b7ee464afa7338038741012103a36d8409b85492f88914c3d06a015f68ea2b968bfbb5168e171bfc18c5c16ead", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 400000, - "script": "76a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac" - }, - { - "value": 343110000, - "script": "76a91491c2d43bea3f61ebf55e1e640f14f0031e3e46ad88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b35fd688ed0f62031356a9b8db9129058fcc520053ed358e0c5d1dde6f03d61a", - "witnessHash": "b35fd688ed0f62031356a9b8db9129058fcc520053ed358e0c5d1dde6f03d61a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 107, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a030141b91f410593b3d5f2943079a952277af54d332044e870f65ca53d30170", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 400000, - "script": "76a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac", - "coinbase": false, - "hash": "a030141b91f410593b3d5f2943079a952277af54d332044e870f65ca53d30170", - "index": 0 - }, - "script": "483045022100d0668de97b5687d484c9de8f971d06b804d2a26dc619b824b2884bc80ecbe97002207f58896b1ff6d52ef755e2fd5de027f39f6baaff10cc7d3b19a6f0edf301ae00014104ccc493c773ed7b190fd3fec0fde94df66605923b5ba6781968921e3f7c86060f62799e085a6873cc5dc1592e99a9090951cad28102cb920da361944d1a827916", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 390000, - "script": "76a91404f19e5871b8c60c0189bee8bd7c645ba243218f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ac3f228550662a7c592878c0e0d9365ad26049fef04629732b47d31f5a9d0bcb", - "witnessHash": "ac3f228550662a7c592878c0e0d9365ad26049fef04629732b47d31f5a9d0bcb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 108, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c78a25e0e2313124c24d80cbe9f8d1c26ef8523c90fea76177715fea5bc2bf6d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299897, - "value": 300000000, - "script": "76a914318bd84a8d81c1c21d2354afce50bfb0aa177be388ac", - "coinbase": false, - "hash": "c78a25e0e2313124c24d80cbe9f8d1c26ef8523c90fea76177715fea5bc2bf6d", - "index": 0 - }, - "script": "483045022012eed9463a05dabdbf1a6cb51db2b749db78d3f1d518405eab14eeb3bb8f95390221008e699b50c4f1b52de1c4a76376234b493a68c8f816efd3ab239130cafa9c0891012102568ed5145892b4ae7bcd153f4e05e5a0e4d1ff8142fb5912e50e5d9f88aca665", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1064000, - "script": "76a914faa3316796f5ea4366cb4dd0fcbe5c9d131a2f9188ac" - }, - { - "value": 298926000, - "script": "76a9147be06736f5ea3fbc9af8e23f07c8f0b72ff80e8f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b3b33a687814628dfc81814a9b4fb7062ead2211268e4306dd25c44ca648797c", - "witnessHash": "b3b33a687814628dfc81814a9b4fb7062ead2211268e4306dd25c44ca648797c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 109, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "20c469506fe84a01ea9a0ea4e22e5216398153f9e200707b3f83a557b1961b48", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299869, - "value": 163000000, - "script": "76a914741773b4b14a083cd6c3f232725e08fd4a34ce8388ac", - "coinbase": false, - "hash": "20c469506fe84a01ea9a0ea4e22e5216398153f9e200707b3f83a557b1961b48", - "index": 1 - }, - "script": "483045022100e36e47b601c43af8b8e7e748e2f8bdf747ffb335b2d48359a5f634ef58f3ede30220291fe8050ffc4556fcc50b9de95360816ba080aea2ddb513aebf324528dbfac901210297a5fe7d3d144aa8b0e6cdaa99890f90d1ad3029f7ffb319c0d151e7bd5a06bc", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 162490000, - "script": "76a914a849ee34aeea55ebd85ca30135a6fc249ca41b1988ac" - }, - { - "value": 500000, - "script": "76a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ab19cf0773a2f7ff247e12517f6fb368fc92fda147a3014e0907d1c07ca5d4c5", - "witnessHash": "ab19cf0773a2f7ff247e12517f6fb368fc92fda147a3014e0907d1c07ca5d4c5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 110, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b3b33a687814628dfc81814a9b4fb7062ead2211268e4306dd25c44ca648797c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 500000, - "script": "76a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac", - "coinbase": false, - "hash": "b3b33a687814628dfc81814a9b4fb7062ead2211268e4306dd25c44ca648797c", - "index": 1 - }, - "script": "4730440220309543ec30b369f9314dc7c7d538bad4cd57950999f4b782b71bd7fa8370226e0220337cbbdc08ecc57034f79894e7b64f83af09934ac404c2816f4302e6bb25113e014104da6bc6a6139bb008454bfc8371141a5fb8ba6de87e9ab1578ab4c31e1b25513d6d1b1b0e66b0e39a29f6baf19f9f0faaf51d22bac02b1c07eb08058498763784", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 490000, - "script": "76a914741773b4b14a083cd6c3f232725e08fd4a34ce8388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ad2d5045450a1b6fa5f6513232a4a1f09c3390056f403f4a1ab7ea54c901da0a", - "witnessHash": "ad2d5045450a1b6fa5f6513232a4a1f09c3390056f403f4a1ab7ea54c901da0a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 111, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ab7401d13fca148a0580aec611e123d9f8dd317936c2830241570a91069962e9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299951, - "value": 201852000, - "script": "76a914e92be97d75e18145fff978ed415535b8afd1156688ac", - "coinbase": false, - "hash": "ab7401d13fca148a0580aec611e123d9f8dd317936c2830241570a91069962e9", - "index": 0 - }, - "script": "483045022048f81cf4f4fcc91c61d153a7d6761046002b2c9cb0902a6945b89b29b2404d34022100b84eee1ef0d179827f51eff250d6c4a5a1701a42ea101cfa584dfcf36aad94e3012103e4b0d754c725dacd1ec1338efa132f46d097fbfac61f0441407c9be17aab44f8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2020000, - "script": "76a914327e588ed2bbabfc99cc600339725cc7a0066fc188ac" - }, - { - "value": 199822000, - "script": "76a91447d7f78504516b8d8ff0c8150c13ab1d21ca6edf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4bfe8b2f33cd22d329e453f4ed9d9a8edce6547910f7fdb0263ab2a6c58d6b79", - "witnessHash": "4bfe8b2f33cd22d329e453f4ed9d9a8edce6547910f7fdb0263ab2a6c58d6b79", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 112, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "286aac0bcdccd6e670270c94e8f56b23f165293f0c63f79bc71d63ddfeb1a720", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299999, - "value": 351441000, - "script": "76a9143676f9f762ec007bf99d0d79d8afc0b32fd43c0888ac", - "coinbase": false, - "hash": "286aac0bcdccd6e670270c94e8f56b23f165293f0c63f79bc71d63ddfeb1a720", - "index": 1 - }, - "script": "4830450221008c49e126d5b108160dcb5a78bcd9a313e1c78e06318d122a5000055f8dbb986d022019fd2bd350b10bf45f0af1f0dd553b12fe7665f8d7f1625f3d1851b6b7eba91f012103b038cd334e6562635612a298c67217ad4260fb3f2dae68ad74a3763e8da01e39", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 17621000, - "script": "76a9148f1fde7bda6eaaeff9f80ee3adcf6c5c7219c99c88ac" - }, - { - "value": 333810000, - "script": "76a9143676f9f762ec007bf99d0d79d8afc0b32fd43c0888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dfa3986babe54b50d013bca88c939e4554d70a774af729acb9e733f3cde1a966", - "witnessHash": "dfa3986babe54b50d013bca88c939e4554d70a774af729acb9e733f3cde1a966", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 113, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "27bac71a6771564486c5d27e30dfcd2d20b012e7e6627c16ac932f0aa3db631d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 152042000, - "script": "76a9148ec46974ca3773150e2eb43ea53c1ad74860900e88ac", - "coinbase": false, - "hash": "27bac71a6771564486c5d27e30dfcd2d20b012e7e6627c16ac932f0aa3db631d", - "index": 1 - }, - "script": "483045022100b3fb53c28e4bc7590a341dffd4fc75ca9378c266c964a874e24ae701cdb244600220735d13f1e4ae0b5c2056c036f55f42808fc6125621dbd92901adad8fec3fe904012102220f279392d0987b3365980988be01526417da4528e417162c1e2a8c1c4f2407", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 150750000, - "script": "76a91405030c6d1e2212b027856fa22f9861d508bc56b988ac" - }, - { - "value": 1282000, - "script": "76a914d5f71f487783c928cbfb46af44c509fc7df7e5b888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "59b807f61be36d2e380bf8ec15f3f07114a59de8b75df8ec17f58668d9cfd5a0", - "witnessHash": "59b807f61be36d2e380bf8ec15f3f07114a59de8b75df8ec17f58668d9cfd5a0", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 114, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "946f08970f34e9196f415670920bb23d5172cbd7f9305ddd749907af8371af3e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299877, - "value": 43716951, - "script": "76a91487b300bf9694a6cf8f50088c40c954cdfc4a4a8688ac", - "coinbase": false, - "hash": "946f08970f34e9196f415670920bb23d5172cbd7f9305ddd749907af8371af3e", - "index": 1 - }, - "script": "48304502210084656a0947322a9dc712c100c3372102f2522a324b7d5b775b04a43b47f8ef52022034c9879f5c8cc51c266f91d291fc1e36350cc135a28357635cc89966ad4f3bab0121033645bd7da6549dc49fdfc275ef335c06a615616e560f39803bbe7dcc0cebcd56", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6716070, - "script": "76a9144a1941d41f60963b2aaeea35ef5ae7a10f988ec788ac" - }, - { - "value": 36990881, - "script": "76a914518e38d19680601c78a866eb262f1f6a41455de988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c530865b6acf4e74556725ce2796d5e67618d3f8fc712e8b0b7c8ba7248b3836", - "witnessHash": "c530865b6acf4e74556725ce2796d5e67618d3f8fc712e8b0b7c8ba7248b3836", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 115, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "efb2dcc2f26adb81be1819dc84d80e3abbc91cb3d80b8066adc4893e391cb04d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299113, - "value": 5371246, - "script": "76a914c140daabb6a4225712f2b5db3dc6714f4919d76088ac", - "coinbase": false, - "hash": "efb2dcc2f26adb81be1819dc84d80e3abbc91cb3d80b8066adc4893e391cb04d", - "index": 1 - }, - "script": "483045022100831925b73fc4caf04a157f9fd574b0d451d9e1968d0c7f028586cb4f6290e278022060d0d2c871222e9abd4f95cc8c04f4a27699cdb56dedc947f361e158b90f21f60121036d75c13adfa81210da28bdb305f9c759209691dc1b060dfa8741d8f5a8744d02", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 500000, - "script": "76a914c52acc6ed8a74a05fb3839456c11c7a453b745f288ac" - }, - { - "value": 4861246, - "script": "76a914c140daabb6a4225712f2b5db3dc6714f4919d76088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7df6ee56dfe56a9b97c0fc162bd9e715d62b56210699c582c5dee715f5422164", - "witnessHash": "7df6ee56dfe56a9b97c0fc162bd9e715d62b56210699c582c5dee715f5422164", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 116, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1cd6f20e1c2ff862901310931ee8c8ca9949120a822f78824270bc3b5de877ad", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 3633336742, - "script": "76a9148cb17fbbcc7a2c1b6d4a42bf6cc726d5c1d68fdc88ac", - "coinbase": false, - "hash": "1cd6f20e1c2ff862901310931ee8c8ca9949120a822f78824270bc3b5de877ad", - "index": 0 - }, - "script": "483045022100e1795bcb152eb27aa849358c1b807640b8dcc921c3a007d5100506a44eca27f7022010933cbc75c744060cf13e90aaf49c82dc3d3991aa739bb40387665f48ff4da70121027535599b9a8cae6e14afdb6fe223319c69197adf1392211bf83c000a1eb2a692", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3624426742, - "script": "76a914ca332e2fad8dc1b20f447a6ae45d2cbd36a82e5f88ac" - }, - { - "value": 8900000, - "script": "76a91432638fe8a334b7cd434d6d2e4ea637b7422d9b1b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2e62956d09b991b597d5b6e34aaa39462f0c45881e0d5ebcdf153db0d58635aa", - "witnessHash": "2e62956d09b991b597d5b6e34aaa39462f0c45881e0d5ebcdf153db0d58635aa", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 117, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "846a86fa3ed119039978e239031f50c2cb416743ac50f75f107a55f3b35f8e7b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 284944, - "value": 198181, - "script": "76a9142db8561d40f41c708832893815f35bedca4f9aa288ac", - "coinbase": false, - "hash": "846a86fa3ed119039978e239031f50c2cb416743ac50f75f107a55f3b35f8e7b", - "index": 0 - }, - "script": "4830450221009e8c1c04ad1c8838ce779fc7334314c584ef88d844e8ca4493dafc696287011702203262ff5752adc12724793e5ff96cdd24bda4d9b023961230279eacd55351f3ca012103767be7c470505b782f4182d99fa1e85762c1ae4c689e60583f5f5b3ea171d766", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 33338, - "script": "76a9141bc342485fdcab48a98bdabaa7d320e1be2f5f4488ac" - }, - { - "value": 154843, - "script": "76a9142db8561d40f41c708832893815f35bedca4f9aa288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "332ff53505ed943d8e4561d40561ec7d0c96cd27a8aded0f126c05ebdf532dd1", - "witnessHash": "332ff53505ed943d8e4561d40561ec7d0c96cd27a8aded0f126c05ebdf532dd1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 118, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "207ac50d84aa773967a2e954df3f0c881bccd163a0274bac35c76f3ed2e0740a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1058882884, - "script": "76a914f6dd9ebeb8c1c82d27ed0d5a6f8e9a71383c427788ac", - "coinbase": false, - "hash": "207ac50d84aa773967a2e954df3f0c881bccd163a0274bac35c76f3ed2e0740a", - "index": 1 - }, - "script": "4830450221009e5511fceb1de859df236e7c0e63564c56bcc4d0d194f799829c1d2bc44c334702202e0d421ea5e3fefa33af6c8219493e839ff4983eceabe6bfab182f2375259b75012103a9534a1e8bd2a18b6027c06d403c35002b89375f52d5ce53fa9045fe68663543", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1055372884, - "script": "76a9141e3b2f1b6824921e7225db75c7ec56d627690d5388ac" - }, - { - "value": 3500000, - "script": "76a91410eecefc7d22d7589b2dd0a6063be45385b3b88d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d8d8e2bd01d7a167f079e505dbe51274400d80e61111b369633f43b8e97359dd", - "witnessHash": "d8d8e2bd01d7a167f079e505dbe51274400d80e61111b369633f43b8e97359dd", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 119, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3d01117d87f43bde531de981d045988390bb8dec86b3d3fdbfca82fb5289c9ee", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 921161636, - "script": "76a914429f17129f6662cb9bc747997b960ef064b506ef88ac", - "coinbase": false, - "hash": "3d01117d87f43bde531de981d045988390bb8dec86b3d3fdbfca82fb5289c9ee", - "index": 0 - }, - "script": "483045022100c01cf39f259ec5b40a3e830598d9aa88ab6bbb9b776dba32740093e87930c9bd022070c62c375b3c7565f993f5f905edac684d7713867e32e8cd54e0a94e2093eaa3012102e252f4413c75591a39036edc5f6f1025ffee158cfa4a897c7ae42a1a2d26844a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 708967389, - "script": "76a914bdf404cd409fe82bdde4e50a7503299276238ce688ac" - }, - { - "value": 212184247, - "script": "76a9146cc220e8c0a83d3de0e4e01bcd075b0190feaa1088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "025ca1879dcc15bc0eaedf69d3a4127d39bd03418da7f5a956ee09be14bfd0cc", - "witnessHash": "025ca1879dcc15bc0eaedf69d3a4127d39bd03418da7f5a956ee09be14bfd0cc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 120, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "948117ebd1ede15bdf26779f35b062261e72054329fa4eca8763456ee84e194a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 878476079, - "script": "76a9146120cb5ea2aedbb9bfcba48d70a2c0cb1ea5170988ac", - "coinbase": false, - "hash": "948117ebd1ede15bdf26779f35b062261e72054329fa4eca8763456ee84e194a", - "index": 0 - }, - "script": "48304502210092e071e181d11f038b1ba48f053fbd8736c6379bf7e3d05db6e12c6df561cb3c0220047383203d27e429061c7b9557d7ec6e8780bc86a0663207c5adc5a1ecc99a9c01210311685e3a193ad4a75ec742b0dea8d3f0e8c72b327269a6098a870ad0fee05e6b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1715248, - "script": "76a9149fffab0d97979db0933ef922a1cf90c262d6d1c088ac" - }, - { - "value": 876750831, - "script": "76a9148d234ace35a9af9a886c9d7bf0cba7a80df9defd88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "82b9a9fd44ce6ade38e71be6e636b8ec4761e7111307c75f48cdb4a8efddd982", - "witnessHash": "82b9a9fd44ce6ade38e71be6e636b8ec4761e7111307c75f48cdb4a8efddd982", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 121, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "30c820171b4ba7a94f0b04ebf958e16d261c915067131b782944967914d63e2e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 365612445, - "script": "76a914bb7606670693d589b875c6a507e9671f2321634788ac", - "coinbase": false, - "hash": "30c820171b4ba7a94f0b04ebf958e16d261c915067131b782944967914d63e2e", - "index": 0 - }, - "script": "483045022100d2f98536b73830edf3ba64f3e3261ae9485b5a8b44492a9201278c3b8f82471f022025b0c0d1d640803e17c703b7ada61ea651847543bec7baaf9c5638e9e0ef77eb01210237d27ebdf7fcee25982a3853fb7fea68e2d1253dec7d26f1daa2d013524bfe51", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 360072445, - "script": "76a914f2decf0a9fbb970ad7bc701a1a6df460cc43723988ac" - }, - { - "value": 5530000, - "script": "76a914622ea215dee0c0480d044da98c9c2d51587547b188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "abeba4bc963938410b4cac241654266f8c6e796483f072bdf33fc38813290930", - "witnessHash": "abeba4bc963938410b4cac241654266f8c6e796483f072bdf33fc38813290930", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 122, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "114cefcc8cf9525552a60c0b3470863c492f0eb159bd76ba9151fb603686d8cf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 326196079, - "script": "76a9146df7f5cc117ee10ef69c8206c9bcc22819d640fe88ac", - "coinbase": false, - "hash": "114cefcc8cf9525552a60c0b3470863c492f0eb159bd76ba9151fb603686d8cf", - "index": 0 - }, - "script": "4830450221009892cc9ef59b2ee5aa5b6f6b94258025903e75f44af19a06e9f797706dc07a480220393b0aafcee4b18ffbd09306de626664e26299add3fa1b2ce267411f038468850121029ac29af5eeafb2526cf8df8d0d83cc106de0b8aca920077703af1b1ccb2f2f8d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 325206079, - "script": "76a914644873cafb10630ce8380598087b3967314cd2dc88ac" - }, - { - "value": 980000, - "script": "76a914fe773bbdaad717bbc376d319645ebc2c22bf485d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "540cf35d71838c8239ed9b0055b7b7cd3d50f08552d23043a03356a5c6a9c9f7", - "witnessHash": "540cf35d71838c8239ed9b0055b7b7cd3d50f08552d23043a03356a5c6a9c9f7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 123, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2ec905afa8c922281543c39f1300e7f8dbd6bd933396be2c18dee745b82bcbc7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 123716000, - "script": "76a91437da323633c83a3da46c13a24515e2757244b00b88ac", - "coinbase": false, - "hash": "2ec905afa8c922281543c39f1300e7f8dbd6bd933396be2c18dee745b82bcbc7", - "index": 0 - }, - "script": "4830450221008c52420e2f9ae40bfa9ac6ea9cf621f3bfc2f428071b5c25bd77cd984f70a9bc02203390d4e1bd4ee31998592f1e974a1cda87753c1f98427beb76bf3272deab48cb01210278e68175f248c9a09199ba996ffac5b4caf4e07f2a20171d4f97e2675de54682", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1064000, - "script": "76a9145c0510aafe1a14327ec7bfd75977811596adc60288ac" - }, - { - "value": 122642000, - "script": "76a9142ca7d745a329e49a7da76f041cca7fe41b92ca0488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "25298fd74f336429d7d567662b5597ef7c22cea1d7c9042fa16b55e0496f5c9f", - "witnessHash": "25298fd74f336429d7d567662b5597ef7c22cea1d7c9042fa16b55e0496f5c9f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 124, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "90a92318e39ed1a50c5a00bdb156a26bc4a0f99a4c54a367efbf6a697cb4dc47", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 475110625, - "script": "76a9142f1c43c1ae88eb5fdf25829007a1592b076352dc88ac", - "coinbase": false, - "hash": "90a92318e39ed1a50c5a00bdb156a26bc4a0f99a4c54a367efbf6a697cb4dc47", - "index": 1 - }, - "script": "483045022100ea8f50c5450e0969a9d5021f90e11a576a08e7349893bf3b773fe489ab645fa802202e2235272197f9285c3dc495ac6db54d9b579d937afe55d45cd779cb62cd74ca01210261a029c1259f827e1254fca34348f6de0ecf4944780a917f45c446953f361c47", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 35462, - "script": "76a914cc39ce08c2c781772178fa386f894e83261dca6688ac" - }, - { - "value": 475065163, - "script": "76a9142f1c43c1ae88eb5fdf25829007a1592b076352dc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "af1f05a19daeef6aea64ae1110d5e1f208194edbc1f58fe8d1c547637987df6c", - "witnessHash": "af1f05a19daeef6aea64ae1110d5e1f208194edbc1f58fe8d1c547637987df6c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 125, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d7d0a9c986a8feebeef215ff8ddc866de509efb9cf1760ab42674d101ba3a9f6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 467133500, - "script": "76a9145d7a7589f40cc1a3e09c970051c074cf1f0e333288ac", - "coinbase": false, - "hash": "d7d0a9c986a8feebeef215ff8ddc866de509efb9cf1760ab42674d101ba3a9f6", - "index": 0 - }, - "script": "483045022100e8d9c9efcb09697bd486be09a3dd429c00050e3f0a195b7cbe33aea0378ff7ea022025e845766caf9d89ffeb7fc6ad559f399d3a8b98bdbe8fc70e9988dbea4f2d480121028bb0f1d451553294512fa6c32d0b40f6319d64935b00ae66ddbff907d11711d4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 451423500, - "script": "76a9143f5ea67094ae4ad73fc9b940433369b3cc7db4af88ac" - }, - { - "value": 15700000, - "script": "76a9149991ad9699a1ac17518cf57c35ed1b3b936f373f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "05470be871fea368454689b1cac8cbeb801146808fa267564842dc6f07e086fc", - "witnessHash": "05470be871fea368454689b1cac8cbeb801146808fa267564842dc6f07e086fc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 126, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7c0f83824fc1e85e8f6b0c69e1fb86c8366b3828545e551b10dba64295c470ab", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 231490000, - "script": "76a914c356e37b46c415c77524148184629acd27c48b6d88ac", - "coinbase": false, - "hash": "7c0f83824fc1e85e8f6b0c69e1fb86c8366b3828545e551b10dba64295c470ab", - "index": 0 - }, - "script": "483045022100da740703556053f81776a2063b824fdd3632f339c768c3d4e3ff3a835b6443ec0220747e7ab6fa48d35788fd6eb172ccd02f8b711db79f6e05572c580ff52557d29f012102bdd58ba4a831882b67932d12cdd3b76b2512d4549d8430bd191b69ba2d07f30e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 201118190, - "script": "76a914bb629bd36fb89d655a4106b60b289ee4bf2063da88ac" - }, - { - "value": 30361810, - "script": "76a91461c53d6d41cd33e021398ccd1ff6fa410a78001188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7945d0782a1a9d548a42e32280229fec6d4d3bf197c300062a2a954eb3c081da", - "witnessHash": "7945d0782a1a9d548a42e32280229fec6d4d3bf197c300062a2a954eb3c081da", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 127, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e3f49d4bda10db46e89f69f5412f7bf845b6fc805232d7ca480da8bf03890207", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299922, - "value": 4225346, - "script": "76a914c300e954e8f17dc1d96dc6bedb473b683e94adb288ac", - "coinbase": false, - "hash": "e3f49d4bda10db46e89f69f5412f7bf845b6fc805232d7ca480da8bf03890207", - "index": 0 - }, - "script": "48304502210094fe73c288d4b44ae6a325ed5e98a44268fd9921c5c10e5da61eb276fb7fb5a102204cbccf48337f3abf75634fb5553d2ad987d2f234e497759109ea5ef07318e5ee012102327831951be803f1591e3f1768aca06d85b11acd81315016307c4af79fba354f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2579629, - "script": "76a914556744fbef0ba8f2aa9eb6fe555ce8394517dbc088ac" - }, - { - "value": 1635717, - "script": "76a914ba2e895905783181b2c7180115ece58345f3c4d588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "db0c982357c85ecaf7cfaec6da31a54afeed99771fe360c192df666d0e878dc0", - "witnessHash": "db0c982357c85ecaf7cfaec6da31a54afeed99771fe360c192df666d0e878dc0", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 128, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "31357e6c9b57fdd28a5030a9df0654f679551a20fd483d5c166a657fc8d2d61f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 210790000, - "script": "76a9143bc1c12570e035cbb69dd5ace0d8932255b146d088ac", - "coinbase": false, - "hash": "31357e6c9b57fdd28a5030a9df0654f679551a20fd483d5c166a657fc8d2d61f", - "index": 1 - }, - "script": "483045022100fa3a0ac14816dc018bb801c786a87205b530dc6bdcab8ec22b201785a9db831802202fb501dd43ececd778f5014a4e4ddf27b77e81ec8280622bea31d25a17dc80a6012102bdb7d7796c60c52817884c577abe26111bd13b52469064d938716e42be1facce", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1458495, - "script": "76a9144991f6e4fe0d10ef9a0ed0828dd90837269b334c88ac" - }, - { - "value": 209321505, - "script": "76a914a333229703b87d74fd360e73f964535dace8da6788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c05f1ad2184be66054d3d09ef6d74a67498fd4247d9894c9e55bb43d935096c4", - "witnessHash": "c05f1ad2184be66054d3d09ef6d74a67498fd4247d9894c9e55bb43d935096c4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 129, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "80642df03ed20013e4d1b5ba006540095b8f7b868801bdf52bc373a068ce00ff", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 69900000, - "script": "76a9148e5f8ae50b6f1c5baeb3863956ef950a6a0889b488ac", - "coinbase": false, - "hash": "80642df03ed20013e4d1b5ba006540095b8f7b868801bdf52bc373a068ce00ff", - "index": 0 - }, - "script": "483045022100ea6224cf34debbfa7cf067a2d010bc69d2b848dea436cb796084e432a9c14d5d02202256911e39454f805ec16d7e3178d8a229e2990c6871ad2e590d804ae1e1e384012102fe217898e8440eb1e2d8811cde22650588132e4f13ac0dc747fdebb037d461ba", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 22625980, - "script": "76a9144424bc3bf52cecdea9f2fed55d12cc9788bca6dc88ac" - }, - { - "value": 47264020, - "script": "76a914309cd7ab88e99569759f018213a2d9e32f9d828a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "007ccea62d7df2e6df491763dc9ab00ffffed6a01d3058a63085558dd598338f", - "witnessHash": "007ccea62d7df2e6df491763dc9ab00ffffed6a01d3058a63085558dd598338f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 130, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "de4120a7ddefa96e9ab365ab82de882aadbd2aa663e3eeda6d826ddd6ccd7478", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 205862481, - "script": "76a9147b6e7199ac1308b6e41f700b0000a89c3c1f6ba388ac", - "coinbase": false, - "hash": "de4120a7ddefa96e9ab365ab82de882aadbd2aa663e3eeda6d826ddd6ccd7478", - "index": 1 - }, - "script": "483045022100a294518a00b6a011d6787e775b060f906da9e0b14488df241e9d672452e6f055022016c47184b015dbed0b5d6ee274eaf0b7b109eb8cedee29d181a729c0e77b9a55012102f8917745609fd8ca4378f90a1bc03d02ff75a5bb6ca33db195623917e93b2a6a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 66312771, - "script": "76a914e0c29c27e6dc7ac5fd375bce2dcf9f7a574881db88ac" - }, - { - "value": 139539710, - "script": "76a914f85effd88fc5fa2e78cd610c0b6012c56c44243f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5dfa9be4bd5aaa203daa8d17a605dc10cf7fdc95c6b1b97f6e2dc634e2410ae7", - "witnessHash": "5dfa9be4bd5aaa203daa8d17a605dc10cf7fdc95c6b1b97f6e2dc634e2410ae7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 131, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1dd8eb978892110698dc7bb3e77e95ae20e635e11f1b9e7b56549218ed2083dd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 399779700, - "script": "76a9141886e16d4f7162c46d7347be3e4c6cd318ac697888ac", - "coinbase": false, - "hash": "1dd8eb978892110698dc7bb3e77e95ae20e635e11f1b9e7b56549218ed2083dd", - "index": 0 - }, - "script": "483045022100eca8d8d0d7fd9e5f30d4d42b06e4cb3149ddd0400eb1f49d25f60e6819fff23a022064a97aa4611830b4d526a697246bd7e6e9febfc755a1a6df8d1a1c1c7dbc3c400121038572c63dff72222aab0dc76c2fcbdaafc9fb63842c6f7e46cef41a46583772d7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7080000, - "script": "76a914f8c708febae1879b2413814316cf9400c7134cd788ac" - }, - { - "value": 392689700, - "script": "76a9141e52bc214929dda07713fb8fa277f2f7c6d48da388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "88db7a1cb1f1620b83e62f72ed9cff9a8ccffa9c22dafd5dacc3f62a6f6b226a", - "witnessHash": "88db7a1cb1f1620b83e62f72ed9cff9a8ccffa9c22dafd5dacc3f62a6f6b226a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 132, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a462d1100e672ad9455ed127ab5c8819937ed49fc6d1961fb1260112ef66c465", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 150000000, - "script": "76a914a55ad4f5a3c3c039d06f0212cd7e4adfeeb6577c88ac", - "coinbase": false, - "hash": "a462d1100e672ad9455ed127ab5c8819937ed49fc6d1961fb1260112ef66c465", - "index": 0 - }, - "script": "483045022100cf4f1dda91df0963732d948dd3d4e6a84e0393be3d5ce1319c2de8a58595b0110220750798cf243abaf1771ad69551e527261f8b9a39fda993d002ca027a465b0693012102f5b3a0fbfd938fceb56afbf1b74b3a09be84563aef7dcd7a6c000761297c5f3e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 50000000, - "script": "76a9142c69cf8cb7d7c852a51628be57cf4a15b8e6a7ab88ac" - }, - { - "value": 99990000, - "script": "76a914a55ad4f5a3c3c039d06f0212cd7e4adfeeb6577c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "96cc2f4cf3c9947eacad94b20a004c46dfaaabba5131aabf05b1bbe161ba62b4", - "witnessHash": "96cc2f4cf3c9947eacad94b20a004c46dfaaabba5131aabf05b1bbe161ba62b4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 133, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5afc26246df5de615a11e8b4e25e07570e172fe98d0661c1cc16723bcec8c919", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 143560000, - "script": "76a91422b2379e489cf3b47a7dabb7f232de90b632c85888ac", - "coinbase": false, - "hash": "5afc26246df5de615a11e8b4e25e07570e172fe98d0661c1cc16723bcec8c919", - "index": 1 - }, - "script": "483045022100aaa002f4a789f26d9009391e8b1018ada3df190d8a69918fe9e66f3898f67db60220583e074f66b1d335f5ea345fc6b831ecc2432f4617a80c26b22df64a1874237e0121029eb08c24bd200683f6e5a1b5baba467ab6ffd651134ae51c41f156c3c6a3b46c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 43550000, - "script": "76a91416e36b218930262979ccc16bbed240f2cec04bef88ac" - }, - { - "value": 100000000, - "script": "76a914b198c8d267a0840436bfb076ac0e6ca1ede09d1288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "011bcd0073bc572ee5602b2729729c4040423691d3c2ed62e1da0976993f51fa", - "witnessHash": "011bcd0073bc572ee5602b2729729c4040423691d3c2ed62e1da0976993f51fa", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 134, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e67fc66bffe979913a3bc509753fc4ed0b75f1a00278d156d85599a555117fcf", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 95520000, - "script": "76a9141a3d39c34743845d918d3efc212f9d718c591c4788ac", - "coinbase": false, - "hash": "e67fc66bffe979913a3bc509753fc4ed0b75f1a00278d156d85599a555117fcf", - "index": 1 - }, - "script": "4830450220075ef5b983af4dcd467e0f473ca9fe50d97d40934dc4bf698bce56509eb30cdf022100efa55744a1405891f2f1bc66ed8f6b7ecc3b9628d1c595f343265185539217ef01210274ebe164c6ad24bc7665e2a2bc702fa7c0f1c781eb979819e4752e6ff3a216c7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 75300000, - "script": "76a914a3f275ffdf4b8827ba03179d4727f9b595096c6288ac" - }, - { - "value": 20210000, - "script": "76a914b7a4d08d690909dc7fa7b48ea01b9bb97dbef82388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3ae96ed7dcf039b0f99e4a1412cfcf173ca9a402bb83b2a5dba8063a41231076", - "witnessHash": "3ae96ed7dcf039b0f99e4a1412cfcf173ca9a402bb83b2a5dba8063a41231076", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 135, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c1ea2749b5867344ce95995296a4fff0e73b70f81920e4575ccf0d55009cdbcc", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 590000, - "script": "76a91486bee458d3d0ceaec4616c0852c1c403754ff1f688ac", - "coinbase": false, - "hash": "c1ea2749b5867344ce95995296a4fff0e73b70f81920e4575ccf0d55009cdbcc", - "index": 1 - }, - "script": "483045022100c99c61da118ee7501d213f2d0fc4d4fcccf8d22ff68067ecd15840e9010f2cf402201d87e325e967c74b63a879bb6e31a6c06766250574e9003e16e9b88c4ed1cea7012102feb0014d4cb9cce60041f6b7acae26f1a61b66efff58fe884c2306e1c74e8c41", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 80000, - "script": "76a914481abefcdee6df84d9452b866dbe1cb696574c7088ac" - }, - { - "value": 500000, - "script": "76a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0d94d164917712d1662110688eac29016529418acdc21e2898e491f91c203646", - "witnessHash": "0d94d164917712d1662110688eac29016529418acdc21e2898e491f91c203646", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 136, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fa13f147973991d7ba3b47997f37b2e6abca3689d1b138789bd47086002f7390", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 26363113, - "script": "76a91433171aa816b018a57f90ee0a4d25208a0737b36988ac", - "coinbase": false, - "hash": "fa13f147973991d7ba3b47997f37b2e6abca3689d1b138789bd47086002f7390", - "index": 1 - }, - "script": "483045022100b1b3dad174bbf04e4a15fcb3c6454ee383899e2440779893dfbf657935008ba902200568d15b51154a01e5f795ba4c0b6ed615908ab166d211e46e9fca04df075375012102d525f952cb91dfd479113e70cc5294947cded6724edcdef4e04adab8d4642a3d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1653113, - "script": "76a914d1730be8ac0a7f0a9410604560de8556f4bb1f6188ac" - }, - { - "value": 24700000, - "script": "76a914e09c0218f6d09c0773c8fb91097105d1622b3e0888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cf4cc8654d4fc0b4f1d1c01c1535f1a91197a0cbeffcebda665819cd5603e02c", - "witnessHash": "cf4cc8654d4fc0b4f1d1c01c1535f1a91197a0cbeffcebda665819cd5603e02c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 137, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "50ee9c8a6ec58473192a88262dfbc0ba8ccd0d56c621e79963adf7da8f485002", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 60793935, - "script": "76a914979bc4e42171994868616577179e391c0be0c21d88ac", - "coinbase": false, - "hash": "50ee9c8a6ec58473192a88262dfbc0ba8ccd0d56c621e79963adf7da8f485002", - "index": 1 - }, - "script": "483045022100eee931a2761ce6d26c42eba8ec702d54b44df6d520a746a2c6a0a1e5b8d7c30f02206c910068a7c21dd795591aa41049902dd4b6d219a97aa7599dd8d87cfd0a040e0121035671f00704f53da4859708e0a25a44ee542f4d3852561d2a935387045ed2474c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 48052268, - "script": "76a9142b515b36dd33b1f9e8513cf175e2ee7a17a2bc5888ac" - }, - { - "value": 12731667, - "script": "76a914c6d35f91f55fb689a852fd23a11818a2ffa50ba388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4ae24fad4d93596ed26857553bbb4b5f09cc6be644e02478f484665f87a61408", - "witnessHash": "4ae24fad4d93596ed26857553bbb4b5f09cc6be644e02478f484665f87a61408", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 138, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b880048c3dcc549b977b81c33b55efa0fe0b74bcf1c8e38035c8a0afc89874c5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 88687437, - "script": "76a91445b22f0ed074e0f86a3f0c51f76e5b1fa73467ef88ac", - "coinbase": false, - "hash": "b880048c3dcc549b977b81c33b55efa0fe0b74bcf1c8e38035c8a0afc89874c5", - "index": 0 - }, - "script": "48304502210081acb424a99cc743d87c6af77d3ae204c9b3a2cae9c0ed7853c5cd6c63120e510220271cd5655c06593e35c4c8c45da08555a5cfda11ba011c4d5d80bb4936cbe2b80121032e20fa42f35a05b14cd29d3ca490521949a01675f57f453e52bd232dffe65b56", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 88526437, - "script": "76a914ba4278c622e3300df7da3ab66954e1122bd066d588ac" - }, - { - "value": 151000, - "script": "76a9145c84ebab10bdf995178e972e5aac94c6b1c5405688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "36f2aaa5964739ab2e7ddbb2bfe90a667497efc83817bebb72890063b8e5fa91", - "witnessHash": "36f2aaa5964739ab2e7ddbb2bfe90a667497efc83817bebb72890063b8e5fa91", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 139, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3e5749e6889c19b82d88f4aef9b04fcb2abbed892d473f09b4f41733fb7b93f4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 3570000, - "script": "76a91423c3bc0b201fb102a802e93ff157308765178e8588ac", - "coinbase": false, - "hash": "3e5749e6889c19b82d88f4aef9b04fcb2abbed892d473f09b4f41733fb7b93f4", - "index": 0 - }, - "script": "48304502210088a2811dccd55fbb1ea01a29f1b9cffb24d603530b1de40754eed98d464cc56f0220227946c32ef83247f0b22d7bdb0fe201f9636d382ec455dc275ace83cb1d99790121022e1e13314814ac9218c6ab5b2fe4f3929ede4205add2aee252a736e653f311a8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2410000, - "script": "76a9146b7eab61fcddc4e502ecd3225b793298ca6acd5788ac" - }, - { - "value": 1150000, - "script": "76a914336e756adadb1c91d2db6b7e26a2102109cd043d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2ece7092942c6a30939eefda9ff3f68db838b5cc2d9bc2ecd015ee2b3c17bcfc", - "witnessHash": "2ece7092942c6a30939eefda9ff3f68db838b5cc2d9bc2ecd015ee2b3c17bcfc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 140, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "12c69c3dfcadbcf29f3fbe8e1a207fbfa8f87eb3f26bfc2026f35f6c7c001ee4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 38091480, - "script": "76a9140ae06ad4d415bf488f669ef56297b931eaaa9efa88ac", - "coinbase": false, - "hash": "12c69c3dfcadbcf29f3fbe8e1a207fbfa8f87eb3f26bfc2026f35f6c7c001ee4", - "index": 0 - }, - "script": "483045022100c9f66968bbeafbf063ac5cf45bec5331f403f4673872a2e4ae198447ea6a02d002202d74760bfdbad767837b2258dc805c442733fb3c15069974cca054fb3eb80278012103d597082c4fc9ffa1f74a423a78d9cce0001f17cf88a353d9b717932feceaeb94", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8800000, - "script": "76a91401f6a525989d766b4a0ed8838c7912bc2131d04a88ac" - }, - { - "value": 29281480, - "script": "76a914a2cc2ebeb9b6c8f32ba5d6d23420c4c61dd1e51588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3658036b9851d286a0581ff84e7fa6599669c0fcd08c92c4ff04a5de28b79015", - "witnessHash": "3658036b9851d286a0581ff84e7fa6599669c0fcd08c92c4ff04a5de28b79015", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 141, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "af3e971d70181e802c76b542392d7c0c05f75596a83f537e76e55b7110fe4882", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300022, - "value": 21000000, - "script": "76a914fe33af9594d43e1c16f1b382c9ac55b60c46d96688ac", - "coinbase": false, - "hash": "af3e971d70181e802c76b542392d7c0c05f75596a83f537e76e55b7110fe4882", - "index": 1 - }, - "script": "483045022100d144909357554842622ebde9d2a19fb0bc53bc1850d545a8144cfdf70114542d02204c0bfc7cd0e5d077e0e3656f8f47e63cc20c3c4872c316a506d18aedb0331f380121037de6056f075d3970281f4241de4045e880c4ab5af575b51ad9eca7e2ed1d3740", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11174682, - "script": "76a914c3a4ff9650ba537db1da2828babb6b7ae52f982a88ac" - }, - { - "value": 9815318, - "script": "76a9146e504490c8329a11e4a26afb4f530a1b98d5ee5388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "419ac9f292ad6d981f143ba747826d33ad03b626c3da0fa26bbf259096cb8ff9", - "witnessHash": "419ac9f292ad6d981f143ba747826d33ad03b626c3da0fa26bbf259096cb8ff9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 142, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0cad24e768ba049aac88cf1203571527711e84a46d41398a0867ea7f9deb0b63", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 29100000, - "script": "76a9148b7d7a6b579fadf4d26316915b063ae39a3e088288ac", - "coinbase": false, - "hash": "0cad24e768ba049aac88cf1203571527711e84a46d41398a0867ea7f9deb0b63", - "index": 0 - }, - "script": "483045022100e33485b974166e9139a5a6624f6359fc01769f9ad78d5bf4937c2568669685ea022036bb410e5fbba5ca2f996ed0ede2256c14ab6344c23816a9f428f72bb0e30b7301210314de589faa38054bb7845f0100f097fa49ffc75ceffd428970e5b06daf768ef4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 28940000, - "script": "76a9144721c8368148f17a251227ad9d31ca2f264d4c4c88ac" - }, - { - "value": 150000, - "script": "76a9145c84ebab10bdf995178e972e5aac94c6b1c5405688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7c9f88910e511cb6414351bfeadea40cfd68d9176679732845ac7afab7462cd8", - "witnessHash": "7c9f88910e511cb6414351bfeadea40cfd68d9176679732845ac7afab7462cd8", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 143, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "91bf065d7d19d4b0ef80d176995af9da89fcd23ccc749b6b4faf432570e7b739", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 8904376, - "script": "76a9143c19c149c129849d4b7ec62bcbd6dbcc663eedc788ac", - "coinbase": false, - "hash": "91bf065d7d19d4b0ef80d176995af9da89fcd23ccc749b6b4faf432570e7b739", - "index": 1 - }, - "script": "483045022100989dc049381c96bc9c945c4621e9b57956175d27ca36af90a18681fea20d50b7022052447d27932f8aa8efd13ab80381e7bca6cb72f404b36e4d2d28bb29a13ce9c1012103636d22c90d49b63fe925d6b96310d152f9ddeb30b6889dc55936351c84ca3e4f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1006560, - "script": "76a9145f2893e207f963ba4d0144384891cfe290c2d43988ac" - }, - { - "value": 7887816, - "script": "76a9147554f3876b5a13227e2acb68a25f133c1b0134dd88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "61efbf3fb97d849909b0d2fdd9e75da87d5cb94e7725d2f9f00c4825600898af", - "witnessHash": "61efbf3fb97d849909b0d2fdd9e75da87d5cb94e7725d2f9f00c4825600898af", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 144, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "36286f72da6f3c77c5eab676fc24836008b76d2243f5fe3f4865c5995f72295a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 46296643, - "script": "76a914281f87b3e2397339fe269d825adeb4e3bc4c2eb688ac", - "coinbase": false, - "hash": "36286f72da6f3c77c5eab676fc24836008b76d2243f5fe3f4865c5995f72295a", - "index": 1 - }, - "script": "48304502210080c35b0cbdbd44afadae10dea4c8c7549a33627dc5715e3f337cbc93e683410b02203b120cc2d42735aff407d2ffa360c28c0f1d9f604ca55a8aacd39dae95df12cd012103cb2d0a288c1f6a0588517193fe64847c06c309339d0d35f2243168b54641be98", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 44507393, - "script": "76a914cfe7261893c4a22d71db113ec35983c50e11265f88ac" - }, - { - "value": 1779250, - "script": "76a914d49928dcea3d6c6cde622fabcff1255b49b7793788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1fd1ad9b1d533fa11ab9c51e2f3bc0417ac742f6106b991d9a21d81f256e7e2b", - "witnessHash": "1fd1ad9b1d533fa11ab9c51e2f3bc0417ac742f6106b991d9a21d81f256e7e2b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 145, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f8becc3d1c00c2936d09cc5a96da2a86fe65b44ecbfeb4ee8cc6f5513893207a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 30578286, - "script": "76a91474236215830a9c61a7067d2df0b7d91f2431d0a988ac", - "coinbase": false, - "hash": "f8becc3d1c00c2936d09cc5a96da2a86fe65b44ecbfeb4ee8cc6f5513893207a", - "index": 0 - }, - "script": "483045022100ff335e36237a5d3e61c7ef1b7b4250a9369ef398f6692e6db6c95498b940623602206ce773d0449f135df4ce0e9199b77270c4b52fdbf07af4162f20bd360b9c6a80012102641b8b286fb6b836bbe93dc573baebfa7a5aeb8be19262e662c3db39cf847241", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7408286, - "script": "76a914f27c378a9bc367241f582b59506d43e4263df30d88ac" - }, - { - "value": 23160000, - "script": "76a914e231abfc1ef1474431019d9854f1ff2c2b0d315a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d2681ab0e00f8d62081e141eb5c7a36a371f861399205d785afae1b4e07f25cf", - "witnessHash": "d2681ab0e00f8d62081e141eb5c7a36a371f861399205d785afae1b4e07f25cf", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 146, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "19dab3dda7df3ad1d1f6e5951c519208826e0bdce9ec8549345b38c7f1861772", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1996028, - "script": "76a914dec45e657b24c5cb4417bf6b1adbc466677d968d88ac", - "coinbase": false, - "hash": "19dab3dda7df3ad1d1f6e5951c519208826e0bdce9ec8549345b38c7f1861772", - "index": 1 - }, - "script": "483045022100c1350217c0c13378b8b8ced315b911a4777a98c8465885d44e4cf630b3fe907a0220208f371bb1b83554eb7aa3d94c4778518e09dc12e8cea30873a979bc708f72650121038bce75485d1035cd29e56ae5cedfb2c2bfb44c3037793a622ed231fbddd3f59f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1895351, - "script": "76a9149bf549bbe4f62b0fa6b299ef152d600543920d0088ac" - }, - { - "value": 90677, - "script": "76a91493b80f661275a0e703e6371ea3a9ecf3fdb0756388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "62b3c3a2f4ee940432f367a331eb550006740f510d880afee901bb5e7ef48ac4", - "witnessHash": "62b3c3a2f4ee940432f367a331eb550006740f510d880afee901bb5e7ef48ac4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 147, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "04799828f3fb982473b40d5d6010112324974c8fe2e34de84ce3cecc77536dc1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1900000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "04799828f3fb982473b40d5d6010112324974c8fe2e34de84ce3cecc77536dc1", - "index": 0 - }, - "script": "4830450221008a950eb32132c1967eb4b9a25f46e47578cc2661101f83d7aa5f2c332d979be002201cf8cf33c344be02a74f31bba0bb1061b2663923b33e57055d781c79fe50a453012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1880000, - "script": "76a914fb2cc2d580e8db8440810e9f4ba58ea8f86b59a188ac" - }, - { - "value": 10000, - "script": "76a91447166ecf28460655d16d401dfa58da60b128128a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "77b43a0392931916e1c2c023e7ebdff1a15ebc384b045495be377d60224699df", - "witnessHash": "77b43a0392931916e1c2c023e7ebdff1a15ebc384b045495be377d60224699df", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 148, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "43b1c759dfc954b49ed6d5a34e11d46d4d13c5a0a33cfc699d9dc1f37d273b7d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 807570, - "script": "76a914c23907eeb94622657f37cf60f79dd2c64a364a5a88ac", - "coinbase": false, - "hash": "43b1c759dfc954b49ed6d5a34e11d46d4d13c5a0a33cfc699d9dc1f37d273b7d", - "index": 1 - }, - "script": "483045022100f2b064ad5e12f43d95916c13b6b3ac4ac1e8ab9323bf9ad12541fb08e2cecf1f02204b462bbb478909ef5cbf023563e09629c8b3c697ecb9c1f5e5eb9247624646c1012103a664dd4c8d0e04702a6ef31416104884bbbfcae2e0e931a07bd5a7261b4291db", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 775450, - "script": "76a914105cd2a16e9d91e19607ea9f005192a3a5c7b24488ac" - }, - { - "value": 22120, - "script": "76a914adf238c3e7a11784a44c7fce46ab9b483a61267a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "490b92a7fa735e433c89a3bc928b65d6192b403a2e96c5b6baed428b773a1f76", - "witnessHash": "490b92a7fa735e433c89a3bc928b65d6192b403a2e96c5b6baed428b773a1f76", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 149, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0ff72c71ba007359c24cf2f26f6ed9263a5037cfc06707f6d881aa6895922b06", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 700000, - "script": "76a9142f3fcdd0d9f2f5203cacded82512902d58f656cf88ac", - "coinbase": false, - "hash": "0ff72c71ba007359c24cf2f26f6ed9263a5037cfc06707f6d881aa6895922b06", - "index": 0 - }, - "script": "483045022100d131b2d8c489b1a4393c8d74bff0775ca5a8d19a96c0b3e2584140f50900ff5e02202b25e4dd1e9e8893092f3322102eefe7a1dbf68e2f570fb45a380d7e18bdd81301210273f874ebd89d0e3bca6cecdad337ea534a86f871a9292b3fed96aba302b3a217", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a914e303eaaeeaf1b833841b51330b7199ade383511e88ac" - }, - { - "value": 590000, - "script": "76a9142f3fcdd0d9f2f5203cacded82512902d58f656cf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5a2fbbc003daeae5816fc2d47261f48a4fd8ccca9f15913e5c33b3a16dc7dd12", - "witnessHash": "5a2fbbc003daeae5816fc2d47261f48a4fd8ccca9f15913e5c33b3a16dc7dd12", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 150, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f725c8db39a2724095db54b75a038d6c660d82596c004305692179dda1924287", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 495857, - "script": "76a914f49dd072583255ec00e81b621a2e7a2eb338028088ac", - "coinbase": false, - "hash": "f725c8db39a2724095db54b75a038d6c660d82596c004305692179dda1924287", - "index": 1 - }, - "script": "483045022100b12afcf7987b713715bfeda13aaa2a784b6c4d6f594f4f6419aacaa1c89a9fe102200e9be3c76d2417f7039835e01fda4afc56bcdeb7719b143d3c1f7699ef725d49012102a80e273aee387e15f52e72cd970206b9f76cff166117e3eed335945cd7743d47", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 212400, - "script": "76a9141a1c313aa0b15d36a4eb60114e618b334857959388ac" - }, - { - "value": 273457, - "script": "76a914443486909ed6ae071b5437cd153dd6a14c6c143e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4a3ac6451164cc8329f3c1a7212d87b38ea098db1774572447ccc74a005e4067", - "witnessHash": "4a3ac6451164cc8329f3c1a7212d87b38ea098db1774572447ccc74a005e4067", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 151, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "332ff53505ed943d8e4561d40561ec7d0c96cd27a8aded0f126c05ebdf532dd1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1055372884, - "script": "76a9141e3b2f1b6824921e7225db75c7ec56d627690d5388ac", - "coinbase": false, - "hash": "332ff53505ed943d8e4561d40561ec7d0c96cd27a8aded0f126c05ebdf532dd1", - "index": 0 - }, - "script": "483045022100be7d533a539d358bb6aa90878d94383e2417ccae547cf35d64952401350e768c02202983344076e454795214c6c2985430db471b4a4cdac25e22bac8d0921d8e3d4a01210290a9f35f79d3995eedf67ddff8034cdc348f471411bb41f555f6271690430890", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1050501974, - "script": "76a91405f91aadc4f58e2302a5f7ffdfa3eb78dd747a4688ac" - }, - { - "value": 4860910, - "script": "76a9140e6a688db0c439633d237a221898c241ae3aed7888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "305fc353044744ecdd266ff873f779a814f77eaa071b54ae276b5bb6af1b4807", - "witnessHash": "305fc353044744ecdd266ff873f779a814f77eaa071b54ae276b5bb6af1b4807", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 152, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "88db7a1cb1f1620b83e62f72ed9cff9a8ccffa9c22dafd5dacc3f62a6f6b226a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 99990000, - "script": "76a914a55ad4f5a3c3c039d06f0212cd7e4adfeeb6577c88ac", - "coinbase": false, - "hash": "88db7a1cb1f1620b83e62f72ed9cff9a8ccffa9c22dafd5dacc3f62a6f6b226a", - "index": 1 - }, - "script": "483045022100bb6aa3a3d27ef61b8b666cc0e8758643188d44274906e5fb436caed0444deca102203076505bacf68fba1d29244bce720609de8945625f97a4f4464cc1338f96b79b012102f5b3a0fbfd938fceb56afbf1b74b3a09be84563aef7dcd7a6c000761297c5f3e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 50000000, - "script": "76a9142c69cf8cb7d7c852a51628be57cf4a15b8e6a7ab88ac" - }, - { - "value": 49980000, - "script": "76a914a55ad4f5a3c3c039d06f0212cd7e4adfeeb6577c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5205823f8e9a134eb808b54bab41c21fe927847ce63cfd9b31de3c5bccdb9966", - "witnessHash": "5205823f8e9a134eb808b54bab41c21fe927847ce63cfd9b31de3c5bccdb9966", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 153, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "de7af49dacf0e9f40a9f5fd3ffa198bfbd267516eb3fdd1be6fb5b46381e1dfc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299905, - "value": 600000000, - "script": "76a914569e37008501ddc6dc9830800c204aaf12354c9b88ac", - "coinbase": false, - "hash": "de7af49dacf0e9f40a9f5fd3ffa198bfbd267516eb3fdd1be6fb5b46381e1dfc", - "index": 0 - }, - "script": "493046022100d3cb68657016c71404aa71e00a1e7547c31cf2066de5d23aed6bc3ad70743aa1022100c6119a41ae7b92a35824691c76864e22dc96061675e5edc67b53d39c175438500121031fe74df1604fdbfa1609f1262e4423a0adb63dfa217e7a6c82f87ea23f440f79", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 316000000, - "script": "76a914514b3f79cac29fb30dc152ffc778b5ba45fbae8e88ac" - }, - { - "value": 283990000, - "script": "76a914569e37008501ddc6dc9830800c204aaf12354c9b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "62827bf546cc3eabd9515eb640af57ef9ab73b6c5ac91858def9e18659cc7e81", - "witnessHash": "62827bf546cc3eabd9515eb640af57ef9ab73b6c5ac91858def9e18659cc7e81", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 154, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5102e561f82e66480c3a2e7c0217d5b2234225dd81936db5f471bc65aa6e8bb7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299951, - "value": 273900000, - "script": "76a91469a74ebebb4e803b03b18ad9a06e8f18de65051488ac", - "coinbase": false, - "hash": "5102e561f82e66480c3a2e7c0217d5b2234225dd81936db5f471bc65aa6e8bb7", - "index": 0 - }, - "script": "4930460221009ddb3effe0f278b69c41eb6a579ada7964b270ecfa2e81258a759c97d7bf0782022100992e4062fb694b3945966874957f3b7e5bdacb73071cf01f53bd86b435073255012102ed86ea5a6271daf8909c75d506dffcc716ec6f4616826a6feccb07b96249186a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 271337000, - "script": "76a914a7ba4217423b24b02c624588c61ab02a351439c888ac" - }, - { - "value": 2553000, - "script": "76a9144aca662eb3cbe6b2a993aea766f67e0aca60878f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d72c504ab4488e4d7ff6f773951fe4a6e079b3637a7a1d64d05d3bf6486dd253", - "witnessHash": "d72c504ab4488e4d7ff6f773951fe4a6e079b3637a7a1d64d05d3bf6486dd253", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 155, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0dd0130ef3c085d83d31c89ebca1b13d552fe7767b0468d468c266c1b48b5a2c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1252517000, - "script": "76a914ed275a32136c0df70e1f77e4f148e6325959c0c088ac", - "coinbase": false, - "hash": "0dd0130ef3c085d83d31c89ebca1b13d552fe7767b0468d468c266c1b48b5a2c", - "index": 1 - }, - "script": "493046022100e3441c8835368120c0af4a887d415f6591a6c23d1db59985451d0bf772878505022100847c99eafd00af601770fafa272fb2058d378902188774a120e64fe9d8a226ea0121029fd45bf29e4611a7f491beec129b48ae052d95f467dbfe85d3b90a26553cb579", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 14195000, - "script": "76a9147ca579ce6ba48f336ab70e5257b475a7fac1a4b588ac" - }, - { - "value": 1238312000, - "script": "76a914cf68471b2e5f3d3941daf946f8d2780f76e36c8a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "974aa1bd33693d8f8188a9a855d964ee9208165226e67ed449aeceef864e4c0a", - "witnessHash": "974aa1bd33693d8f8188a9a855d964ee9208165226e67ed449aeceef864e4c0a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 156, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6ad5464c0fc5f5387b2def24ded155c2880e56a8223b9d04a1078c30b7fde8e0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299768, - "value": 6148600, - "script": "76a914aa214989add45bf61b1231c057987f8a634a476b88ac", - "coinbase": false, - "hash": "6ad5464c0fc5f5387b2def24ded155c2880e56a8223b9d04a1078c30b7fde8e0", - "index": 1 - }, - "script": "493046022100d20e7239b228b162170725ae382bda504556ba3d629e3255ab9b301a94357bbf022100f3b96b40735da40c4d8afd6912970d75d677c8edc8a97014790854102da44d50012102eb589b2d02e9c47434fd0b90255d4cba3d7c971eb2569a72ff4c1e6920b8758c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3697200, - "script": "76a914dc1fa3cc6d966f249db94ce7d206d6b10b2e975288ac" - }, - { - "value": 2441400, - "script": "76a91419923565ddd46e8b6a5fd4cabaabaec40bab2a1788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "de1a8d84b9c425f7191cb734b3f0be18acb8afcb7dff7b5bdc91effee19ff646", - "witnessHash": "de1a8d84b9c425f7191cb734b3f0be18acb8afcb7dff7b5bdc91effee19ff646", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 157, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c9a888edfa39b0a7b6ba9f7c89971bf2650e5f33081c3c96a8ea863405958b38", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299892, - "value": 1240000, - "script": "76a914aa5ba3f1b5fcd61d8209297ea58123d0bbec9a6788ac", - "coinbase": false, - "hash": "c9a888edfa39b0a7b6ba9f7c89971bf2650e5f33081c3c96a8ea863405958b38", - "index": 0 - }, - "script": "4930460221008f8e21d097b8c9cbca7abf54e4fe1763fa73699bdda280f54978c18579db2300022100c2117dbc86d75d3e0322ecff86eb3911f6bf7b9afd57664de9373d809eabf96b012103b6d06ed95e7ed35d15ceba838f7d20d498a33e74f158c1230ec7cabd58452178", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 30000, - "script": "76a91440abf94ab4e4de52c88e4abd0b150b1ace4cfe9288ac" - }, - { - "value": 1200000, - "script": "76a9140fa393ca4a27c497611d404e707f60c2efea25fe88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "111a6b5b711b7937de6d7e861aeee54f26b8e78d8cc6ae2051e8bd75b7601c18", - "witnessHash": "111a6b5b711b7937de6d7e861aeee54f26b8e78d8cc6ae2051e8bd75b7601c18", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 158, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "82f1e01432c16da6c7d5bbdf45e8c9074089550d3e7c5d054f61cb078f1bdb9a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 7720000, - "script": "76a914875cd5faa8ebec5fe04fe1ef5c5c155d0171fa4f88ac", - "coinbase": false, - "hash": "82f1e01432c16da6c7d5bbdf45e8c9074089550d3e7c5d054f61cb078f1bdb9a", - "index": 0 - }, - "script": "493046022100c64dc9440d9597e121342fdfac4244110207319edaf4ded38fb479e8803ae986022100d8b9fd756a4693adf364eeb119b3a203ae2f300f5b94a91be10d390b149895aa012103316929d1d51c9f1533b68103f1f4c3874f5f426bfd69d28ffca5527689c97256", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1220000, - "script": "76a9146471610bd893181e954c40fcf619b8c4e1408fd588ac" - }, - { - "value": 6490000, - "script": "76a914917b759dc4077dcaa9f2a86fc7e7444c55c3d63888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "780944f54c90fe00886f0bbd358376a9de2a57c87716da03f60a942d5daecd13", - "witnessHash": "780944f54c90fe00886f0bbd358376a9de2a57c87716da03f60a942d5daecd13", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 159, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8d4daa22c002f63d5033a2366281dff09c05210359bedf81c08049a9484132ac", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 55318444, - "script": "76a91417139b8a0ab9e3553bcc8dfcc2a5061129b9d29988ac", - "coinbase": false, - "hash": "8d4daa22c002f63d5033a2366281dff09c05210359bedf81c08049a9484132ac", - "index": 1 - }, - "script": "4930460221009997e7347c77e35f7e25f2115f9a23c88326f61f215cf30a7a8accaa4c099feb0221009cdcd904a7c26719962f7652da2d8e83a2ffbdd6c14f780575b19904bbe01b650121024edc8447ce2f5a4b946d350a972587f16a751bb8def369102ba51359c44e3458", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 30808444, - "script": "76a914dc12287b41c4fd36733e758426a8209644b1e93988ac" - }, - { - "value": 24500000, - "script": "76a9148b33f9706422a40b5c2f30820a806c5f1063af7f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e30fbf462de5f4f8840caec49d208ed4a86e18ce2a0b0b15c48dcf9291332417", - "witnessHash": "e30fbf462de5f4f8840caec49d208ed4a86e18ce2a0b0b15c48dcf9291332417", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 160, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "af85dede2ad33f3eb61d88e2d4e4cd5e1971985e55a6ddb4f2000c62b4c98ed7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 43212404, - "script": "76a91406eb8d6259cf63a794f14244399a023a6913c1d688ac", - "coinbase": false, - "hash": "af85dede2ad33f3eb61d88e2d4e4cd5e1971985e55a6ddb4f2000c62b4c98ed7", - "index": 0 - }, - "script": "493046022100b54d0856455fafd2cc1f748cae5d4ae74d4f85842f0aefb10f90c022ce7e17a8022100e584dc884600f5ec674ca512e735f01693f8307ce8c5b3b07b217bb72a595cb101210384aeb2206296701df1deef11660b870e2e202ac40ea8d49515d3db0965df7e3f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 652913, - "script": "76a91486a116e177b17184f7b599ae4d1c2d2d3a10271488ac" - }, - { - "value": 42549491, - "script": "76a914dfa2c032c0591ff92212e00270950e8aef4b9eb488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fa4aa69f8a65b901e62b2e01a6e7bce7a30645c4f7b9206c744918b153f7a1ba", - "witnessHash": "fa4aa69f8a65b901e62b2e01a6e7bce7a30645c4f7b9206c744918b153f7a1ba", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 161, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fd2a8429137a8e08b48936538a7445499fa98e13a955cbb082efdcef08550ec9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 35690000, - "script": "76a9142b3a3ab6065de594fd0e4b99fcf214abc4c7a00988ac", - "coinbase": false, - "hash": "fd2a8429137a8e08b48936538a7445499fa98e13a955cbb082efdcef08550ec9", - "index": 1 - }, - "script": "493046022100f2809c1882bf0aae5fad23a1c155271843176143f8da8492b72e92789796fbc60221008df1f6236a5cbf8734b49a424e3ac9a7ccf32610155fa7e2b2bbed0c52487f8c0121037c833d3fe3363ea1ed7e3a3d01f5143ab4a2d02ff0a204d6328c9aa5781744cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 13436715, - "script": "76a914ca76510afee7d4277915839a2979454df70c57d988ac" - }, - { - "value": 22243285, - "script": "76a9142b3a3ab6065de594fd0e4b99fcf214abc4c7a00988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2c08540c8470b6e4c25c7c2f907f0f88949d2b8e3c7b2504f90f421b20ca1035", - "witnessHash": "2c08540c8470b6e4c25c7c2f907f0f88949d2b8e3c7b2504f90f421b20ca1035", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 162, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "aae42250a170a85bdaef6f487ac16942908b0cd3fd7d2f091d453b7def0f20f9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1536343, - "script": "76a9149191c7262b8d144940d223b9ab81998656f3a91388ac", - "coinbase": false, - "hash": "aae42250a170a85bdaef6f487ac16942908b0cd3fd7d2f091d453b7def0f20f9", - "index": 1 - }, - "script": "493046022100af2ee7ba67cad751adfe4cb23c7af76434461d7dc4c5193bd7e890e4fe6c371b022100aa3e04e87aaa70e7209cae6a0b144421b08b8b607778ded2fb79898f818860920121028da941ed50d6bf3e7c8ca3b5a75921c980d5dcce123a397be88f0bace6a0fe64", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 503712, - "script": "76a91470d1d8f04ba6095134d30085963c438d73a315fe88ac" - }, - { - "value": 1022631, - "script": "76a9142c50c7d5c92cf406586cf6954aae00528570fe1088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1ba9cc851eac434b0b49e3e1d86f2a37655984027de510e88a863aa5cfed88b9", - "witnessHash": "1ba9cc851eac434b0b49e3e1d86f2a37655984027de510e88a863aa5cfed88b9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 163, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6a35e64848fe1e1e648d9e807be052dd7c2961fa0f0b5c5cc67cc30a661f999b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 97580020148, - "script": "76a91447c141e9c8e692e2b2bb8e598ce59dc3694e0e2788ac", - "coinbase": false, - "hash": "6a35e64848fe1e1e648d9e807be052dd7c2961fa0f0b5c5cc67cc30a661f999b", - "index": 1 - }, - "script": "493046022100cb37a5a6c53622c5cfacff9da6abd956a34ec78a559f90144e9180737afd20ee0221009fabe4ade9952ef77ec02facac7f5801dbca2e2b8c603b64bbba30695a4fbd450121035ebb27cb89175660375aef79f7ee6c1cf6116334739a2fc119178e8975e9d672", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 95580010148, - "script": "76a9147bec7721ae1fddc2e8436905fe977583b006174588ac" - }, - { - "value": 2000000000, - "script": "76a9141c1191d0690843511f0a014a8d2d42b1a3d9835588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f13bb8680c8e11b04d4be6f370d7db0ffcdab6be951d9fa934efde0dd7ba4ce4", - "witnessHash": "f13bb8680c8e11b04d4be6f370d7db0ffcdab6be951d9fa934efde0dd7ba4ce4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 164, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1ba9cc851eac434b0b49e3e1d86f2a37655984027de510e88a863aa5cfed88b9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 95580010148, - "script": "76a9147bec7721ae1fddc2e8436905fe977583b006174588ac", - "coinbase": false, - "hash": "1ba9cc851eac434b0b49e3e1d86f2a37655984027de510e88a863aa5cfed88b9", - "index": 0 - }, - "script": "4830450221009b865d136b0f846413178024a0b1ead742cd3805b474d4aa2152b8a0d917a335022067036d175164d91529a50b75e6725a8eb3462d166a573fe145696a5e2d2aff97012102ebef2679791fe99b8fddeb09f8017120ae7f1a99d0f54d85f21e836b28a58bce", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 104000000, - "script": "76a9149485d636997ec22b79d4b53862a66bb713bdc9c388ac" - }, - { - "value": 95476000148, - "script": "76a9144c60619e6b007c15d86b298a4788a5050a93af5d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "14d50f114e8a7e0bc96f5457988a93a2dde60d79e752495192c14a9678aa2666", - "witnessHash": "14d50f114e8a7e0bc96f5457988a93a2dde60d79e752495192c14a9678aa2666", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 165, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f13bb8680c8e11b04d4be6f370d7db0ffcdab6be951d9fa934efde0dd7ba4ce4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 95476000148, - "script": "76a9144c60619e6b007c15d86b298a4788a5050a93af5d88ac", - "coinbase": false, - "hash": "f13bb8680c8e11b04d4be6f370d7db0ffcdab6be951d9fa934efde0dd7ba4ce4", - "index": 1 - }, - "script": "4830450220196cdc3ff663074fbb111d1e88ea989c52319c29030ce3ff1f1247a80c41602c022100a021a88c0a5a36abbff9099583b12b76affbbe2042f83ef300b8f7b190323488012103d2f0307d0ff49c4982c3b8adc0ab14ae9b4c33a79845d297cffb0a3e73fd197f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 299990000, - "script": "76a914fa31576f07f2dfbeb0d68110a90dfaa311f825fd88ac" - }, - { - "value": 95176000148, - "script": "76a914b5a361d5b7c2c85acd9c4a26d186b0302efc381488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8e429f0d879876de8b62813db629da716bac75490871828ea218fad0f655a3f7", - "witnessHash": "8e429f0d879876de8b62813db629da716bac75490871828ea218fad0f655a3f7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 166, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6d79db2dad028e20ab90c712b574013e8be7d98b54c64dfc28cc1f3f0248c266", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 6239266, - "script": "76a91460578987b03548f6a244437edab630d2ad3f908488ac", - "coinbase": false, - "hash": "6d79db2dad028e20ab90c712b574013e8be7d98b54c64dfc28cc1f3f0248c266", - "index": 1 - }, - "script": "4730440220034a81d612e64d4b42f88b27c52f69cfd38a8d4dc872271409ea7ce4a48e2e31022018d83aaa19267542de511df1b2b99c626cbbeebc19689eb240f62e47c946550b0141045057d3dc2a1186da3bc808e724ef061688f5cd9e8bb987005b4b0c840b64a2403eaffbd34eeacdcce7aa997b1fc3f24328b6f0107f8f1929dd373e94ef096bf7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a7ba0792aca2cc84d605dd8cce11aa8e48bd35744380f0e18f99dd88e1a2e8fd", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97481, - "script": "76a9142aa5e0285f8b5f2a873c25ce4364bdb42d500c5388ac", - "coinbase": false, - "hash": "a7ba0792aca2cc84d605dd8cce11aa8e48bd35744380f0e18f99dd88e1a2e8fd", - "index": 2 - }, - "script": "4830450221008814ed960ea166604c4b2915ca8f9b6f380604bae61f478d13ce25af9ab97d2c022028da1ae3863524634d05b95952a8e91f7e348513cb68f48aae7304b47733a624014104a756676d2fd5ca068b6afe819d0ceae9d50716b01e64901d947f349c3df8745743509bf0cb854f4bb1f2a22d92441351b283002c39b853ae0945efda9e928114", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4955000, - "script": "76a91424e1d8d03b0ea3a7690dbfc96c6e3775f31d725188ac" - }, - { - "value": 1284266, - "script": "76a914f226e8dff9a53f1a4943a08c5b15ea514e2e767d88ac" - }, - { - "value": 77481, - "script": "76a9148174d6ba948a3ed4d5be61e009e740e16cb355cf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fc40cec763970ac0255dffbd7889f25fc697f47b6010aacd4ceeb9a4b02bee76", - "witnessHash": "fc40cec763970ac0255dffbd7889f25fc697f47b6010aacd4ceeb9a4b02bee76", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 167, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8e429f0d879876de8b62813db629da716bac75490871828ea218fad0f655a3f7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4955000, - "script": "76a91424e1d8d03b0ea3a7690dbfc96c6e3775f31d725188ac", - "coinbase": false, - "hash": "8e429f0d879876de8b62813db629da716bac75490871828ea218fad0f655a3f7", - "index": 0 - }, - "script": "493046022100bf2c5265c321d19339a748a19533f1a1631242d80fcc3164f91e06f1f5c951ca022100ff5d27faec2d04e778bbcf8e6682521496b2cdfe60eae7ba104bd9b1c684ba75014104ea3f53ebfba1df8d0c62cfc4f167a8d729433465c748c53d67c5a69a5fc7136ae2aa276cb26b853d423103b860b43f8a954357906e14082430b24b68f00c3b43", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e63a786a9525f023efc6d2e975544c84220f2f79030c83d3a60e970188b0a4c1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117481, - "script": "76a91405b34b4619522ceb2087a04ba0df095cb3bced3188ac", - "coinbase": false, - "hash": "e63a786a9525f023efc6d2e975544c84220f2f79030c83d3a60e970188b0a4c1", - "index": 1 - }, - "script": "483045022100a83f1435a33b642b0ba64596f5c487306db435073510645f24bab89e2b102df50220317543f353d45fe831b84813a006044757ff23a1555cb2aff2293d2454f034190141047c5df75596524d59cc4411f136fa36df33f6ec27e8a3e33ee8af52ca48004dd71a90eff1c7b4913110d0630aa2d5d125fc1b10f9b651c086c9ffd1a686b2793d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4955000, - "script": "76a914f06308b64107e7e39d49998dbe383c8a06e70e6488ac" - }, - { - "value": 97481, - "script": "76a914cc64676b92fc9c1598a1db62cf8cb8f3cd0c25ec88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3ad6b54fe2f692224ad3031056601c5e0c1c037efe600823984015b925e0e64a", - "witnessHash": "3ad6b54fe2f692224ad3031056601c5e0c1c037efe600823984015b925e0e64a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 168, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "98b1c8f5d3ca78d5ca27d75b850fcf614e896a7fc4cc971c82891f953f9c8e5d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 200000, - "script": "76a9145d61b24a2bc0312e39252e861677ea12aa60fc0b88ac", - "coinbase": false, - "hash": "98b1c8f5d3ca78d5ca27d75b850fcf614e896a7fc4cc971c82891f953f9c8e5d", - "index": 1 - }, - "script": "47304402201f44759be7667cb33edeeca081fad87507725ec0a13d49ab97ed4cff388e34b60220265619020a759a1d6d17bc15814e70049e7d360d5be47f049bd8916ba6b2fec1014104c63f51bd26a3ffa700b4018e0eb772ee309936bd0443522bdd8860744c6aa456668e17ed7cbbd6c63f734e1e10581bc029ac30225d02b4e81f1b88236909966e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f7cf006b0df42f2d23134391d937bac730fb21b497fe9bda149787959027f453", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299967, - "value": 77480, - "script": "76a91491fee19472cbb758235ed81ad00281ba17d938ef88ac", - "coinbase": false, - "hash": "f7cf006b0df42f2d23134391d937bac730fb21b497fe9bda149787959027f453", - "index": 1 - }, - "script": "483045022100c4586f2789b53a0d6fef68b20dc6ece9bb64e5ad5064ec6f5e1d750e9a87dc36022056bb8e2ff529707e2f56fc5d091019b5d3c889bab6c717a6d06f0d81637e279c014104bdc3ab8f598a623395ba96ed6413b71a13cad2720d7c00861b7f1dea46a682c8c73db59a91d06f16f963ee18f48e0e54fd70d47e522fde8d50df89a3f94adaac", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a9140cb9a131143da025d11203820bf00b1e9f44109788ac" - }, - { - "value": 100000, - "script": "76a9140450cad3a3cd648f583e796602be13c6a27adb5e88ac" - }, - { - "value": 57480, - "script": "76a91479edfeb2f95c270f9361b93cbb9d05cc409159e088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "047e49ee9f942362adda5477846da6a48e60f36dbcc414bae84336f55226ef75", - "witnessHash": "047e49ee9f942362adda5477846da6a48e60f36dbcc414bae84336f55226ef75", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 169, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "519bb09291b940ea2c3ea081f282eeaf9835616b3169e85ecf587061013fb60c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 287062, - "script": "76a914701a45854dd282daee43fb8b46cb384311042ae088ac", - "coinbase": false, - "hash": "519bb09291b940ea2c3ea081f282eeaf9835616b3169e85ecf587061013fb60c", - "index": 1 - }, - "script": "47304402200635ee1fac5fc671f524d23e694bc4eaa82eeb5115c0e42cc03a1bb1a828985202207830872468b146faf6a5a6e2e49eb28e9b717da24141d658873dfbe7cbaac83901410434172fa00f9430580ac42063a36f160ebdcb361456f9e57aa0f9c6a77964dea8d95b91982fb748a15938209260be2f109caa6d2141b0a6a948f8f170df7be1ca", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cd71356ce889ca663db6a17d564e4018bb22c97324c6ee61456f21814ed1f6e0", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77480, - "script": "76a914f6d3614ae980500158bdea58f69bda4a84b227a788ac", - "coinbase": false, - "hash": "cd71356ce889ca663db6a17d564e4018bb22c97324c6ee61456f21814ed1f6e0", - "index": 2 - }, - "script": "4830450221009469208759c414a5da2abe5bbbb2b01e8886e40c0054c2e00c5f9ada4b2d6f5f0220212cc23edeaa3f69760f44f64ef117b94befb18fb59dca0e50155814967b34d4014104bee700a01a3e2d160a15ccf0b5ee5f2674423de2877d09f2e38b0768fcd8feb13c61205b3e01f718f5973756d8aa7fa9afc9cdae0ee4426478fddabe905dd1af", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 276258, - "script": "76a91479a8e358b58e4cf054aba755f0a2116670e4759888ac" - }, - { - "value": 10804, - "script": "76a9148fcc4e4b73ace64e998fa6d1db2f95a7c115ccab88ac" - }, - { - "value": 57480, - "script": "76a9147b25f4d714ac3fd71ae524ad512efad06de64f5b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "663bbd130547efd23a2f4ab153ff95c2dd21ee894a9883d537183935f3b7687a", - "witnessHash": "663bbd130547efd23a2f4ab153ff95c2dd21ee894a9883d537183935f3b7687a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 170, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "048da7b695fb22e071a74eb6e0ae3f469b95fa47178e6a8b67bea7351378998e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297662, - "value": 1222889, - "script": "76a9141e9b5d790c14144608f4c767649e7f47df5e5db188ac", - "coinbase": false, - "hash": "048da7b695fb22e071a74eb6e0ae3f469b95fa47178e6a8b67bea7351378998e", - "index": 1 - }, - "script": "483045022100b8c4e05b68d629f4440cd80e0bd4bb7c71b607b723a7c410d1453ced8267d5e6022046ca307158d5224851e4db473dff72222c1f79563eb9a5908ab9975facf39e5f014104ce198a826962885b8485cc53504031091067c40ac5866626c6e39f4f5098ee2d3ab21a7ff50053566b71e1ca643cfd2e1fbab200d584cf8ec85bb9bb5f0cc38d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "89a04230d2ffa9655c9941662d2397346b7895f7767402bf2023ac33a6cad300", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 97489, - "script": "76a914cd1dcb29f9790961e0c4820c1b9b39fe2ba8829188ac", - "coinbase": false, - "hash": "89a04230d2ffa9655c9941662d2397346b7895f7767402bf2023ac33a6cad300", - "index": 1 - }, - "script": "4830450220742f2aa3bb1d72038eee25fc9db09c1c00d47fbd7b5ece806d2a9b97102da942022100d364d4401ebbc2545285e834e94452bcc1a3bce0aba38071bb2f470580718e75014104e64f818be59ce58f7027e66c9316ea00f4be5042774cce49d08ccc21119cd64620eed87b3009dbd25c8cd765f4714fdfd020b1b14db948dcb204ae840af3dc37", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 220900, - "script": "76a914af7e2fff7fbb590ca337eb5ad9d474d8088fd7a188ac" - }, - { - "value": 1001989, - "script": "76a914910b5f5f67c1f07c08292780654160fc732777c388ac" - }, - { - "value": 77489, - "script": "76a9141528010ec0c52dd3a3113658703b0b45454d84a588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cbe07049cbc0464c55f241df1cf5b5d180c47b4b08d17df1ce80eb6e98cf67dc", - "witnessHash": "cbe07049cbc0464c55f241df1cf5b5d180c47b4b08d17df1ce80eb6e98cf67dc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 171, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f5a075ce61d4d7199874f9d24ea11e7e0ad6a4ddb9aacbd76fea968692f4bf47", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 3358877, - "script": "76a9143fb22b3244967a5467a7298c5edb7b5ceb1acaab88ac", - "coinbase": false, - "hash": "f5a075ce61d4d7199874f9d24ea11e7e0ad6a4ddb9aacbd76fea968692f4bf47", - "index": 1 - }, - "script": "483045022006217d446ff12ea2e62e1ef500cbf01843c4ede9536563d3c4683a4a50edcf39022100e70d9724c604a5470c89df3293beaf3c170033d911f16a97bf7d4b7b21f45a75014104e5ee5ea7d6e03937de56d19a666cb647b08d0269ec24c5280909aceb8ec3d29e9632d6a0df5338812258537f73717d303dd4ece58e18879776e350a7b4d60874", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "61d3c17aabeb275d5a212e9766f4e106f969055c302832f95f6689d99658b43f", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914e1a0ed2b64072bb54e9b0435577c4da28d6000f588ac", - "coinbase": false, - "hash": "61d3c17aabeb275d5a212e9766f4e106f969055c302832f95f6689d99658b43f", - "index": 2 - }, - "script": "4830450220275735346ee69eac1f41130a0a38e5497d219b4493fb11cbff61edd127171c030221008eb7b3c112b4cbf6a6d92c65856db5d00abfdae792ef4863eceac027d89ff0640141046927dd4e5869b8e297d0706ae6968e9b9a3725c53fb15599a2ed17b33ca278ef0f0ed83bbd41ffd993ceee5472e2a5daf1df73302e4bbe79cccede7acc5126ff", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3296000, - "script": "76a914e0546540364035a71e39a6e1ec1ea3673b1ce7f188ac" - }, - { - "value": 62877, - "script": "76a9146589fc8d7acbd4a1945337f1a97c56de03c5fbeb88ac" - }, - { - "value": 117491, - "script": "76a9145b7640cbbe057040e705c14d9861d4f77e64be7188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7203e26ce14b2409f12b47737ccd0b9676b33e4e87cb4526f4493469588cc664", - "witnessHash": "7203e26ce14b2409f12b47737ccd0b9676b33e4e87cb4526f4493469588cc664", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 172, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cbe07049cbc0464c55f241df1cf5b5d180c47b4b08d17df1ce80eb6e98cf67dc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3296000, - "script": "76a914e0546540364035a71e39a6e1ec1ea3673b1ce7f188ac", - "coinbase": false, - "hash": "cbe07049cbc0464c55f241df1cf5b5d180c47b4b08d17df1ce80eb6e98cf67dc", - "index": 0 - }, - "script": "473044022044e5c52785a2da56d87aab516fc61353cd5c2767bb4bf4f0260c73de872b3a7202201c62084a4c74439bff2d4a35b613f41d9f8cd864c4259006b6162d5bf0aff141014104a5570cdc0f8820414e2235c57f7298218cfc1441f5ecdfaf3d4263ddc9881787d02c751f6355d3ae0e271b7357c821751159b2b6ef714c556170bda587d079ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0375ccc9db3949d8e0be0060617c5588787fc5e2383057cea5a726cc2f11cc70", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914809789e736a62e2d40b4d59e21a64895519fd19088ac", - "coinbase": false, - "hash": "0375ccc9db3949d8e0be0060617c5588787fc5e2383057cea5a726cc2f11cc70", - "index": 1 - }, - "script": "47304402203a33e826cb9f7f1ce25f018eba2ce688b84bbc88a4ae462eeaf529fda6754136022068ebca2d8506a93cdfc9429886bfc80fa9af10c6eb84705617b1bd1aa9061bae014104c3f4b19ccbf6bbd50ad0aebeced74148cb8ef000d70e432487be326ceca33c60612c6f4942ac21e17dfabf74d595b92d9e523e7c80d1efeca55a6f51758afe08", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3296000, - "script": "76a91480b2305ef0d7fc98504fb0ce5889d69da80bf7f188ac" - }, - { - "value": 117491, - "script": "76a91465162c2ae96b1f3a2d39a33f48b520418f19550b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "82af52ee805504ee07054d894dafa03e533dbcde677f7525ef1ae0528bd43116", - "witnessHash": "82af52ee805504ee07054d894dafa03e533dbcde677f7525ef1ae0528bd43116", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 173, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4359f76ede3f1159a05b6b3b173dc1489abd057e71150203ff1bc7919a2227c5", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 8188598, - "script": "76a91474ffd322b0bc57f8602c3e5989e7b65e0bf35c2f88ac", - "coinbase": false, - "hash": "4359f76ede3f1159a05b6b3b173dc1489abd057e71150203ff1bc7919a2227c5", - "index": 1 - }, - "script": "47304402204222954625e7a66a32e9362ee5aae18892e9346677a8521d9b5668a941f1fbd402207aefbe2db4f4ce2670c8ee7b1b13e8cde18750c764fa8ae91da9de997c2dd000014104089db562fd3444e8673becff31b5170f86289aed0a7b3c18c1842b699617786f053b9de8daeea2225f4a14b0aa575c5ba37afcc11f54260d1d99c3aa28be0f05", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8ada1611dae4ef799fc99cbf1ef3054858b7bf66a1d4b699581d56d92710ee0c", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914edfc2497e47a913b4f0169e61324703293fde9ed88ac", - "coinbase": false, - "hash": "8ada1611dae4ef799fc99cbf1ef3054858b7bf66a1d4b699581d56d92710ee0c", - "index": 2 - }, - "script": "493046022100ed4cee40d76b7f7e16a407cd71c5da0ddf86e41d6bb1b8bb98ed17de5d6225d8022100ad108c12d568a2bd1958697f87f9c68cf98d08f315b787c715aa61da34de50c50141042ad2f571cd3296d46b9909ea3b9dbf4b640947b332d4f553ec5d7a12318e5c0af57186f9ae11b8d9820cffd47d4cc2a8a52eba073c44e3f61d0cba321cecfcd4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6730600, - "script": "76a914250ade7bd688807051dcf42cb95a50b211917f1388ac" - }, - { - "value": 1457998, - "script": "76a914773ab67f6aacec7dfc662e54891b6e47b8193de988ac" - }, - { - "value": 117491, - "script": "76a9148b49cb9c5f4e6ca5019d7b907b545f2aeddc96fb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "223fe498ee0cae311da708da3b62079c7eabfe8863ab6c9871e5a22de718ea9b", - "witnessHash": "223fe498ee0cae311da708da3b62079c7eabfe8863ab6c9871e5a22de718ea9b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 174, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "82af52ee805504ee07054d894dafa03e533dbcde677f7525ef1ae0528bd43116", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 6730600, - "script": "76a914250ade7bd688807051dcf42cb95a50b211917f1388ac", - "coinbase": false, - "hash": "82af52ee805504ee07054d894dafa03e533dbcde677f7525ef1ae0528bd43116", - "index": 0 - }, - "script": "493046022100abdedc9960b3ea3d3a5c287849825909ff7b4f64e8bb2f5975e4a535b5c85931022100850e851172601d24e115edc8a850952e0d22c4b7bdef819855e5ab7fc643b8480141040262335102c5143bea57913cd266ccf84ef43725597f2ccdcb37e8310c7c43371c785e6478d201f133ea2ef8efcd38677eb5ba680b82d06a5ec3877571e8f936", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "00ec29ccdb23ef0b14584f7b098d1156448a6c68bd4f96925364348ae4b6a3c3", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 37454, - "script": "76a914f96870067d2dd97c3b93fee5203153e811cc170f88ac", - "coinbase": false, - "hash": "00ec29ccdb23ef0b14584f7b098d1156448a6c68bd4f96925364348ae4b6a3c3", - "index": 2 - }, - "script": "4930460221009b87bbf0c3796ae418d9a31a30742d101a287af9c46a29a481ceee02a23da57d022100e4cead9c8c6c5e56c543e7cf8c629798def3ea763d8d913a4993d6887264415c0141043ad7e8af53a86a5ad746dbab912d0bead8b50c3f1cba8ef0b4b4f7be7cc91b391bc1799568ddb9d03f8c066e709a9a275133f22375dffe17324f69563e31961d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6730600, - "script": "76a91430d229d285949a6c68642a26c01860a4bbf66ed888ac" - }, - { - "value": 17454, - "script": "76a9147e0ff116743e6ad3d85b2d60805ef60253e714e688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "485c13c47394a65c0fef1d79a229163b552379f8af7ceed47f3c4b9683c31bc3", - "witnessHash": "485c13c47394a65c0fef1d79a229163b552379f8af7ceed47f3c4b9683c31bc3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 175, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cfcca75d4ea2a197a98e5341ad8768562eae55da590794f29bc684bf3bdb5ec0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4288971, - "script": "76a914595261a7987219e36b497828b491157acd50058d88ac", - "coinbase": false, - "hash": "cfcca75d4ea2a197a98e5341ad8768562eae55da590794f29bc684bf3bdb5ec0", - "index": 1 - }, - "script": "483045022100e655950417e9557cd7c6dc49013cf8225c68948da516beef03a3b18738c48eb8022068102faf5a4c1f503f3f24ba6c46cc27b316155ab6cd11d29512f3ee1af3d7fe014104b0be4ae825b10d1d7b9593deddcf06ef80e58b1383a197120ee3ad280789598f8469084cc38146d1989ff9dae31c783b04b9034fbbdfb56ddf93e822b1c0aae4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "69e90621f8ecc301b5d794a5a2e6319aa43520387e36df29531ba6b9090c5410", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117489, - "script": "76a914d11ad7b04e157d9d68f0e6f983a7cc3be37363fc88ac", - "coinbase": false, - "hash": "69e90621f8ecc301b5d794a5a2e6319aa43520387e36df29531ba6b9090c5410", - "index": 2 - }, - "script": "483045022100de4bc9fac543825bbd762e7f078e488c6b0b7fd1a0cebac2f3c098b214bc16d80220287ede8b8897ff044546f253470697b591152b20bab2c97970788e3be4295d67014104a82253b57619cc3d8505295b3e4663c4fea7cccdfa26c9561cdb60aa623577210baa6015d8bde2ba601e7287421cd26a7f6f8aaa6fea1f4bf39d747e2677565c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3690800, - "script": "76a914d371ae82de32e0c8d797b789124dac36aa166d4c88ac" - }, - { - "value": 598171, - "script": "76a914f3c0da7317682b394b612c607e66d2858092475288ac" - }, - { - "value": 97489, - "script": "76a914c09d44e24705a2b3f13f1909a30797f8d1fd830a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5a6ae09b6842d16c7327b0d2bc316eca90d3268ff469a5b7b7f837f2737ad7dc", - "witnessHash": "5a6ae09b6842d16c7327b0d2bc316eca90d3268ff469a5b7b7f837f2737ad7dc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 176, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2a4d9b02d391d8497757ac8ba1a2c8d14637e1971b36eeb40ed34b70edaa199f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3981171, - "script": "76a914485c53e74d7e6c9b030d45eea380564fffdf27b388ac", - "coinbase": false, - "hash": "2a4d9b02d391d8497757ac8ba1a2c8d14637e1971b36eeb40ed34b70edaa199f", - "index": 1 - }, - "script": "48304502201095158755ebe6e5624653c3841e01a816054080051016fb5746af1f0d8ef248022100b9c8191cd9fe5867d9f9765996ff8b0fbe739663329211c69f3bd7545f7cb46a01410482791d8c86efbf836cfa7266073021af3bda81acd00921f7c2d33013f27eb570dbb71fc7ef296f479da2721a42eb1c2f556c2e9832ab7b09ab13549215c9dec7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ee83c7c346fa7b75511c3b7618595acd49f69af03134814a1368df7947fbfeb9", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 77489, - "script": "76a9141bed9f95f699a6f4adbc0beca3b53cd4070a1a7488ac", - "coinbase": false, - "hash": "ee83c7c346fa7b75511c3b7618595acd49f69af03134814a1368df7947fbfeb9", - "index": 2 - }, - "script": "48304502201c65fd796cd2ea9e828ee8af56be0368562ee3fb4f16793c95c4b3b47840d9ae022100f9466d2669eee28647d8c4454f5bb98c10166b3ba5a09d33a12ef92112a4e9ae0141046ef17ba18a206f8ae78e1935abc3a2ad5a879e3e3228c8459cd78d2a7adaf3101819c8e1ee42a46934be470e761b9c08bf803fd554fc41991af67e04a97a0d47", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3700000, - "script": "76a914e78756c994924a104a309e425314f2ea670f65b988ac" - }, - { - "value": 281171, - "script": "76a914454efc60ab1e91bf88fee7ed4f0a782c371f0a4288ac" - }, - { - "value": 57489, - "script": "76a914ebd7c19ded0b7b72639f963cc611f0f2cd5cd3bb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a092947c538070e2d75d0b103e70a2f74a91271de0ee0864990d63b490fecc3b", - "witnessHash": "a092947c538070e2d75d0b103e70a2f74a91271de0ee0864990d63b490fecc3b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 177, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5a6ae09b6842d16c7327b0d2bc316eca90d3268ff469a5b7b7f837f2737ad7dc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3700000, - "script": "76a914e78756c994924a104a309e425314f2ea670f65b988ac", - "coinbase": false, - "hash": "5a6ae09b6842d16c7327b0d2bc316eca90d3268ff469a5b7b7f837f2737ad7dc", - "index": 0 - }, - "script": "48304502201cfe4ce40c08d36ba8880eda02ec27246c1e958677779edc9a79ed61c9513ae6022100cba091051fee67e157d1680b729cc09b9f9473af0cb4616b40b8cbfdf45f8f53014104ae6be215df201e70e067cc0dc9fda1a41e65bbd23ca1bfcab2f57b0eca2e109709ff6e01d262261102a517e260931e249a85b2352e6da96f478db5711f69cae2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c3892544133a3d3d7cd5b6d22af506259a0f9e3fef8670f171194bbc87c9ad2c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117450, - "script": "76a914d5883fb00b78b18f81c541b0e0e09287e222411f88ac", - "coinbase": false, - "hash": "c3892544133a3d3d7cd5b6d22af506259a0f9e3fef8670f171194bbc87c9ad2c", - "index": 1 - }, - "script": "473044022034dc640fbf743b77c17e5104a55516e51ed15c37b8d4c6643d16fd0a9ee92e5102200cf5d69965e387e6d2eca1de5b45df5967a855b50cedb0999b69c837d8c604e101410485f3edb753c6b098e2b38c962275c4f52c2a67f23246226a3791e0cb782ec5b674f82bc3f268cacdec232b5da413687306ef202c7278123a9ca60e86efe3ba1e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3700000, - "script": "76a914cfebc4d97ea46836d98f8db357028edac37489cd88ac" - }, - { - "value": 97450, - "script": "76a914f584aa58d16fb88d7e618c56348554ca65b04d7d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4c50d35a4e68ee20bba2072c3c2f9142c35908c9f914895bb8e0089f082ee556", - "witnessHash": "4c50d35a4e68ee20bba2072c3c2f9142c35908c9f914895bb8e0089f082ee556", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 178, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3fd24c721778333877b3d102899587a8f3b0de566664de8f80c859c1e69c7e84", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1755588, - "script": "76a91480a958d6a5de0f1e6127ce9791b9a2565ace206b88ac", - "coinbase": false, - "hash": "3fd24c721778333877b3d102899587a8f3b0de566664de8f80c859c1e69c7e84", - "index": 1 - }, - "script": "4830450221008d1cc240f5f030fc39f7e62a78dd21705140f86d713c7029643af6f6926360970220183b501591f075764ad2de7f5688fb300c2549034273d69727cf876ebb0a5f98014104bd5c1aa990d07819f72f24c5e65bf0a1ae972d662728412202915215e58ef2240c0c50e6ca3a08f3428175498ac4843920a431d8cb99b44097e1afbf4d37dcba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5dc6974e0ff0be5a2c60252d5383d890baf2d0814ff24b976ccac61db1317600", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117443, - "script": "76a914aa247b5455a6fa6f7baab3baf942904a2d4b8d5e88ac", - "coinbase": false, - "hash": "5dc6974e0ff0be5a2c60252d5383d890baf2d0814ff24b976ccac61db1317600", - "index": 2 - }, - "script": "483045022100d35a40fd6ede381be53dedb7a3aeda9b300c94471bb0e92de7d51a0b379faca9022059cf3cd83decb93860c0d84be5e1e58e0a6ba97274e0a2a98f9cce2511fbf9690141045ee30caeda717c56765904526062981e750c2d73877a10450cce6241acd0e02117e3e78c630306dda57f3f7baf5327cfe979dc812294e5c84774947fb462fd3f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1335740, - "script": "76a91448012e7f8ee1beae5465393ab1aa8a3f9c8662e688ac" - }, - { - "value": 419848, - "script": "76a914e515e4b77a48f2be58f958ed42d60cd449e6cf6b88ac" - }, - { - "value": 97443, - "script": "76a914042c957a2313b738610b9292bf675a11f6457e3388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "32d3b23e55d0b91d900f84eb219a7e4716e7ae82f27ffd5a65b4588865f0e1f3", - "witnessHash": "32d3b23e55d0b91d900f84eb219a7e4716e7ae82f27ffd5a65b4588865f0e1f3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 179, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4c50d35a4e68ee20bba2072c3c2f9142c35908c9f914895bb8e0089f082ee556", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1335740, - "script": "76a91448012e7f8ee1beae5465393ab1aa8a3f9c8662e688ac", - "coinbase": false, - "hash": "4c50d35a4e68ee20bba2072c3c2f9142c35908c9f914895bb8e0089f082ee556", - "index": 0 - }, - "script": "48304502202d82be34491071bea94af9d63497ccd5d88699733dbbb09cc1c0b0f9e03287db022100de6e04398b802ccbb27826bdc2c34ecffc7211dd7577d5df031b8f148d9e62ea0141041b1248f2e6c2f6007433bf46730c35ee4a41500b9e94c161e960a3ba52dccbf1b0f650eb207138bc5201796faa38b1ca866922d5e9432230075bb9b101309491", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b34530a3c6296435bac03e4eee96bb5c767c1e87d4cdaea98857cd9d1fd285ef", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97489, - "script": "76a91401d987d380aefef0c87e904be4921c136b108bf788ac", - "coinbase": false, - "hash": "b34530a3c6296435bac03e4eee96bb5c767c1e87d4cdaea98857cd9d1fd285ef", - "index": 1 - }, - "script": "493046022100bd1c3be50daf14c0fab1ab1df0fb1bcdf77bbd25cfe654e563af9790cec98e62022100a00124bcad9267d76e1607a64d44f4d7045518bc1ec797edf3cbd995a0a99d86014104795098a212313ab26400c4f78ec277fa01f2117413df7aafa28154de66a9fb5425b2819e9b595b819084ef55aa40036f622e8310666a1afce0af8b51afcff3b1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1335740, - "script": "76a914a0caf4d05350518c04960361676c28830e08502288ac" - }, - { - "value": 77489, - "script": "76a914285929da6f434b603f87c8a442e734dfeebc46eb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "de0217866c61c3bb9bd9c329ff4a3cd994c433cfec6564e35dad482f05421e30", - "witnessHash": "de0217866c61c3bb9bd9c329ff4a3cd994c433cfec6564e35dad482f05421e30", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 180, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4f67cac681a2d0d76511332e9311bfac808d05a57070fbda4b64d531e7bded39", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 112786, - "script": "76a914fe65dcfbb023dfc3850df2aac198f35c13e7184988ac", - "coinbase": false, - "hash": "4f67cac681a2d0d76511332e9311bfac808d05a57070fbda4b64d531e7bded39", - "index": 1 - }, - "script": "473044022056c5db2adcab46dc3fd166c214eade112ecf169a782f03fa3d7b09d1cd12c8cc0220012180528d23d6c620012003e5ea57a5969cc57790c80526812fad97afe514170141045841b254e0ceac7e996c2a6bc64af92dff42bc008edf76e1b985bfff6ec5dfde7ae2eca6dcab447a33a3867312fef935a62af57251b6674c3da04506f5a07986", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ba7616f6f4baea1514ac088d4febdf7e707af0c61583e6802e3322805b38537", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 57452, - "script": "76a9140035fa4bd964e2e7d97ec911540ef77d257c5dfb88ac", - "coinbase": false, - "hash": "6ba7616f6f4baea1514ac088d4febdf7e707af0c61583e6802e3322805b38537", - "index": 2 - }, - "script": "493046022100dca4cea69ab2b94b76209d1a4f838d9f8600fc9f9e684494711d625889c183670221009facc146bb19d2396e52a049deccc150263439cdafb87000686530ae9b4651f001410493c539fac57a36f81f1c3a0d9698ee59e5d8504478d6b81175fb1d8edc35ae3817ace5824b7c596506fe977a3f42c9062ab5b934d45b66845b3e84ef1180fcac", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a9140bda76507227695d224a9e07db3bc06c5cf1fd6e88ac" - }, - { - "value": 12786, - "script": "76a914ff33627dc2ab743abeb1a5483f1717ef570bd42788ac" - }, - { - "value": 37452, - "script": "76a9147f580454f0cb8129e3e853f81aa34179899805c988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "17a4877b9d2c20a363d1f52ad70bc4cc4aa5864c3297e42d2d773429d6bbbd00", - "witnessHash": "17a4877b9d2c20a363d1f52ad70bc4cc4aa5864c3297e42d2d773429d6bbbd00", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 181, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "de0217866c61c3bb9bd9c329ff4a3cd994c433cfec6564e35dad482f05421e30", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 100000, - "script": "76a9140bda76507227695d224a9e07db3bc06c5cf1fd6e88ac", - "coinbase": false, - "hash": "de0217866c61c3bb9bd9c329ff4a3cd994c433cfec6564e35dad482f05421e30", - "index": 0 - }, - "script": "483045022100f4bbfd07f20a938f41ab60bbdfe3a4b8d434e37ebf0b19f14f0cbb8c224608d702204e3f18359f7677444e97ec925b3d715425eb522426ebb64544c18edb81eff2cd01410497352eafaef76bee4a9ced58ba47b15bdb1e79fb3a270e5a9a83311f930a92fc1cdbed4b87d9834fc7993447911431dbe558e970e5431a3abb42c30960d5bf48", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "49ef8b88bcdf3bf8bc7ae7bf674728421dbb530b02c89b73b8ea377802739036", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117481, - "script": "76a9149ce524ab1cf7cd08b5faf779a359dddcab28e10d88ac", - "coinbase": false, - "hash": "49ef8b88bcdf3bf8bc7ae7bf674728421dbb530b02c89b73b8ea377802739036", - "index": 1 - }, - "script": "483045022100d97e680aff0a018d4e5f1c297abf2fa564496b95a7b1a76205a269503b9474df022071137d1aa2e22ddcc0577147f69b5bba98a175bae47e1495e8f6ffef5828c29e014104fa58445fa36f4cc6a66d574e03995e185dcce6bb78e5cb2b09037027e921ea5a8c185e2114e3258fd20a8d1052d4d2f7c74f710863460896e563016a5ab22f1d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a914a44876ed63f5054b9acebb3394c7c50f7b365caa88ac" - }, - { - "value": 97481, - "script": "76a914fcd02887eec7211b80852ba7e6207625308170b388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "259820bf9359036030f9093d05960800b7560f0133cf49d51ff7655c684af13e", - "witnessHash": "259820bf9359036030f9093d05960800b7560f0133cf49d51ff7655c684af13e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 182, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b9ebb91ad833a092adf9085bccc2eecbf8b3b9e9f10e128babda92dc9b08c236", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299990, - "value": 3356032, - "script": "76a9149443b0d1965ee6179d264e673121e60ac891f08788ac", - "coinbase": false, - "hash": "b9ebb91ad833a092adf9085bccc2eecbf8b3b9e9f10e128babda92dc9b08c236", - "index": 1 - }, - "script": "4930460221008069ea74475c45f2452d4c635ee0bee6bcb2bdc67e18c543fa85bc1c0862086d022100ea198ad162a5201c1f67452142b2947c67800dfd03feb97f5a17325e7b8dd34e01410456184d4dd268b367aea6435efdbdb8c5a387bd65a0e1833d70631198ff7b5c2da1f41412eeccd149ade33fc2a8f2926afb8583a3bfce04e4a8ef4a6e0299c0d9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "35a0122ffefefc07e4da8506be1feb6f58c88c11e3b9fdb686f475506f75e684", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77491, - "script": "76a914bd207ee8344b3c66deebcea8ccc17dbb8fcc68e988ac", - "coinbase": false, - "hash": "35a0122ffefefc07e4da8506be1feb6f58c88c11e3b9fdb686f475506f75e684", - "index": 2 - }, - "script": "483045022100d34d466fc38f3b24aaf499d5b8f027e52e1aa1246afba6242f7489e9f3b7260d0220245c5f5efcd7b44d4a6c436ebe50b0797ad2672a1b8a6c9310c7eae47d675fef014104ed6d573dccfb99b94212a5f1ac8df568aed915dbb67f5d64f83c2f182b21380e4a319a5697d0e420fb2bfff7d1d6c2178e47d2f951c56203d9c8164cb820cde1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3132000, - "script": "76a9141e640a48d1798693bd7c92924033983db4b1563488ac" - }, - { - "value": 224032, - "script": "76a9149f3e76863d0ed6e85c83db0f7629f4112ad63eb288ac" - }, - { - "value": 57491, - "script": "76a9143a859256841cf3e7b83539a4b46e14a6da5cb41388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f51bcd93c0ef63ab3aaa857fc856b20e350a0dccd5c87d6e7d26eadd9de1510c", - "witnessHash": "f51bcd93c0ef63ab3aaa857fc856b20e350a0dccd5c87d6e7d26eadd9de1510c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 183, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "259820bf9359036030f9093d05960800b7560f0133cf49d51ff7655c684af13e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3132000, - "script": "76a9141e640a48d1798693bd7c92924033983db4b1563488ac", - "coinbase": false, - "hash": "259820bf9359036030f9093d05960800b7560f0133cf49d51ff7655c684af13e", - "index": 0 - }, - "script": "48304502200cc5a393a1a55e47c76dae10e601b6e9d427ffdd18cdda427dde031785c0e6de0221008ca7b63fe297a88a894a3f9f178d59b9bc3df948038f235b2fb9c3502064d73a0141040ad3815bc3ee2c359497b1548cd484a7bcf0e7b3c119d413ef5e0deead3cb83b543ac082737008be7b591212519740d8a405a5e2ba0b5e9d2271398cb74e44cb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e917947083d7f925fd82c21af3bab89a87be31993437c7422f7eb026fa5a3d3f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 57491, - "script": "76a9146fc49491fdfbd0b78c567217fb4dd73f8f8ef4aa88ac", - "coinbase": false, - "hash": "e917947083d7f925fd82c21af3bab89a87be31993437c7422f7eb026fa5a3d3f", - "index": 1 - }, - "script": "493046022100dda2605c30a8f187abd7ded8f79deac0377fd26155434691abe37739bc29cc02022100ebdc0ccedf8515ec2979c8defbd03d36f468803d93ea5b08b5a9400980c3ec4d014104c87dd551e8b3e91d64776f4194569cba3fa5268e81e8a9c4c43bc99895e24eb67095c03ed5db81c350282670fb87b3d9edf3977f012ea11fe78d8ba2e59e637d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3132000, - "script": "76a91488b3f7b7c52c8addd16531322e9839ef8f2ea47288ac" - }, - { - "value": 37491, - "script": "76a91460841c561f4a07dae8700c6220045d6fe6f4d55688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f1f1868bfc26cea0203c6fe0778b4d8adefb7953c368027d02da7ec1b8fba53b", - "witnessHash": "f1f1868bfc26cea0203c6fe0778b4d8adefb7953c368027d02da7ec1b8fba53b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 184, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cbc755d75dad6af84ea220644f902f63d2defdda13e4aa5d522f5bcc5539c568", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 22711262, - "script": "76a914983e212a947b833311cfbf10ecc9979844ca065888ac", - "coinbase": false, - "hash": "cbc755d75dad6af84ea220644f902f63d2defdda13e4aa5d522f5bcc5539c568", - "index": 1 - }, - "script": "4830450220787723a25ac34fc719f4096c60db2111232c40007c4c0418091c45d7608eb89f0221009d9f5a848b170c66e8855baf20e5d0f5d00339398683b246da9c2bc91782e755014104d4329542a888f44403004225bf64f10789e83918cb1dd009a00760bec544d61b18752bcde001fd1c1311e8934000f9116e510bfbaf294f5b90e55170ae7ce82f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9dae1be361ae72541ce2743d139300ec033e06e346a482771d4e8502a2f955eb", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117443, - "script": "76a914611b3ebf0315701ad4ac502b169b45cb2910014b88ac", - "coinbase": false, - "hash": "9dae1be361ae72541ce2743d139300ec033e06e346a482771d4e8502a2f955eb", - "index": 2 - }, - "script": "493046022100a04c1fd3e6ea252c8a443f323b2568e4dec63e2b0fc9d55f4cffa6d906a0c0d9022100af2416b42d262640372a4b0b34c203e6b65a7fe7546428219bcfbb9ffee9941a014104abcf8b976e564a86b712ba4c8210a26f16cd4674b5cbe0e6747f11be789d7bf48f12f9c3592ef20506db53088a5567eb931f9d1451709ea0ed9d054ba92f525d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 20000000, - "script": "76a9147cc49aeb44054a199893a1326402bbacf3f2e54188ac" - }, - { - "value": 2711262, - "script": "76a914d9618ae19a0a5f600a84398b224a5b3857ea73e588ac" - }, - { - "value": 97443, - "script": "76a9147638892ba6406d4d655653298ead2899590c34e488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "76c4c31e6ef03e3a15107ee12fe3f4f30ff458be5357bdd949b821ceb2424f25", - "witnessHash": "76c4c31e6ef03e3a15107ee12fe3f4f30ff458be5357bdd949b821ceb2424f25", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 185, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f1f1868bfc26cea0203c6fe0778b4d8adefb7953c368027d02da7ec1b8fba53b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 20000000, - "script": "76a9147cc49aeb44054a199893a1326402bbacf3f2e54188ac", - "coinbase": false, - "hash": "f1f1868bfc26cea0203c6fe0778b4d8adefb7953c368027d02da7ec1b8fba53b", - "index": 0 - }, - "script": "4830450221008f796c6a2e475f56e8c928c8548931977336212c7ca29ffdec87694d88477d5a02200e234a1c22d291d0e03f097bc4ca648a9b567665c08f07d83088d5fa61efaf33014104da081123304b837bcec6788d4b14ce5b2d8aa2a754c321ffa1745bdf0ed5e6ee941b023b600f75016a83e51ad270da16887027ce8ec4d7ec4fcdded08d3c176a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1885cd26bae0f40c3c7ccb872286368a267948a8ba3b43bef4ee40a7f9992ff6", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97491, - "script": "76a914f2e7a4fb587b75579bec7cb960d202739bc770e688ac", - "coinbase": false, - "hash": "1885cd26bae0f40c3c7ccb872286368a267948a8ba3b43bef4ee40a7f9992ff6", - "index": 2 - }, - "script": "48304502202d85a67a49a9f1e4276f2c3fe442688bcbaf261d937dcdfb71c3fc895910611f022100d1a69c1f207669af1d14092accfd938848f525798136d21a01636342042c59fb014104c17566ab05b2cdfb2007961b476eb7d49d0b1caea1b8945fd5af1542bebd7dc0b99731d40193b642d749c80d8247ab00b4ff83a3adc9d569760d15be359ee357", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 20000000, - "script": "76a91438859b3d711ae387ed72019dbf6e267986a9e36188ac" - }, - { - "value": 77491, - "script": "76a914de22eac26e1011b8d8a7dcf5327487eede77b02488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7bbba888b442798b791fb3695d897c4b8cce59b084435cb9c9ef1ccb59f61ac6", - "witnessHash": "7bbba888b442798b791fb3695d897c4b8cce59b084435cb9c9ef1ccb59f61ac6", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 186, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cf8b12e31d1b120bd575022ac293b992011b3a1169fe1f6290fbffb5ce2bbb86", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 2617076, - "script": "76a9149833ec55b2edc0344d12bd5267f8a4965db51ac588ac", - "coinbase": false, - "hash": "cf8b12e31d1b120bd575022ac293b992011b3a1169fe1f6290fbffb5ce2bbb86", - "index": 1 - }, - "script": "493046022100b8a145f379e7796848e551fae6fe50622279c788511ac875f4ab94e6e0066c26022100def47a1778a603c352572996787b0bb73cd2b654a9565b3f7867e5a3d9db29d4014104c7221880430c54dddadf1260b5672d4b8032808c77da22b3a97d98e0b4ca446a6446796994c19f065b5da436f3478572c5884e4d2bb3e6ede743792578089987", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "464f44e52a8d336539cc8938662181b635098c6257804e432a396260c1f6f7a0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117450, - "script": "76a914684e70517e5300624888ab5b560fca4ba465c53a88ac", - "coinbase": false, - "hash": "464f44e52a8d336539cc8938662181b635098c6257804e432a396260c1f6f7a0", - "index": 1 - }, - "script": "483045022100d4400eeb1c125f8728d69e7874e3af328c9600f7dd44530c474f47e30067db96022033a43ceaa194bb217861017392e5907c71d0a738d5fe6f28d95b277000d64bb80141044ddb5cb2aa43ba9968acdc11a41f6d52fddb05643e62019f533dd3b7bb357a866e7c3433700c701beee19c5d230b864c5a2d8dd419b87b6cc2b31007a516b791", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2250000, - "script": "76a914bf2779070849dbd3c30e248f6f4711ca0b6aa68c88ac" - }, - { - "value": 367076, - "script": "76a91413bbc52bba6ed5e1b28c22b9842b6b09e30762db88ac" - }, - { - "value": 97450, - "script": "76a914ab1347b8018f28010920058ac1a44c00e906b8fa88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4210cc2322034792cf750016486c8195a41c493fa7186adec06b15963ffca8c5", - "witnessHash": "4210cc2322034792cf750016486c8195a41c493fa7186adec06b15963ffca8c5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 187, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7bbba888b442798b791fb3695d897c4b8cce59b084435cb9c9ef1ccb59f61ac6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2250000, - "script": "76a914bf2779070849dbd3c30e248f6f4711ca0b6aa68c88ac", - "coinbase": false, - "hash": "7bbba888b442798b791fb3695d897c4b8cce59b084435cb9c9ef1ccb59f61ac6", - "index": 0 - }, - "script": "473044022053c4a4ed72dfffd21f5528e797e354d08abca5c2545330b3ac150c70704e258602205edd8d7fd7ed4af41e0b70c109dfb0ee9a40b3f87d2598862e3db81d5b8db21d014104fedd1884ed0782b40accb858f4dafb3cc26dc4a1ebe9bdbbd4ea7a169194a13ba09583c8abb20ca59b85e20ec0ddfc93cd49bf4d694d5eb2357b54c43e967a5c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3b289c804b68ac3a9a2e395a149af60c50284c1217c5ee15b6307eb89a180bbc", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117491, - "script": "76a9141f11600691e9201c6fdde628bc0ca1ff7464bf2988ac", - "coinbase": false, - "hash": "3b289c804b68ac3a9a2e395a149af60c50284c1217c5ee15b6307eb89a180bbc", - "index": 2 - }, - "script": "483045022100f7eddf1cfa2d1e75a58e86cceaf65216dd614344a424a3f37307f498e852fbfb02207ca61508b0bb2369819c56e46a79f694aa13e7a8595168cdb5c163d98d6244790141042330d150f2a05456717746486d841369c5736b8a2415e5b06c0338c0485f3b27700ddfabf022db3a0c8c7e578c577d63b94b07ffcb2e184827d3a900068f257f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2250000, - "script": "76a914da62d103855f5e320fa3eabbfde11ab86925d54988ac" - }, - { - "value": 97491, - "script": "76a91457da192693671c05b2f1a41e6a6d762581297adc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9fe67a7927f2abdd4c3316f25d652fba4438a68575700c8959c2861b73df6043", - "witnessHash": "9fe67a7927f2abdd4c3316f25d652fba4438a68575700c8959c2861b73df6043", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 188, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f617f863fe4cde59317471b1e38ee509add504af63c1d28b7beaf871f3588909", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 25574488, - "script": "76a914ea5bfad074724ce0eca25ff2be7ee89e578b089e88ac", - "coinbase": false, - "hash": "f617f863fe4cde59317471b1e38ee509add504af63c1d28b7beaf871f3588909", - "index": 0 - }, - "script": "4930460221008dad82cd2e4a1643e783aa12a29129d726d5cbda36274aee1def5db6407ee917022100a038aa3a8ecc0a33e6dc8bdfa9ed5ebdba65e95f599f5897bd78ed61d40058d8014104e41ae6eccaeb6afb8fc56f5db7f2fb724bda526e32b315bfda45008e4c9e3a5c1958d77c2b79a8f61c3f74b091e3d2d140138c05d92670d66c983ec24d8106e4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dd25297d03b48458c874f609c6fc547913232cc1e3c2aac762ad8c1161408f79", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 77489, - "script": "76a914cbdfcaeaaa558cbf1e74fba25b07a0a2a3bb6bd888ac", - "coinbase": false, - "hash": "dd25297d03b48458c874f609c6fc547913232cc1e3c2aac762ad8c1161408f79", - "index": 1 - }, - "script": "48304502203c287cf0aaa04ff9ec67d6bc14b0e6d9df30a4ccd4395de3d6d6396f5bffa8e3022100b6d964630e3f18ffa9fd0707ae38c04f79a7a93e83390e35168d8f714cb8711601410495b7d69ae355841a0c1440239b7e090e9c9f83bca253f8fa36452fd37a5aa80bc2e6c618c930606b185be8dcd586c4a11bcdcc5b43014ab93dce4b7fd4801ed3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 24230000, - "script": "76a914af3880782d7dd9cb36bdc630c08a30c4b42f879e88ac" - }, - { - "value": 1344488, - "script": "76a914368ee96ba1bb455279d39cd9b81df3620684dba588ac" - }, - { - "value": 57489, - "script": "76a914a4e5a65add5093489a4bc146e369ba139f874bc788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3b4c82f5b8cf9e36a5904e6978a433a323f69afe940467c4991b74e26247adc3", - "witnessHash": "3b4c82f5b8cf9e36a5904e6978a433a323f69afe940467c4991b74e26247adc3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 189, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9fe67a7927f2abdd4c3316f25d652fba4438a68575700c8959c2861b73df6043", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 24230000, - "script": "76a914af3880782d7dd9cb36bdc630c08a30c4b42f879e88ac", - "coinbase": false, - "hash": "9fe67a7927f2abdd4c3316f25d652fba4438a68575700c8959c2861b73df6043", - "index": 0 - }, - "script": "493046022100a8ed29339041d515c6a9b9d50984552c1c2cdf8d91098cc7918bd60b3b0b87fc022100e5dda8bc8d11966566b37599dea5f730ef39338946402e82644f336484a3e3d501410440bf23f84347d1d8d259316b9b28d5bee64cdeff905801a5f186939f6df01a01b9a5d20cb3c58dc3fc316ab471927da6ab905281018277cbd89de281a1ddd4b3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e9f1658592f3f65f288d454347e0d4c4e1cc5e49a92c64a27fbab840eb23ce98", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137450, - "script": "76a914ffc1a2bb7ddf7224c5b5c772dc86826bcdafb40b88ac", - "coinbase": false, - "hash": "e9f1658592f3f65f288d454347e0d4c4e1cc5e49a92c64a27fbab840eb23ce98", - "index": 1 - }, - "script": "483045022003f2ecf149f084e416fb26119ac6e8ad66cd40cc1b3868f5b3cc5d865658b7cb022100bb8b2f85296a9e45fa259dd264f9d4c18391b64a4d30ccc81d361e356893a263014104d59a79179e1eb23c7ebba0d1ab64ae9d3cdcffce5702b1ac6423d5a23550923cf7b183323d8107ce1e41734be37b4845b8b5115acb43cbd772c78299ca70cabf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 24230000, - "script": "76a914a5d619aa836d9263020aafd73b0951cc21ebc33a88ac" - }, - { - "value": 117450, - "script": "76a914e4a9de4eb0c3d699d4994002de024478b7b7635388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3ece388fa5de75c945aff90ddb971efc0b9fc034ff4f8d638899bb3103ff5ba1", - "witnessHash": "3ece388fa5de75c945aff90ddb971efc0b9fc034ff4f8d638899bb3103ff5ba1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 190, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c0261481a1a3c3d6ca3e92aa622e7cc0d34ef92d8ba457420b626b91fcede5aa", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299978, - "value": 1801726, - "script": "76a91427b45299b0d52a71c7e7d81e528c489e7b98ab9e88ac", - "coinbase": false, - "hash": "c0261481a1a3c3d6ca3e92aa622e7cc0d34ef92d8ba457420b626b91fcede5aa", - "index": 1 - }, - "script": "493046022100bac153ec2a0d94cf0fdb316f0ef7b4fb8b3acc6b8466a0a34b6dad17b4a5ea3e022100a149aab493b474a9401a06dd447b8bed4d26489b3f217e0ebe35bd8fb68e8b4b01410478934a3e2a86a3f7d496cadd48d2ca6b76a3415e87135061aa15f928f4447dc12174024a668e24ad3c031093d66d2ec680496c29f58d6150f05a77325c563eee", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bcd91b19f64f6e0e90cee107a3039290c6f9130fac32774168d107b30e245ad5", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117489, - "script": "76a914d8b1fece4c41392828cd5225962a99664c89543888ac", - "coinbase": false, - "hash": "bcd91b19f64f6e0e90cee107a3039290c6f9130fac32774168d107b30e245ad5", - "index": 1 - }, - "script": "493046022100e418187b18464b8c37099dea262d438dd59a044bfba78c4971d4b0dd814d8432022100ed0f3ad9ac57fbd9daea1111695da4d49fd0dad5f7a82a91db4ef768b4fd17ae014104d9e3b050eb7defe4d08feb465484fe78e6eb43179c55bd4adccef303925486e6be110b13402501afde53c289f4bc5ea464f3dbbc9911b380aa488cb15488def3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1582700, - "script": "76a914b0326ea31749ec3479abf6c939c5bbeca0fa8ad188ac" - }, - { - "value": 219026, - "script": "76a914a9900c52c1f22f66a455409f3faa84498b016f9b88ac" - }, - { - "value": 97489, - "script": "76a914b5f4c022f16df645bc539f9eb0f493cf47cd48fc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "570af765958108c2aad60c94457d54fe0d05edd75733d628ed4b7a6a7ce6708c", - "witnessHash": "570af765958108c2aad60c94457d54fe0d05edd75733d628ed4b7a6a7ce6708c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 191, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3ece388fa5de75c945aff90ddb971efc0b9fc034ff4f8d638899bb3103ff5ba1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1582700, - "script": "76a914b0326ea31749ec3479abf6c939c5bbeca0fa8ad188ac", - "coinbase": false, - "hash": "3ece388fa5de75c945aff90ddb971efc0b9fc034ff4f8d638899bb3103ff5ba1", - "index": 0 - }, - "script": "4830450221009f72d77bc4633275e702432b4b420796f87ce86ebce064f67f2db09c1d985ca50220343efba47a5a14ecee79f713f467c983b84452091c03565fda20aa0719e0fba90141044f2985450c59f4d44c033b96e7ab1de799bf82849e4a8e2e4212e089fe7c7d12d1fa2ab19ec2b46efadd32112ae6b03981571962eb5c678ab15622ac545658b4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7dde1af34f188062c6e244c0fce8700f20ed8f39093d3266ea3b333a0969856a", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117489, - "script": "76a914440b4b736583cc145db9514b18ea97350a304c7d88ac", - "coinbase": false, - "hash": "7dde1af34f188062c6e244c0fce8700f20ed8f39093d3266ea3b333a0969856a", - "index": 2 - }, - "script": "493046022100d206dd48fa4b00ae1f813195ae63b733ccbdaf5a32a17a3a8993d5e290fed14f022100adf37ab5f6956373ec43d631a52925943bbd0f8fedcb3414f21d2d094cac06540141044442e15eedbb022c9598b52035058665442deb4ba630bb4cf1089e457a23650f504795bf045a33c3e7ea5e31ad56b66a1fb840a184273eb25f59af90b0ff197e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1582700, - "script": "76a9144c5f65f9dfe23ac18b24ba05652569874210267288ac" - }, - { - "value": 97489, - "script": "76a914bb7f650ab03d39d6eb6dc21a59665ff7d553eadb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "03de43ad0d9d41fc0b62d5cc5d4a972f7de4bef10c82be3c0c139295b03083bf", - "witnessHash": "03de43ad0d9d41fc0b62d5cc5d4a972f7de4bef10c82be3c0c139295b03083bf", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 192, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "add1ac93eb73b6571b48309ead14d04d4a257791b3117f228f8b2283cd1eb574", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 12079106, - "script": "76a914cdfcc79d89b3b43bba9fd2a73f26bfdb3c4507a088ac", - "coinbase": false, - "hash": "add1ac93eb73b6571b48309ead14d04d4a257791b3117f228f8b2283cd1eb574", - "index": 0 - }, - "script": "493046022100a1e49fcc37a4b441fbe36a6dc9845c16dd218f6bb3b329d8c127a4558ca05e27022100e695302d7d8385f7d5c2b1d777fb5cbc8686cef9adfe328ca37df3171ce861c4014104bd2601150a4e71870b60dc152290d2fb92e1a94f05f99e5a425d6cda63725503b9efa495f10bee4e46256e09c8b74305083b3c3eacab0fa2f97399ac96d6ea86", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bc5023ee0193cec46fa71e3f6a1f3d68a3d50858150e7676088b2d31dfc7b0ae", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4152371, - "script": "76a914ad40801f6a7718296a7ad3a86a8b06114e1e2d2688ac", - "coinbase": false, - "hash": "bc5023ee0193cec46fa71e3f6a1f3d68a3d50858150e7676088b2d31dfc7b0ae", - "index": 0 - }, - "script": "483045022009241b3ad08bc2e1799b091a1c88cd281ac7a69e84c25941555dd2bdc8aaddfa02210089f29edaee12578bdc343a6d2fca5b4d0ffe4370b099256941a5c227f87c17d2014104eeb93b9b6347619b86b4ae00633baa1b31111163fa93399ed051cbc3009a663ec767bb2a63ede52f7271e7088be22ecb6c3680070b97682e0bae426dcff6cd2c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "621f42f995d8628d63778f317cc43ca1baa33327374f6faa9b24af6b68dc40a2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 880992, - "script": "76a914c9bbd4104333a3c1d29e353d9704ce8c0f1ae2ab88ac", - "coinbase": false, - "hash": "621f42f995d8628d63778f317cc43ca1baa33327374f6faa9b24af6b68dc40a2", - "index": 0 - }, - "script": "48304502207e840c8db51c3cf028629c60d3c184e5abe39ba61d31f7c88631d995f0ee6bfb022100ff906f6f194a340536fcef0a0bc26c15a3b53ff2fbee65356a98e6a30a8db7cf014104a69e774e96b1b3fb5646c2b1cff25c2c1a43c93ac4d407cbcc97a6c7a05c7bc6aa595b3ba38e7242019e217b85ff8435a6a8f4c1a12e448797eca2f881c6c793", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "214846c2f79f371cdd1b8bf0036439e4a505a0cd75d0ee42d7f0543c5ce04f45", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 384192, - "script": "76a914200a2933f51298bd6eb5b111c65907d440cd07b788ac", - "coinbase": false, - "hash": "214846c2f79f371cdd1b8bf0036439e4a505a0cd75d0ee42d7f0543c5ce04f45", - "index": 0 - }, - "script": "473044022029d25877176ecc8482f20af522a844aa283014d9513065e15be6283ccd39daea02201dbcafcbde8bf0898dd827aa2c369c8303ef3f79d1b638d42ecb5a7418ba7736014104736dcdfbde683a219be88757dc6287b13de507a4cfbe3c2277f5cc00d1258e98b91dfca8afcc50d122331c33e2f8e4e7639fad5f9a9bc913d56992976d954fd8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4cbec5a06422c09fad97652cd7a0c2b52f6ba8d73337236e6c5149644f211d14", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299967, - "value": 77480, - "script": "76a914131bb23fae784ada8c2547963f57fa1d4c28c3a088ac", - "coinbase": false, - "hash": "4cbec5a06422c09fad97652cd7a0c2b52f6ba8d73337236e6c5149644f211d14", - "index": 2 - }, - "script": "493046022100de3d58111279bb3a0eff64713e22fa5910d419173852f6378d935edfe262a46402210093d9583896a1af5a690aeb40e7b4057af7b3f64d54a0c68b58cbcb6b8adf352201410496938c67dcd4449e13104d460162d943c9a7838173ea22dee2ca5eb1ece2184c8aca8479cb6db68d8b5a6813163e57522e4a9d3e0fd48a99223a07faa604cf6b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 17496661, - "script": "76a91486c01d35744050ba11b95df83a05e6024eb2f5f388ac" - }, - { - "value": 37480, - "script": "76a914e841d77195e84dc4af4ebec92d2bed2501e1db1988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0442f8b655af48eac6a8f5c87c616fc26a0d28e7f4ee0d444414f0a638aa54fd", - "witnessHash": "0442f8b655af48eac6a8f5c87c616fc26a0d28e7f4ee0d444414f0a638aa54fd", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 193, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d727659a57c1005a10a764f7b0f1d130b2f1a32f4c65ca970d30ecc75d8a9c79", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298814, - "value": 13332443, - "script": "76a914868e42f4c68fb069dbc3663cea7d074871c4381488ac", - "coinbase": false, - "hash": "d727659a57c1005a10a764f7b0f1d130b2f1a32f4c65ca970d30ecc75d8a9c79", - "index": 0 - }, - "script": "473044022030a8901c7d5e640a15496fcae53354f859174ffd4fcb67e2ac8c2d8ae7ed7c1402207f83306a38b83af985ef7830550cc8b5bc6573f351faddc1e29574a3c80fd5ff0141049c16b73e3fd2ab835ece2043234ddbd705abe08472f1ce040f7ad1c7f484b3a690a06eca155e666e928be92136ef31e6dd2e713ba9d4b981e6b426a31291e5f6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6681514, - "script": "76a914ec468e65a8f9784a9f988bc9d21b8a8f13ef234688ac" - }, - { - "value": 6640929, - "script": "76a914868e42f4c68fb069dbc3663cea7d074871c4381488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fbd24683c3ed34a7b31e22c60156b6061d30bda3d26682fdb0c6f2711494a788", - "witnessHash": "fbd24683c3ed34a7b31e22c60156b6061d30bda3d26682fdb0c6f2711494a788", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 194, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ba395c4855635018f27cf4fedc26092b4f0c3e6606cd08bf42ec62d2c186a2ef", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299959, - "value": 19220489, - "script": "76a914bf7dfb385abf4af5ee8a2f998c04e4a8974f745088ac", - "coinbase": false, - "hash": "ba395c4855635018f27cf4fedc26092b4f0c3e6606cd08bf42ec62d2c186a2ef", - "index": 0 - }, - "script": "47304402206358ae85d06e592a8ab6ff5fde151d5696d44bf16133b16f5deba3ae5f0299b302200cb1cbb53e8136f092ca81ef68b9613660ca129a4b7d96c6082f8221f1524d0101410478b2cab4499a736e29ccd5a343cafb3122559216c2b3af30b105c15f1701ff2c35e738466d7d0297cebd3204cdda437ac92b24417e2fd4dc18f4d8951e505e24", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10992634, - "script": "76a914cd430cc9a36b39fbf16a6dfe05e118c099e18a2288ac" - }, - { - "value": 8217855, - "script": "76a914bf7dfb385abf4af5ee8a2f998c04e4a8974f745088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9a092c6396be9df818924619081d47dd39ea6469427d39da76266fc13053e5f1", - "witnessHash": "9a092c6396be9df818924619081d47dd39ea6469427d39da76266fc13053e5f1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 195, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f69d534ec99c86ac247f0bab061230a5b018fbd69a861dd3fd0e56c6dbdf5ace", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299905, - "value": 4975562, - "script": "76a91478770be5aca1444090fe32e272d5501847298c4b88ac", - "coinbase": false, - "hash": "f69d534ec99c86ac247f0bab061230a5b018fbd69a861dd3fd0e56c6dbdf5ace", - "index": 1 - }, - "script": "47304402202eed0eb72dda81218d010731e16d486fdc81e2f35fa2ddd54b5b43e079d08408022020578ca10a8e2d25dd2ae88eb9f40f512b60623f97ac4989ca1c9c3e5dc81e84014104aa12ff1ffa41fe8328a5e2854c4b7f2875a3b9c57b100c69541f95b59dc03f2b5a863f72f133f74c74034304110959789bb2680d817bdba9f89234b01bae3308", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3083836, - "script": "76a914ad39c18f087dd7ef30dcaaa9de9931100c340b8588ac" - }, - { - "value": 1881726, - "script": "76a91478770be5aca1444090fe32e272d5501847298c4b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "af2a3663c18e4225ad0d970671f136c755262d93226b0a4ed4e9a81a6e4291dd", - "witnessHash": "af2a3663c18e4225ad0d970671f136c755262d93226b0a4ed4e9a81a6e4291dd", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 196, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3bfd298b240a582279d957b25c178b3c787a3f21024507e234ab20c981590d4d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 93996138, - "script": "76a9144fc5e274ffd18e6791c00f16fc7041855e521a5a88ac", - "coinbase": false, - "hash": "3bfd298b240a582279d957b25c178b3c787a3f21024507e234ab20c981590d4d", - "index": 1 - }, - "script": "47304402203c5d559fbfdb40246f5838b3783ac4098a9d31bcb26cef28347ee8b7b8c0d7b902207bed338ca09f0b27e82fd7f7c6d4f9d1088ec18037c247b61f29727be3fe2b2f014104ddfdddf976f89cf49363c02123602bae849213f81dd20b05dbdc7b41263e93083f13c924203a81c5bb60f99e790f6a5c96648b0cffce9a591d5953ebc8bb45a0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 25000000, - "script": "76a9149e7431660282a311f5e3e3711507f25ca198e2b188ac" - }, - { - "value": 68986138, - "script": "76a9144fc5e274ffd18e6791c00f16fc7041855e521a5a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dc1df861a8c2a6fb728cd72d53a88472723b25d11ef458cad958044e634b5dd4", - "witnessHash": "dc1df861a8c2a6fb728cd72d53a88472723b25d11ef458cad958044e634b5dd4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 197, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c5182f7e33281c3856659852923ac8ff389d18cb99e5b030de071afe3cd344e7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 12890000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac", - "coinbase": false, - "hash": "c5182f7e33281c3856659852923ac8ff389d18cb99e5b030de071afe3cd344e7", - "index": 1 - }, - "script": "473044022055d05bcc5f1ae235f86babd90ab94086db108947e93732715197aef0381bcccc022029717c2ac22cc6653c19eed0cb855118aca74d43a18b310e7c87120dc6efd7c401410457fbf746bf1d48c6350a52e4c264a7e505056c2aadef3fa6d03c3e2abeaf704273500cf186513da95cbc2c6cbb6e55ab5942da7d5ac281319076bb8c1b0d27e5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1800000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 11080000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c8686bf594d37c47a728c7d36c3e78f0d84fff2f52d961216e07547f46fe27ab", - "witnessHash": "c8686bf594d37c47a728c7d36c3e78f0d84fff2f52d961216e07547f46fe27ab", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 198, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dc1df861a8c2a6fb728cd72d53a88472723b25d11ef458cad958044e634b5dd4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1800000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "dc1df861a8c2a6fb728cd72d53a88472723b25d11ef458cad958044e634b5dd4", - "index": 0 - }, - "script": "47304402202c0a2b67a74619beeaed8299377992164db7804bab46411216fcf81b07467cfd02205ec8139e4429cf739ace1efe5beaf367d2ae33fa786318752267543cfbf2bcfd0121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1790000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d210132a66be76ed8edbfe516e4c8d1ebcea2d5a29d7b4ae652e77892caa48a9", - "witnessHash": "d210132a66be76ed8edbfe516e4c8d1ebcea2d5a29d7b4ae652e77892caa48a9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 199, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d44428f72ece7ccbac629da10c4bbacd19224a191c92e503eac700c762a027cf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 11046550, - "script": "76a9142490cdc303abfb8d25e6a139823c0fb1c396ae4888ac", - "coinbase": false, - "hash": "d44428f72ece7ccbac629da10c4bbacd19224a191c92e503eac700c762a027cf", - "index": 0 - }, - "script": "4730440220689d5bc399da4737f85c6c5445e76b5726858ad9b7606ffe03b5f61680580d790220740a674952d74f40f95b716023c8239fb7b4be3fe41b15330c1123f712097aa7014104199dec630581c4f6450f9b41e1c03f91f24dda9bc0550739e81c21562249f9d490ff0c517cd32cbe9e77ac67d10b0c0799db8305892d73ef20e34d8b0402edbf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4405480, - "script": "76a914fed2f26063b37e438cec2703cbf5a8e4392c5d1a88ac" - }, - { - "value": 6631070, - "script": "76a9142490cdc303abfb8d25e6a139823c0fb1c396ae4888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "855094f0f0205e664c64d6fefdb6053fe28e4556c4ba09b2ca7acd5fa57f92c6", - "witnessHash": "855094f0f0205e664c64d6fefdb6053fe28e4556c4ba09b2ca7acd5fa57f92c6", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 200, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8d71fe1692f78981a20fb5a2ce977e9d7b9ae6829252727234a38b7dcb09c86a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 9687576, - "script": "76a914e2006fd4ae784640679428b6cdf7cee4dd5880a488ac", - "coinbase": false, - "hash": "8d71fe1692f78981a20fb5a2ce977e9d7b9ae6829252727234a38b7dcb09c86a", - "index": 1 - }, - "script": "473044022067b363e87789be97fcf67840ddb44c157426caf72c1da5532ffbd9f2de8867570220663b06510badb6b484d29a61100cf99531c5999885148b04745a2beccc3d2cd5014104482138b31a8348b3a04af0a8cdcfa651a91a9be4fbc1e169d44663fa98b6b404e12486545a1d7fadb1db08feae0d3faafcb558e02be7a62d8c12864804a91638", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2500000, - "script": "76a91448c42eaeae081abd067b5edf51af7e57c56c4a0388ac" - }, - { - "value": 7177576, - "script": "76a914e2006fd4ae784640679428b6cdf7cee4dd5880a488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "059d9055a8ee5e2fd4327e93dca6ea1f8dc0e7c90344e96d5727cbcdc1ba5463", - "witnessHash": "059d9055a8ee5e2fd4327e93dca6ea1f8dc0e7c90344e96d5727cbcdc1ba5463", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 201, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c91d0bdbe4f6b0c7586e872af73ed9d2a3cca9e1e9448c1121cdff277c803cc1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1880000, - "script": "76a9145a4ecb5baeddd6a79eb7ce66b0e96314489fedf188ac", - "coinbase": false, - "hash": "c91d0bdbe4f6b0c7586e872af73ed9d2a3cca9e1e9448c1121cdff277c803cc1", - "index": 1 - }, - "script": "473044022023d4f8e841778b659e52bf446405e7f4863effc2ac428f6794d86318fbf9c47d02205b9954f836b1569a474cb5196fa2814b4a507ca960e8a3cb328f4db363ca9e5401410422cfc2bcedb10594d647ad4e2aebea5838a213146be941e62f0e1d9bb47927adce5d3b377101357b912bd821de6555116bd9a790ca69cbfdf56c303738edb7a6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 500000, - "script": "76a914d2c75a23ee8e15bcde722e6ea7485b3db2319dcf88ac" - }, - { - "value": 1370000, - "script": "76a9145a4ecb5baeddd6a79eb7ce66b0e96314489fedf188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c7d157782ebb347060b2bba17725bfe0072c7c9f76f21575ec82cb59ce1e903f", - "witnessHash": "c7d157782ebb347060b2bba17725bfe0072c7c9f76f21575ec82cb59ce1e903f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 202, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2aa2c5588031bf7a21509f7a3b0718d0efeebcd4b52def0a24e047139ed8cb9b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 3675000, - "script": "76a914ddbf0eec28abbe5be544890b4e894100c2b9c25488ac", - "coinbase": false, - "hash": "2aa2c5588031bf7a21509f7a3b0718d0efeebcd4b52def0a24e047139ed8cb9b", - "index": 0 - }, - "script": "47304402207e4a04b1544c66693764c9c99e3b829d5fe365ef20e963c0f044b46d81f8219202203d00d95f32c8e078f063361d8c0aae866acd4a87227798a4f08b499c4686b3ac014104c2de0fdc9c334a2b99fba3b2d4aa7206f2f74f029b04d402053d7e801bed90b3af5bd2a93dc493b40be9896c638fdefd560c94bdb0b4d255dcea26cd2c857bb1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2000000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 1665000, - "script": "76a914ddbf0eec28abbe5be544890b4e894100c2b9c25488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "45fbbc16e5730dbef91b6b31540722f7f00ba42ff31686f28074608c658275d5", - "witnessHash": "45fbbc16e5730dbef91b6b31540722f7f00ba42ff31686f28074608c658275d5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 203, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c7d157782ebb347060b2bba17725bfe0072c7c9f76f21575ec82cb59ce1e903f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2000000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac", - "coinbase": false, - "hash": "c7d157782ebb347060b2bba17725bfe0072c7c9f76f21575ec82cb59ce1e903f", - "index": 0 - }, - "script": "48304502210086c67ea4b61bf2104b1684c399e54938b152c7deb8d1e69af9439d48a9874813022060c234fd6d52bae0baccc2f06fbb2462b2d4c03464c245713fc4eff6e42f586f0121037bedeab7fcb8f05bc5fca2bb43525bd7af9f125035149ab4f48843db0ba37c8f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1980000, - "script": "76a91438bb181091ee71cc4a0259dc2fb43dc01622d71888ac" - }, - { - "value": 10000, - "script": "76a914ddbf0eec28abbe5be544890b4e894100c2b9c25488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "60f6f7ccfe96ee03db59230a88c70f9ac2d26988c749b9b8ecebc28407f46d7b", - "witnessHash": "60f6f7ccfe96ee03db59230a88c70f9ac2d26988c749b9b8ecebc28407f46d7b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 204, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "58858d9343e33eca0c73831a31b5660486180f4f176b11916088e768ffe25da0", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2975000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac", - "coinbase": false, - "hash": "58858d9343e33eca0c73831a31b5660486180f4f176b11916088e768ffe25da0", - "index": 0 - }, - "script": "47304402200f2f20eb41fbd592852fb6a1326e537236b80491f28c03177031c562f93b49f30220787cc5023ca30a5a5f4fa8094c339c3a852db6a5a0b8394aaf43b17952bb46b801410408e0b2378aa23e30a4de4774fdf540f6a72449c99d29ace5a07ef04537dbf29504b7c4c4d5f82a0f949a7f039e386d68a3f1d04da7c86988311ae7ac824c9cb7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1400000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac" - }, - { - "value": 1565000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "be034aeea9400c833163839e1a13d1c67e85caf95d032b2f72fa78fb0074efbf", - "witnessHash": "be034aeea9400c833163839e1a13d1c67e85caf95d032b2f72fa78fb0074efbf", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 205, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cf6457b24c043b3d3d49657c49c2c3aa3d47eeb06c7c126a1ad1d82db8f02f0e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1518129, - "script": "76a9147840ab3e10213585f7c52d7b5396f80d67140cc188ac", - "coinbase": false, - "hash": "cf6457b24c043b3d3d49657c49c2c3aa3d47eeb06c7c126a1ad1d82db8f02f0e", - "index": 1 - }, - "script": "473044022027fc052f1394ac310cb6591b1793b54163dc2ce8a5e680dae793324d04d0ad7602205954bde8c2d10072be57896cf01aa56a269e5cf9dd083630e064f0932609de88014104f442ea70b4287080b971936e8b1044cad5df7f7762a50ff340b794b656852727b27367f53062035014427a02037907e21df0188df6eb92a907af9791ea2c2b3c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 440000, - "script": "76a914e83ad96c1e7399f12c60438cc3f97cbe1aec817988ac" - }, - { - "value": 1068129, - "script": "76a9147840ab3e10213585f7c52d7b5396f80d67140cc188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b4fa7015b676fbced8117ecef47883e8f6876154dc7d68f76c307f69b49fd02d", - "witnessHash": "b4fa7015b676fbced8117ecef47883e8f6876154dc7d68f76c307f69b49fd02d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 206, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ae4501368920a52e3a6107b48a6e3f1876d3c1772cee4c13ced8bd0fe06479fb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299396, - "value": 249990000, - "script": "76a9140afcd889830cc4b753204934be819da95d4c7e2588ac", - "coinbase": false, - "hash": "ae4501368920a52e3a6107b48a6e3f1876d3c1772cee4c13ced8bd0fe06479fb", - "index": 0 - }, - "script": "4830450221009bdc2750d58dff4422dc5ec425cc59f99aba66bc1139e30f0b4c3fe1c99875e7022047dc01394621273bc8fed1cfb71f9fbdac022f8ff3b4a2b02e879936b58fde570141040c3f07b9d1861534599bd5aad6e991d1722b8035be62bed8533301a50a078f2498f942a224ef5eb2ed696eedeb990fe07bc06184be43e432ebd8a38accc15895", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 14000000, - "script": "76a914fe4f4ebed83f0a3aa1e7667c43d38f5e663c3c6a88ac" - }, - { - "value": 235980000, - "script": "76a9140afcd889830cc4b753204934be819da95d4c7e2588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dbd2980740195119eb9314add80a841e086f53b9f56f3b6f6b762e8001bf1fec", - "witnessHash": "dbd2980740195119eb9314add80a841e086f53b9f56f3b6f6b762e8001bf1fec", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 207, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "830f94dcf2595c697378167b98ceafcb9b3e80353a9fa5fc6f10be17d9622fad", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299967, - "value": 1023379842, - "script": "76a91437ac6c595c5fa66ce8d2a1055ee0b6ddfcdccd5b88ac", - "coinbase": false, - "hash": "830f94dcf2595c697378167b98ceafcb9b3e80353a9fa5fc6f10be17d9622fad", - "index": 1 - }, - "script": "48304502205ac9330477e400f8ca387c1d6030c73d3463005566aef7a0097c60c35fe0c631022100c93b4cb50bd7338c58643430c0d615f5c5eded7fa9dbe4c954e23c0990fad3f40141049af842244aac4299345522be966acbf5b21839596913d75c2a5d3f507c1b4d28a34db3adbb923faf72aef0b0fd21f720bbfe278a946b96e4315cf31ba02c78d3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 33671000, - "script": "76a914717bdbb3da3babe1834251a343d308781f53b3db88ac" - }, - { - "value": 989698842, - "script": "76a91437ac6c595c5fa66ce8d2a1055ee0b6ddfcdccd5b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7eb196648bce30bcbf2df7c131aa1a2cc8ae3c41e7b721e44d7f1ba895e07785", - "witnessHash": "7eb196648bce30bcbf2df7c131aa1a2cc8ae3c41e7b721e44d7f1ba895e07785", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 208, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d8a1c18ee2d90a55de5f8f86fab9ca6b8a38a6285b25fd303ba4ba7dbf68ba3a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298324, - "value": 15440000, - "script": "76a91495365ba2fe4cf7fac8a159895b51d044af74802488ac", - "coinbase": false, - "hash": "d8a1c18ee2d90a55de5f8f86fab9ca6b8a38a6285b25fd303ba4ba7dbf68ba3a", - "index": 0 - }, - "script": "483045022100934f8a16c40bf0978e748ac2c7d7be1799bee510f932e0cc424146f74d3d3b6502206dfb2a1315c4b182282b88ac83c64d843610b6c0248c74695da12f8494e4943f0141046d6556a505e02af5498a83450382d2ea926da1a7d1be057328abf9e8bfd09455f1abc71ac82266afbcfe05e113f061be907f4380c88a4cf424172d07b289ec47", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 283500, - "script": "76a914a48c35e18e369168a18029a75ceb84705b1c87b088ac" - }, - { - "value": 15146500, - "script": "76a91495365ba2fe4cf7fac8a159895b51d044af74802488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f7967d217e7cd67baa414eb08eb3fac359cbe6cd70cc2becc3e8940f39e2cb7e", - "witnessHash": "f7967d217e7cd67baa414eb08eb3fac359cbe6cd70cc2becc3e8940f39e2cb7e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 209, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c09cb62172553f8523efde81727cf72e7f63ae2070a4b735dd32d32c102da081", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299686, - "value": 62929300, - "script": "76a914ab58815ecc8ddf4e86d6daa23db54f2de1a38b5588ac", - "coinbase": false, - "hash": "c09cb62172553f8523efde81727cf72e7f63ae2070a4b735dd32d32c102da081", - "index": 1 - }, - "script": "4830450220762771baf882667a4e6eafa1154c3a75de641c0011b1eb5dd67e6de91aaf8831022100bd5fed870998266288e860f343376d23fce779211bec7fcb122a7de33743cee20141041d24632a20f6fbbf8ab51ba2d368bdbf6177b6a8f7b0700e89bf496c8de05f8ad99415f237f83fd9db625a67cca5684ab987b9a491c835b1b09f6665ea80f3ae", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 32973156, - "script": "76a91474d5651497109434ee9167aedc96b99fba69edcf88ac" - }, - { - "value": 29946144, - "script": "76a914ab58815ecc8ddf4e86d6daa23db54f2de1a38b5588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3e55827311aeaa6c1c20d40b365e1cf6163e88add060a38740292686e93cdb5a", - "witnessHash": "3e55827311aeaa6c1c20d40b365e1cf6163e88add060a38740292686e93cdb5a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 210, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f5b81ba03e75e38251baf314879ce7d290c1265f471303a3cc6efa00cf362b73", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 9493868000, - "script": "76a914c5e062f551abdd2a0d643921bb2054b5183c3bd188ac", - "coinbase": false, - "hash": "f5b81ba03e75e38251baf314879ce7d290c1265f471303a3cc6efa00cf362b73", - "index": 0 - }, - "script": "483045022100ec00dc3d491435dedeaab6877841acb66466c0e763606397412715f894d2eac4022049f5e270765b7b26fbbe2848f707937f19401c2840c52fb4b18e3f7ec4a23c44014104f48efb30e8ad677df49b4d71d785fe57efac8df3894ac25229c6049d7dceb7a2f71e515a54ed664249dbd169ce3e6d1440e6f9247d210c5ad2a4a3680ad92f66", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9480058000, - "script": "76a914c5e062f551abdd2a0d643921bb2054b5183c3bd188ac" - }, - { - "value": 13800000, - "script": "76a91484e548b85401e5f8a68915a1f28e9dc2f0b244fa88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a9de6c9e75d455f475ef81b0a2c928c0cdca937d37c386f3710dc16c7f376154", - "witnessHash": "a9de6c9e75d455f475ef81b0a2c928c0cdca937d37c386f3710dc16c7f376154", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 211, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "977a352e316e1e7e7b118bd0e5378eda6fd5efabb6c4d9eaf4564549d96bdc92", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298270, - "value": 4224894, - "script": "76a914c4d42fe7ed1f274b298a7bbafc7a54321cca4ad388ac", - "coinbase": false, - "hash": "977a352e316e1e7e7b118bd0e5378eda6fd5efabb6c4d9eaf4564549d96bdc92", - "index": 0 - }, - "script": "483045022100dadbb5d9658604704a77760df648aaaaa3054dbcd392cd58f8c78d4f4b2ff498022024120d7766232f217f0c8e6150d2bc83552748821dad64138ea2a7b54c8e5b1f01410407e5fe78b10d41904ef68c4542a1e83b8e9fd122b56edd75588aff642005c6c15f5be341801b2ed7dd1d7b41c5ea49fee924cdf6029338e5dcaa7c1e7d10f6d7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1530000, - "script": "76a914fb14fb94375fc4a877c35326f4885bbf0e4c766788ac" - }, - { - "value": 2684894, - "script": "76a914c4d42fe7ed1f274b298a7bbafc7a54321cca4ad388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c50ef971b51f31b554ff4fb34ec4a184bd98bf6259cf4e383e9ed26733bb1edc", - "witnessHash": "c50ef971b51f31b554ff4fb34ec4a184bd98bf6259cf4e383e9ed26733bb1edc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 212, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a89b413208f2cf739bcc3cb0c4ae432f4ba293ad7657643eb0fd1f1d58af0cfc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299063, - "value": 4678520, - "script": "76a9144e90b8d7f2d646f25a100ca0eed05760f3adfef288ac", - "coinbase": false, - "hash": "a89b413208f2cf739bcc3cb0c4ae432f4ba293ad7657643eb0fd1f1d58af0cfc", - "index": 0 - }, - "script": "483045022100b374c2814a6edd302a03abda3e8632611afac9943957a6a251645950e621a4cb02202e0b82bdaa8be5d6e384999a6bc57f5bbacc3533e41bda9d76ef703615aa37750141043942507f50df12e82a31a29c488e4509c43465a1fdd1bdd19bf2c90454d2ccbd1619ab3ab4206f66796a23f2342d7206cc13e7f3ca4612c0cdf8899010693a6b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 84000, - "script": "76a9143b96fff6364a054e979f41afc7edb36d7d34e98088ac" - }, - { - "value": 4584520, - "script": "76a9144e90b8d7f2d646f25a100ca0eed05760f3adfef288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3d6e71d4c582b6fe2d21ccb44799081e15c30c8b7a0f66b0e3cfd856a594eadf", - "witnessHash": "3d6e71d4c582b6fe2d21ccb44799081e15c30c8b7a0f66b0e3cfd856a594eadf", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 213, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b20f5a66c2494971bc708fe669e2a88981a6fefb0b6ee7be7a1b2aa71f48a703", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299738, - "value": 13380621, - "script": "76a914d9498b66c0316ff015814e91bc4c03c521c8cd7488ac", - "coinbase": false, - "hash": "b20f5a66c2494971bc708fe669e2a88981a6fefb0b6ee7be7a1b2aa71f48a703", - "index": 0 - }, - "script": "48304502202a05e37c9e2b854e9cd644a3abee40d76e7e53ebad0f3775b1c84b5b50de25c90221008879708124bdb2fc352ab7025dc1bdd1b60d1cbe98c3955e263efcfd718dae4b0141048139a69db2f7af19cb3a604b05e369b7b0cb11c7d051d1510bb5c1c531a25ee1b859848c570e4987f8e7e4cb3b6001ac3770d8a17cc0c88b13e76ed16ea18776", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11013701, - "script": "76a9149151bda1761c63f39346bf2e6ccfa50157939ad388ac" - }, - { - "value": 2356920, - "script": "76a914d9498b66c0316ff015814e91bc4c03c521c8cd7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7e2c4fc9ba2a1de93bb3cbb7dedf54dc3a5ca7f55d67a721c5d24c28a9daad53", - "witnessHash": "7e2c4fc9ba2a1de93bb3cbb7dedf54dc3a5ca7f55d67a721c5d24c28a9daad53", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 214, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f0b82da4cab68cef1050c475c40f299ac114466183092721ce74afc0c880805b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299314, - "value": 3984500, - "script": "76a91433b77b04ec1de113e83c2e1ffcff5bec878919cb88ac", - "coinbase": false, - "hash": "f0b82da4cab68cef1050c475c40f299ac114466183092721ce74afc0c880805b", - "index": 0 - }, - "script": "483045022100e9fb5bebcfcd8b86b1f731f9d4b6c61efbd2c7db9436c246378c03996427536502207051775cacac188e949af0ad7ca760d787f2d4d9cb4ce6522d1ab6badb52fc0901410455df966a59f39ca4e36c647ae8262e857266317bdbd22e566c623651579d12aefd987a8ffde2847459311a43951acf1d648d84d262edcf127e08b78d7759e5a8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a9142d7f6673e6c2f0ca90c96d05c3588f8a915c0aca88ac" - }, - { - "value": 3874500, - "script": "76a9140dc7c527d0175b7161c152a5476a826b1441f8f588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6a401ced94e43dee0acaffa906e73eb50dc4e83253fc52ad65eb5da5142af7d4", - "witnessHash": "6a401ced94e43dee0acaffa906e73eb50dc4e83253fc52ad65eb5da5142af7d4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 215, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "332a1dc6f54d54fc9efbdc3b466d08b7f4918706f54897e4df830cf3acf05011", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299928, - "value": 19359957, - "script": "76a91484dc7f03115f6ae77d49da4822c53899aa3d274e88ac", - "coinbase": false, - "hash": "332a1dc6f54d54fc9efbdc3b466d08b7f4918706f54897e4df830cf3acf05011", - "index": 1 - }, - "script": "483045022048fa94fd9dfad15e726b9c95766ee418a042b1972f98b6ebecf6ea2da13851e6022100fffafda29b474abc8e7796fb9b695f5b2c9109fbf77450a8ea61aa3fd5d3f83b01410492fe2c2153cf546472755d72644421b45a42356ac30bde263fc877cb54086c706fe22ffc90ba21f59f19acc59b31f8869cce0fe491b04ecc9ef5d89ff7824d68", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7550000, - "script": "76a91468974547af9bc1199d89335d4e1975984cc16c5c88ac" - }, - { - "value": 11799957, - "script": "76a91484dc7f03115f6ae77d49da4822c53899aa3d274e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0d5858163b0b16dc6ab877c915696a9f121522f524c228e35c3d5c33e941487f", - "witnessHash": "0d5858163b0b16dc6ab877c915696a9f121522f524c228e35c3d5c33e941487f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 216, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "62650f017ac2eb9c75a0544d992c527062823d579108545cb2a5479fb359b8a9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 67895568, - "script": "76a91400cc7e866bf6cf66f08e96ac114eae16408ec2f388ac", - "coinbase": false, - "hash": "62650f017ac2eb9c75a0544d992c527062823d579108545cb2a5479fb359b8a9", - "index": 1 - }, - "script": "483045022100a328092274e68f32c57084959a974e120e7883b0072322ae86e90fb995bac13502207c759d90ed46b891fe1b5e761085093baa439d271c950f77c2cff7f74895ddd30141046dda918dcb208cfb57b36987818a505be4e7a9bb2aab3120486d503747c91119ca105189d89f549ec10f277a996e47d514b1e95db54efd566a503b77a0581553", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2940000, - "script": "76a9147c3139e6f21b7256bba8f2394f8abc3c0bc7345388ac" - }, - { - "value": 64945568, - "script": "76a91400cc7e866bf6cf66f08e96ac114eae16408ec2f388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dc448c02e7e493e193c8a3fcf0f6921551775248b921843102874d97b1d0cf20", - "witnessHash": "dc448c02e7e493e193c8a3fcf0f6921551775248b921843102874d97b1d0cf20", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 217, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e5cff96e3375ef342dbc8ab44e8aa5459347c93274eb88d38c4be1772bf3771a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299856, - "value": 5642956, - "script": "76a914ceb7d42f4dfb254659cfb345e404629fcf80099188ac", - "coinbase": false, - "hash": "e5cff96e3375ef342dbc8ab44e8aa5459347c93274eb88d38c4be1772bf3771a", - "index": 1 - }, - "script": "48304502204f994f59ee2a2f2ba53a6ce7a7e4013c3c88f28116709e0db0504d5c7c0a56f5022100d37cf79ea4a0de816d86f3be1c4546e65d97a3383afb826f801513caa4aaed0f014104ca2d3ec3df5479559af23278dab1b56e29a308f2dcfbe1f41ccee450d315bc93cfc659038596171ca974363c7e7164efcebcd933e9816910166d85d70eec564d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1101370, - "script": "76a914d5e6cc809a6840b67e5db7249d0f5f149dc912a288ac" - }, - { - "value": 4531586, - "script": "76a914ceb7d42f4dfb254659cfb345e404629fcf80099188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6be72267c9a08e969702c412a53d1249ebe01cd32f0c33d62b6b33eedc26b3d5", - "witnessHash": "6be72267c9a08e969702c412a53d1249ebe01cd32f0c33d62b6b33eedc26b3d5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 218, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4908309e52f8c0e1ae37d35df4b5a6ecc6531d3d922a10375f5755f84847bd85", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 451918100, - "script": "76a914fcce3c65933d2b1122b3712bce84b837f581010088ac", - "coinbase": false, - "hash": "4908309e52f8c0e1ae37d35df4b5a6ecc6531d3d922a10375f5755f84847bd85", - "index": 1 - }, - "script": "483045022100cd472b036fbc36bb1243392db527a03ac5185ead55be1a4022baac0e3ed5b4a402201fe3414f0fe660b504995126888f902d493da9c5a231d87e10b4d02903a3cc55014104ece257102cb0ccc032ef90c1b07b9586c1fde787ef376bc03750fa64601062dda95ec5de135d8766bef7ae0797fec116f570f4420d338081d2affe3b770579c8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 33748100, - "script": "76a914c799e00b3257ad1dd78fc5fd56d1672212db7d8088ac" - }, - { - "value": 418160000, - "script": "76a914fcce3c65933d2b1122b3712bce84b837f581010088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e3602d237616ce22def4ab6a54215bfb65f06bf8bde555d26f5c66bac72252ac", - "witnessHash": "e3602d237616ce22def4ab6a54215bfb65f06bf8bde555d26f5c66bac72252ac", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 219, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a51e282d90b2153c1c5ec8f1840b2d4211f6d6eba36af1cbfbf905b40822d93c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299858, - "value": 3927449, - "script": "76a914b6cd135ae7fc316ddde9d2240a238d6d090cffed88ac", - "coinbase": false, - "hash": "a51e282d90b2153c1c5ec8f1840b2d4211f6d6eba36af1cbfbf905b40822d93c", - "index": 1 - }, - "script": "48304502210088e9145a33439b158927cd174e7835397f1b56375053150a5316065b4db6057c022061fc63afdb698582205d9a517b8a24d06c641c91d94903d785f2d306a77485290141043b9c8fd3c4eb06402830ba48a407f3749154d08dfbe91083728866202b2517f4369b1e5f62ba55f7909d347dc49a641c9f004e4da59947bf51cebdcaef1c6509", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2249700, - "script": "76a91449f5bd810958cd7d24557c05d891a6ee621aeb2688ac" - }, - { - "value": 1667749, - "script": "76a914b6cd135ae7fc316ddde9d2240a238d6d090cffed88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "68cac3f892a91a8a8939e9d1b9f33e3e5fafc1472f1508712390eb1b3c12b627", - "witnessHash": "68cac3f892a91a8a8939e9d1b9f33e3e5fafc1472f1508712390eb1b3c12b627", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 220, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2de7b1635076e9d484a279ead9d9c2a4877213c8c36aa292432a4cc5281a1cb0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299922, - "value": 5563141, - "script": "76a91480ec695555b7a305defce6509867ce5c4456ee1d88ac", - "coinbase": false, - "hash": "2de7b1635076e9d484a279ead9d9c2a4877213c8c36aa292432a4cc5281a1cb0", - "index": 1 - }, - "script": "483045022100965e4a22ebad94cb4dfcc02dead7b4faf1a262afbeb1c6b38696599a670ee8110220121867de333e197961ef31ada0d97566925c43a43d6134325019b6a41bfa5728014104652c30b28b3d3d6bd83d4cca8b1361af545640728930e9703177df06150984b703e50fcf9f2999f0d9fb2e6dd943d41ebd79216a756ae7b4f96ce7a352dae7c0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2202740, - "script": "76a9144bab299de43d5f6388f602c8febcdf67417db70b88ac" - }, - { - "value": 3350401, - "script": "76a91480ec695555b7a305defce6509867ce5c4456ee1d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "20e567b7035a956a07893bc3c06ffbee7561739ad517e072af2067e931c07884", - "witnessHash": "20e567b7035a956a07893bc3c06ffbee7561739ad517e072af2067e931c07884", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 221, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5e6c879a86b2bd4644c3dccf3964f21c814c4b3cab0f6c174fff8520905bfa34", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 225606319, - "script": "76a914843d0dc511df2ef7e13d312a7bd7a5c44c5bf2fb88ac", - "coinbase": false, - "hash": "5e6c879a86b2bd4644c3dccf3964f21c814c4b3cab0f6c174fff8520905bfa34", - "index": 1 - }, - "script": "48304502203d0179635a5f747a4cdc448078dcedf5add6297a6d61d65dcf2ccd29fd9ce254022100e49bfe71aceba593b6d2af99f97b4c47467ee09112e953dd9a957ba231132a43014104457fa673577c17a8c516bcdef8a74676363b2be363d0309dc1689821dd3b813744bdc9baafca51e1eb6f2e837dbd05549bf3d6257050d87da03d8084bf18d25c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 150000, - "script": "76a9145c84ebab10bdf995178e972e5aac94c6b1c5405688ac" - }, - { - "value": 225446319, - "script": "76a914843d0dc511df2ef7e13d312a7bd7a5c44c5bf2fb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4c99a15078620d8cd09d27728d5eab61594f0d56038ca60e00f00cfcc6551800", - "witnessHash": "4c99a15078620d8cd09d27728d5eab61594f0d56038ca60e00f00cfcc6551800", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 222, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bac9484d0e77a444a0b75c11aa9af6dd2b647bd74bb78488cc8409455e1f90f0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299942, - "value": 4564642, - "script": "76a91478770be5aca1444090fe32e272d5501847298c4b88ac", - "coinbase": false, - "hash": "bac9484d0e77a444a0b75c11aa9af6dd2b647bd74bb78488cc8409455e1f90f0", - "index": 1 - }, - "script": "48304502205821476ba097b211050bf5dc3eb243f7fb58d7a9c6fb18b86564e39301f976aa022100e15123824e89d8a97c8572c79cf2a6e03c5ba94769360bfc4b1a3c6684336506014104aa12ff1ffa41fe8328a5e2854c4b7f2875a3b9c57b100c69541f95b59dc03f2b5a863f72f133f74c74034304110959789bb2680d817bdba9f89234b01bae3308", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3083836, - "script": "76a914dab29e122ca01cfdc00fdea6d8d88f58fcfbe68588ac" - }, - { - "value": 1470806, - "script": "76a91478770be5aca1444090fe32e272d5501847298c4b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cbf77f93ee10fd668147435243688fc1d473c5c78998d95fc5989414f8fe3915", - "witnessHash": "cbf77f93ee10fd668147435243688fc1d473c5c78998d95fc5989414f8fe3915", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 223, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0cac8f5ff1c6bc9d7cde00649deea2af571948d40e4737e10b9a05948d226e41", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 33587834, - "script": "76a914d1149728645fd4648e86d0687e115246cc060cd788ac", - "coinbase": false, - "hash": "0cac8f5ff1c6bc9d7cde00649deea2af571948d40e4737e10b9a05948d226e41", - "index": 1 - }, - "script": "48304502207698f8e949394d5df22740b89f4ce7c6fa158e3a0cdffd60b261b9de294a627502210086142bb5ba20fa53342972d3d1982c012de6ead5a42d22e2c8d84fe41900371e014104361fdbdbdf0ce71d8df283700e9f7ba97367c6ad02955558de33da5fe86adb4bfff95f98a88ffd806072b2559d9d19439155ec16e4359178d84c4f9f044d6493", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 32807916, - "script": "76a91413cbf79e069e9fcf382fd9f18e664f17593e8b3b88ac" - }, - { - "value": 769918, - "script": "76a914d1149728645fd4648e86d0687e115246cc060cd788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7b4b94b9346f73cb469c930cb274732c6c3678b3651bf5688398fbaefbac83f6", - "witnessHash": "7b4b94b9346f73cb469c930cb274732c6c3678b3651bf5688398fbaefbac83f6", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 224, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e4efbae113ec2ebfed41b8c199da19b4f507000bdff28d09bcd6caf8f245e6dc", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 30221634, - "script": "76a914e349adac3e1cc84acb4173175c96b88f91576c4888ac", - "coinbase": false, - "hash": "e4efbae113ec2ebfed41b8c199da19b4f507000bdff28d09bcd6caf8f245e6dc", - "index": 1 - }, - "script": "4830450221008fbd513eb4a319b2398f282fdf704fdcd4e00ee4a4bba10ce51271abbe75208502207e819f980a19b644d81939f5e06fa30508d86b67a2d80308063510bf0cc21c5d014104aaa94a132f656c10d619ddce4f47e0e8c4a9f8354bba2a939d9a2b3e573595738c906ba6194d94db9eaf159da70d558bf8381679fcb7eef98e2a2e8489f1105e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3000000, - "script": "76a914e394c7029eb2c5d80480f284edc9bdf98087332e88ac" - }, - { - "value": 27211634, - "script": "76a914e349adac3e1cc84acb4173175c96b88f91576c4888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "349fd4c3cc1b1586fb7076af24bb2e0ebe2ac6d3cfdb7f334ce9caa189527a37", - "witnessHash": "349fd4c3cc1b1586fb7076af24bb2e0ebe2ac6d3cfdb7f334ce9caa189527a37", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 225, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7b4b94b9346f73cb469c930cb274732c6c3678b3651bf5688398fbaefbac83f6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 27211634, - "script": "76a914e349adac3e1cc84acb4173175c96b88f91576c4888ac", - "coinbase": false, - "hash": "7b4b94b9346f73cb469c930cb274732c6c3678b3651bf5688398fbaefbac83f6", - "index": 1 - }, - "script": "4730440220152f226d1a1eb61e640fdde196ff36e781c7c1162754426e096bd5f0e6b4f65802203e45aa481372229d773bef24879866fe8d524285825f96ecc5ace1fe59f66fec014104aaa94a132f656c10d619ddce4f47e0e8c4a9f8354bba2a939d9a2b3e573595738c906ba6194d94db9eaf159da70d558bf8381679fcb7eef98e2a2e8489f1105e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7000000, - "script": "76a914e394c7029eb2c5d80480f284edc9bdf98087332e88ac" - }, - { - "value": 20201634, - "script": "76a914e349adac3e1cc84acb4173175c96b88f91576c4888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b2b73f43ab422b8adb4e5cbbf58adbb61fe88be09bb48df3bbb8efb4586426e7", - "witnessHash": "b2b73f43ab422b8adb4e5cbbf58adbb61fe88be09bb48df3bbb8efb4586426e7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 226, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1497fcf78a31daa96609d5fbe49e27929b023a7603c7074ec20adda7285a0491", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 16576389, - "script": "76a91442929bff95b785ba7de16a75234f846f2bc5a0e488ac", - "coinbase": false, - "hash": "1497fcf78a31daa96609d5fbe49e27929b023a7603c7074ec20adda7285a0491", - "index": 1 - }, - "script": "483045022100e73f55722c9d9b11313366e14058b11be269b7b138ff44bbd8df089cd5dd944a02200f1aa923ae300936d6dc3e8022dab77e26daa4b41d6a6c5f48132db89239fd4e014104d8a8bc10249e7ab0ccd37697f19cedf0114c73e73bca542cb8e41ad09b89ead48f6e84cb383677aa1ad3f7c094948183c5d320c8a77a4707597f9d296cf962ce", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 12000000, - "script": "76a914a2eb9424d630941be52428941636c0caa31deb8c88ac" - }, - { - "value": 4566389, - "script": "76a91442929bff95b785ba7de16a75234f846f2bc5a0e488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6d6c61c07eedd91c023ec9bf67c6e2b7468ce6886984686bfb3bc344af4ca37b", - "witnessHash": "6d6c61c07eedd91c023ec9bf67c6e2b7468ce6886984686bfb3bc344af4ca37b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 227, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f0b29a54668b757af8020f63d3384a36b1ca7099cfcfa967c0f7cb81520705b9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 4725000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "f0b29a54668b757af8020f63d3384a36b1ca7099cfcfa967c0f7cb81520705b9", - "index": 1 - }, - "script": "483045022052cbfae8bda73fad86464f48f49ed7e2ce473bdf9f3cf0d60528be9c8e79f5b5022100a03aebf5712c56ab8226b4078105a274028a5d3d58089744028b762cbca294a801410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2200000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 2515000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e550b98316693e73d83da75300ad3faeb99a968eeda47edaa2214457207eaab0", - "witnessHash": "e550b98316693e73d83da75300ad3faeb99a968eeda47edaa2214457207eaab0", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 228, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6d6c61c07eedd91c023ec9bf67c6e2b7468ce6886984686bfb3bc344af4ca37b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2200000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac", - "coinbase": false, - "hash": "6d6c61c07eedd91c023ec9bf67c6e2b7468ce6886984686bfb3bc344af4ca37b", - "index": 0 - }, - "script": "47304402206d55388d8453e52e9ee91591872ec6a4224c9be6862e91ca7a57aa83d9df3d7f02206adb2e6c65eb9b55c562c98c5abeaf9aa93218e00843f0235359c7666bcd181d0121037bedeab7fcb8f05bc5fca2bb43525bd7af9f125035149ab4f48843db0ba37c8f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2180000, - "script": "76a91485c926cc9a4519a5789412dc8e5bbca5f0d1b86988ac" - }, - { - "value": 10000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1e4ae00f2afbb2921e9815209ece36be3412bd794db1759bffe95ae30ec1265c", - "witnessHash": "1e4ae00f2afbb2921e9815209ece36be3412bd794db1759bffe95ae30ec1265c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 229, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6534c0124ab957f1d0cd4aa42972e295a3847898cf7f5a851c404457866ca9c5", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 4295000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "6534c0124ab957f1d0cd4aa42972e295a3847898cf7f5a851c404457866ca9c5", - "index": 1 - }, - "script": "483045022100d79061140faca029d40084616f8dcdc65b2268e6a0bc4099e5190b419b638741022005e73c5801a2dfe1b8a8329a89cf7811a769c11fd889e2f754e22745eb5e92c201410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2700000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 1585000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5e5a3bb35ac6acf35a73189414f16aae35b4eb700143b157b30d98a6430372e9", - "witnessHash": "5e5a3bb35ac6acf35a73189414f16aae35b4eb700143b157b30d98a6430372e9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 230, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1e4ae00f2afbb2921e9815209ece36be3412bd794db1759bffe95ae30ec1265c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2700000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "1e4ae00f2afbb2921e9815209ece36be3412bd794db1759bffe95ae30ec1265c", - "index": 0 - }, - "script": "483045022100870325d85c919031e5a5a5d9bc48514c7a876d00fec86d72798059c9fde890ce022006b485e224414ccc04b1b79688dad3a535c70cfc1eaa61c35605abd754091b590121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2690000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1fafcb932f0ca6ff030b025fc322066490f15179864a3613727cd7451281981f", - "witnessHash": "1fafcb932f0ca6ff030b025fc322066490f15179864a3613727cd7451281981f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 231, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4eea84dc341083452c1aac0257ab454b36888d9ec5a2c95b56e5713d9dc3c1bb", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 12690000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac", - "coinbase": false, - "hash": "4eea84dc341083452c1aac0257ab454b36888d9ec5a2c95b56e5713d9dc3c1bb", - "index": 1 - }, - "script": "483045022100f272288ef212962632bdcd104404ebc3010cff252ca9b8b8079aaf0253e31047022070533b20c1829c23b3c629c8cf14bf8980fc9613b531b95e9bd15bcca1104505014104e104b1a7cdb22d7ee5acf80865fb952360ff0af8498a7d141a5fe4d33742ecfa42ec49ff4eb8313b57cefea35b9e916cb39fa1405b3b8944f369220094bbb3cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1300000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac" - }, - { - "value": 11380000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7e4c2bc61090dd222764e02d3f133d0d63c500d2c84e7fb34563fd6002fb2b0e", - "witnessHash": "7e4c2bc61090dd222764e02d3f133d0d63c500d2c84e7fb34563fd6002fb2b0e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 232, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1fafcb932f0ca6ff030b025fc322066490f15179864a3613727cd7451281981f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1300000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac", - "coinbase": false, - "hash": "1fafcb932f0ca6ff030b025fc322066490f15179864a3613727cd7451281981f", - "index": 0 - }, - "script": "47304402207e148ed939a477de6ccaaee0acc3fefd9a4c1c49794e3d0a5fa2909516c3127302202c2262deff8ba54815b249adf58719fe615fe5aa1f8ecaea7680028cf6527b89012103afd34045d7080e5f3d8fc0efab187951caed4b06571c7cc617d01d9abe8b36b5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac" - }, - { - "value": 1280000, - "script": "76a914cdd6cbd410b70ecbca00b02d0f962b710a7fdec488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ad1f912113a902413e4840c85bed595658facaf90e96b3d0cdde85f5b2ae7e29", - "witnessHash": "ad1f912113a902413e4840c85bed595658facaf90e96b3d0cdde85f5b2ae7e29", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 233, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dbc2c2bc0828ea7710d8c3bb8c01a39fd4bce45bafeba188b5c665a9f7c97e1a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 11564258, - "script": "76a9148444e446b0e0b673a9df7f9f141b1d69673c701488ac", - "coinbase": false, - "hash": "dbc2c2bc0828ea7710d8c3bb8c01a39fd4bce45bafeba188b5c665a9f7c97e1a", - "index": 1 - }, - "script": "483045022100fe87a415858eb22dd9d81505b3f55728ba5e72286fe968dd67fb1375beb57f9402205819eea0f13f6b79efd80dc1d08ba454485f274e99122ec86198f64e799952cb01410403a5971577258b52229714475e20ee1c66219861b22dabac28a42804beaf8e226d2b37c29a48ddeb92a4a8f2dcd939159dd7ff5baf56a92fd91261aeb7e1aa6a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1500000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac" - }, - { - "value": 10054258, - "script": "76a9148444e446b0e0b673a9df7f9f141b1d69673c701488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0b82b25627cecc831c8a48e19437fefcc81b18ebe8252e105f96c4f1b03d720c", - "witnessHash": "0b82b25627cecc831c8a48e19437fefcc81b18ebe8252e105f96c4f1b03d720c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 234, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "08ef4e9668846e3f11bb5ab6b72ac379fec4fcbb0d049723230a0cd4a686964f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 19047600, - "script": "76a9141d03bd9811980f07dc4c0561abf1dcfc18880d6088ac", - "coinbase": false, - "hash": "08ef4e9668846e3f11bb5ab6b72ac379fec4fcbb0d049723230a0cd4a686964f", - "index": 0 - }, - "script": "48304502202b01044f381d209e8c4ec4cb4a36095a8cf79b7314903202f9e41cb03b08e06c022100ca2220ac45b577647a3dca67638a24a4075e9d81b358658347ff40ba1479a35001410492c48d00c45f8ee6bd6f068c9fe677d1f8a95b672ad303840052e3d759303666789b47f19af568d36327cb861f1964d2bb2de6e7a486857b6a03f773e4590311", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 13216441, - "script": "76a914018579859d6e174b290ae7a8b34d1d0f98d2781d88ac" - }, - { - "value": 5821159, - "script": "76a9141d03bd9811980f07dc4c0561abf1dcfc18880d6088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "078caa9f781b2c346090929c36ff28536e11c840909b8afa61c383a7b82072d7", - "witnessHash": "078caa9f781b2c346090929c36ff28536e11c840909b8afa61c383a7b82072d7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 235, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "baffe65825ae2fd54a95cf14df0633be221a38bc3edefcbddc1e882bd1dc33f2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 8674181, - "script": "76a9140b5f9578dbedb411291669e1afe5b3ff66713ec788ac", - "coinbase": false, - "hash": "baffe65825ae2fd54a95cf14df0633be221a38bc3edefcbddc1e882bd1dc33f2", - "index": 1 - }, - "script": "483045022060c4e272d15fbba3aaa2e71277024801e0f067f21fe9e097c322e43ed19489b802210089aa8d83aeeebcfb6a2fbdcc3dca9cb17926145271ea9721c4ffeb0287ef90c10141046e38ced760e3ce6224ce481056c1e00120f571dc2f4254eca8051af62c6aa2c36dfb1f4c0ec3e0e24030829781f0c637ea5a9172b495e9c2b9c077c9fb277ef5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5716170, - "script": "76a914f52f272af1f6cba2b006c1fc9876cbfa483e5eba88ac" - }, - { - "value": 2948011, - "script": "76a9140b5f9578dbedb411291669e1afe5b3ff66713ec788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f18ece5101763235b57a5525d3a2b35999bdb02ea2bd9d5d9eb8f0d37398ae53", - "witnessHash": "f18ece5101763235b57a5525d3a2b35999bdb02ea2bd9d5d9eb8f0d37398ae53", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 236, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c3745da12cb1735fb6eb67646011de07b9400d034b4dc8dd09bf2cb01ba7b77f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 13741987, - "script": "76a914561f48bcaafdf1809487b54985775fede82556de88ac", - "coinbase": false, - "hash": "c3745da12cb1735fb6eb67646011de07b9400d034b4dc8dd09bf2cb01ba7b77f", - "index": 1 - }, - "script": "48304502202a1f6ab604ef55825983aca5d3156e0f687cbb88a7dd74e690f4268b73bfb59d022100f5eec48cfe9f482193bd042a510cd28d0194b6c9fecf51779f92e6cb174becc80141041a918391c618997d97422353f44d43b18717ced1909a517745593441970c267e64f698df5a2f2f887a6caeb4b9b46f35e902f9c4b65820bf3466ea2e1df9f370", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7929864, - "script": "76a9144800670a693aea48ff264000a2c1aade9aef18a288ac" - }, - { - "value": 5802123, - "script": "76a914561f48bcaafdf1809487b54985775fede82556de88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0404ec9a48dccbf49814989ae82d1a03f6082349cea5063b0c8c6aa9303367ec", - "witnessHash": "0404ec9a48dccbf49814989ae82d1a03f6082349cea5063b0c8c6aa9303367ec", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 237, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1bb9921704561de415bcd9dec76aba350646526cb065eef893ff86ac50860518", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 2695000, - "script": "76a914cd9f95c6872bd126ad562b7139310683cc2468a988ac", - "coinbase": false, - "hash": "1bb9921704561de415bcd9dec76aba350646526cb065eef893ff86ac50860518", - "index": 1 - }, - "script": "483045022100a3c8968e70e3721b5a3d8db5bb3d745b1f2209951ed094a91c7bafacd77521c302205d31b5f7dc3c736fa0241318a051f1fe2b2e3c459ab872b11695b0d49275205901410452f1ff1699cf346d57b522b8071789c6f824b90ecddd00e388e57b20f0a51bb7a75e90d075fc8a3b8176b57e3e704200413c7fdcb41a48a5320a9f1cb15a3700", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1300000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac" - }, - { - "value": 1385000, - "script": "76a914cd9f95c6872bd126ad562b7139310683cc2468a988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3b3fc7c04f2a34daa471d2552de578255e7463e7872ef3fe153074e390c8f136", - "witnessHash": "3b3fc7c04f2a34daa471d2552de578255e7463e7872ef3fe153074e390c8f136", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 238, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0404ec9a48dccbf49814989ae82d1a03f6082349cea5063b0c8c6aa9303367ec", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1300000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac", - "coinbase": false, - "hash": "0404ec9a48dccbf49814989ae82d1a03f6082349cea5063b0c8c6aa9303367ec", - "index": 0 - }, - "script": "4730440220117f80b0ddc6c043de65ef41fb2a8cf343ed4c930f9941cd7841c4ac95fa4458022064e6881d9787b54b5d7328475087226ea4a3538d456926bb4bdc2261a4a1a482012103afd34045d7080e5f3d8fc0efab187951caed4b06571c7cc617d01d9abe8b36b5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1280000, - "script": "76a9143dfeb05e14625b32bfe7be9c5454e599dc2d74b788ac" - }, - { - "value": 10000, - "script": "76a914cd9f95c6872bd126ad562b7139310683cc2468a988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0c4884af71ac4d81fc6017701a7cd8a129cde30cd9fdfbb097099b1ef98796d7", - "witnessHash": "0c4884af71ac4d81fc6017701a7cd8a129cde30cd9fdfbb097099b1ef98796d7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 239, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "27ec73c50cb9d99793d816f05fd4a867ec7d67c3a74ff463e27d67f12f7bde7d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3555000, - "script": "76a9145e93e0f7f835cc5c65d9f6c064b81767a2596de588ac", - "coinbase": false, - "hash": "27ec73c50cb9d99793d816f05fd4a867ec7d67c3a74ff463e27d67f12f7bde7d", - "index": 1 - }, - "script": "48304502210087eddc6a22125ba89b178bb469c77e83e39ef6fdb3ea12225ee3405092213d2b02202fca8213b84432e0a3c8013bcda79256ea1212510051477c508ff9ed786b2391014104bb5d8ac634cba4d445d19e231fe19234aefeb538aa699732eadec54ae538dc659a7e8835ffe6287a836f341c5dd9d5edab7d1496b260e0cdb01f50cd318c90d7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2300000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac" - }, - { - "value": 1245000, - "script": "76a9145e93e0f7f835cc5c65d9f6c064b81767a2596de588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3e072881a1e965ccabb705f2495e5c6ad85d81f868299bb83d3f848876e73820", - "witnessHash": "3e072881a1e965ccabb705f2495e5c6ad85d81f868299bb83d3f848876e73820", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 240, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7bc7d8837fb03518358cbb09da297f99c9b98663443025723817779fab0b0894", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3500000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac", - "coinbase": false, - "hash": "7bc7d8837fb03518358cbb09da297f99c9b98663443025723817779fab0b0894", - "index": 0 - }, - "script": "483045022060cf020cf444c9a194c63c96cb07c3511ba7850020287fd12aa00a278ebef830022100f442927349cf8ee06dba8a5b353f289fe405bca14942e207b29e418ed91970430141048372c61c205da3b5d1535fb2cfc18830af5f2ed8d06356657d514b47ee7b08bbe9265438708cef0c13738c52ae607c9e2cb6076697b7cea63b9e69dd1e98dd97", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1500000, - "script": "76a914626ebedca70103f5c1e06ed5904f0bc478a263df88ac" - }, - { - "value": 1990000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "44ef67b925432050bb10af2633f0bc499bb652e3697da5ccdb852b551241f851", - "witnessHash": "44ef67b925432050bb10af2633f0bc499bb652e3697da5ccdb852b551241f851", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 241, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "17ea52310ce51150addcaac5e17b2323e8c7800bdbedcb9b4336660f3b32df9f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6386172, - "script": "76a914c179b91aa8bd17ad055a27975287116c660cc24088ac", - "coinbase": false, - "hash": "17ea52310ce51150addcaac5e17b2323e8c7800bdbedcb9b4336660f3b32df9f", - "index": 1 - }, - "script": "4830450220280f03be53353209f084a22e2aadd6259cf24eb49b0b2e428d6e9585ac452e3b02210089139621595d54dfc46241bd54b6d74203b1ab51a9efc30128d84570339003b30141042bb3fdc58be4484c86337e1373d4a8a545231ca5b3520e5a64c25c35d865e974913faf17f83d8b6cf9b2aee637172cb74866b739706e3679baed121c91a7583f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a9145d21f93d690a60d67d5a28d32330a57dfbfd7f2f88ac" - }, - { - "value": 6366172, - "script": "76a914c179b91aa8bd17ad055a27975287116c660cc24088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2179eb00b5e2d800104a0d00d117c0d81ccc0d925ad27c396270c75a8b32e731", - "witnessHash": "2179eb00b5e2d800104a0d00d117c0d81ccc0d925ad27c396270c75a8b32e731", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 242, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fbadb361a0d96738184659e802a9b2c64579bca34394d5fd9d5457822690980c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 200000, - "script": "76a914da5dde8abec4f3b67561bcd06aaf28b790cff75588ac", - "coinbase": false, - "hash": "fbadb361a0d96738184659e802a9b2c64579bca34394d5fd9d5457822690980c", - "index": 0 - }, - "script": "483045022100e00eeac3144b7a9bc9abd891b6ae23b9c145b8e2d1e359c3c1b093bbb913a3c10220055a898c0c7a372ccb9fd4dc97789342ee801206878c6475b8f2b489865cddea0141049de1c8260ad5729982fa9589f0aa795a76dbd9695418c232963098eac9c1a2b3c74669555f94f6e3fe7800916a8e30651dc7eefdb82e773bb096358420818d5a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 160000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - }, - { - "value": 30000, - "script": "76a9144f2d8082ca48ed2f8cb5e8417c1bd17756796a5288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b9c1fe0ec24fc762ecaf06fd547158f89abdfd2f442cacda51f4a577646c4d3d", - "witnessHash": "b9c1fe0ec24fc762ecaf06fd547158f89abdfd2f442cacda51f4a577646c4d3d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 243, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "44ef67b925432050bb10af2633f0bc499bb652e3697da5ccdb852b551241f851", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 6366172, - "script": "76a914c179b91aa8bd17ad055a27975287116c660cc24088ac", - "coinbase": false, - "hash": "44ef67b925432050bb10af2633f0bc499bb652e3697da5ccdb852b551241f851", - "index": 1 - }, - "script": "483045022100898eeb46e230f14e3ac6f078844d9504e4833e9b611fd550de6eb95f7b6fd865022005ce53fefb14bbbf97e728bf61be18cc05c179f660429709e978e3e411c2f7b50141042bb3fdc58be4484c86337e1373d4a8a545231ca5b3520e5a64c25c35d865e974913faf17f83d8b6cf9b2aee637172cb74866b739706e3679baed121c91a7583f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a91464f1ddf8f325b19b4059436f1812ddd317bec81488ac" - }, - { - "value": 6346172, - "script": "76a914c179b91aa8bd17ad055a27975287116c660cc24088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dd4f2bfeb33c421067de9f833c19a1e36cff3ad2866fe883c0fdb99bf9faf7a5", - "witnessHash": "dd4f2bfeb33c421067de9f833c19a1e36cff3ad2866fe883c0fdb99bf9faf7a5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 244, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9ba6bbda4cd185f12d81ab7ef5f5f6e865ff0e8855f2743f6e15f464be151dfd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299346, - "value": 125983020, - "script": "76a91495365ba2fe4cf7fac8a159895b51d044af74802488ac", - "coinbase": false, - "hash": "9ba6bbda4cd185f12d81ab7ef5f5f6e865ff0e8855f2743f6e15f464be151dfd", - "index": 0 - }, - "script": "493046022100e42679fa50972fa3cd882cb1376c6ee6198e514bb7fca4a5fdbfebbe0a55748c022100fb56193229eca2448c79cfa2cbfa2ca1e2679979e3f13bd73e619626c80637de0141046d6556a505e02af5498a83450382d2ea926da1a7d1be057328abf9e8bfd09455f1abc71ac82266afbcfe05e113f061be907f4380c88a4cf424172d07b289ec47", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 592920, - "script": "76a914adf95b6304caef49ee8799a65e471f1ea1ffe21688ac" - }, - { - "value": 125380100, - "script": "76a91495365ba2fe4cf7fac8a159895b51d044af74802488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f15bf0bd183affa15f8da03b4fe327df2ee61a3241682cb2a75466146000334d", - "witnessHash": "f15bf0bd183affa15f8da03b4fe327df2ee61a3241682cb2a75466146000334d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 245, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a5407b3c4f185a21b29876da472f00c58f11847e99d873510ca6cf19f75a5c12", - "index": 1 - }, - "coin": { - "version": 1, - "height": 296690, - "value": 13966152, - "script": "76a914f6fad39e02a90d87c8379790548957f88d749fb488ac", - "coinbase": false, - "hash": "a5407b3c4f185a21b29876da472f00c58f11847e99d873510ca6cf19f75a5c12", - "index": 1 - }, - "script": "493046022100bc6babaaae9fbd81016551d13e0118311ef9d0ca9f8b4a7c1482f2844c7e86400221008a0cd454da1694c21801431c7701b964593aff727dcf4f3192aae5545b428c2c014104d4370857dad9a0159a9da1fa7d40aa2576c2484d9a8be5c3e97606b9b95094301c081fb20479e01c0780cd3865edd6ff176ea52ad5b3a1799e3e8cb93a2dea3b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1600000, - "script": "76a9141f1797bffa50d49f254f1c583ab7ecf846cd7fd988ac" - }, - { - "value": 12356152, - "script": "76a914f6fad39e02a90d87c8379790548957f88d749fb488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c140980f9f9ba3c6efdea31a5f1a39e2167cbf13bd6d35f635be96df71b36c51", - "witnessHash": "c140980f9f9ba3c6efdea31a5f1a39e2167cbf13bd6d35f635be96df71b36c51", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 246, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e888024c010ec2de9f11f07491bc24bf066a2dc3cd3d5afbc19221ba546afeca", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299952, - "value": 63598215, - "script": "76a914dd3ec87d40d60a9b3b22377a3e2947dbec5bd19488ac", - "coinbase": false, - "hash": "e888024c010ec2de9f11f07491bc24bf066a2dc3cd3d5afbc19221ba546afeca", - "index": 1 - }, - "script": "4930460221009e200e42e5ca989520f2085b0b3db9c806231e73dcb89a24f923c9aad88970ba022100d60fbeaee56b0c4a4e34800d136c6c0085d1fd016763cd28d0169c1486364100014104cde254dc34c5c13588d61caf3f562ac3b825506b7498bb1829aa4150a18d8bc556cd85fc7f052dbfa9e9eb60806a181b8178f1899dd726f03b3ad697114da0f4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1063800, - "script": "76a9146aa74d499f6cbd15705c55da9b739af7311f9e6e88ac" - }, - { - "value": 62524415, - "script": "76a914dd3ec87d40d60a9b3b22377a3e2947dbec5bd19488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4cbefa26add0b81214d07840fe05b16f1d82992ae671bab565026b1b641c29f1", - "witnessHash": "4cbefa26add0b81214d07840fe05b16f1d82992ae671bab565026b1b641c29f1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 247, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c140980f9f9ba3c6efdea31a5f1a39e2167cbf13bd6d35f635be96df71b36c51", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 62524415, - "script": "76a914dd3ec87d40d60a9b3b22377a3e2947dbec5bd19488ac", - "coinbase": false, - "hash": "c140980f9f9ba3c6efdea31a5f1a39e2167cbf13bd6d35f635be96df71b36c51", - "index": 1 - }, - "script": "48304502205fc2cddcb7e668a4ac773284e38dcda24fb98b826d7293f4d42c6795411904e7022100f08a3c2946a33df144c97e4ff6c560f0ca6b45d412de465d18d271605b11475d014104cde254dc34c5c13588d61caf3f562ac3b825506b7498bb1829aa4150a18d8bc556cd85fc7f052dbfa9e9eb60806a181b8178f1899dd726f03b3ad697114da0f4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8510400, - "script": "76a914e2a42a5a493f78a04a9cc151acb8d3935b4c694488ac" - }, - { - "value": 54004015, - "script": "76a914dd3ec87d40d60a9b3b22377a3e2947dbec5bd19488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "10b1212240fc95e871e57d931e478b96bc247a7268578f85cd35b41780e1b33d", - "witnessHash": "10b1212240fc95e871e57d931e478b96bc247a7268578f85cd35b41780e1b33d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 248, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4cbefa26add0b81214d07840fe05b16f1d82992ae671bab565026b1b641c29f1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 54004015, - "script": "76a914dd3ec87d40d60a9b3b22377a3e2947dbec5bd19488ac", - "coinbase": false, - "hash": "4cbefa26add0b81214d07840fe05b16f1d82992ae671bab565026b1b641c29f1", - "index": 1 - }, - "script": "4830450221009c5f6be86780d86c5a1337e9a9edf316e266a6a3cd383ae45775759d42d661b10220119130c5a47f5ee3cfc6657670dad41278b835611088179ae7958515f879ccc1014104cde254dc34c5c13588d61caf3f562ac3b825506b7498bb1829aa4150a18d8bc556cd85fc7f052dbfa9e9eb60806a181b8178f1899dd726f03b3ad697114da0f4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 638280, - "script": "76a914683167442bb5494d6193bffcc764cdfdc8cab0ca88ac" - }, - { - "value": 53355735, - "script": "76a914dd3ec87d40d60a9b3b22377a3e2947dbec5bd19488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "03fdc031253084fb38aeb2b5df00fd8e78fa6221c4fcad9fda7b08db36ca195d", - "witnessHash": "03fdc031253084fb38aeb2b5df00fd8e78fa6221c4fcad9fda7b08db36ca195d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 249, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "32903b49d8ca65c391d7ef6ad828498a773d99ce22bcb3701fc9a96e12bc7799", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299836, - "value": 8295799, - "script": "76a914754d6bef1ccacfe778d4e9cfd7cf8d3ea8729eec88ac", - "coinbase": false, - "hash": "32903b49d8ca65c391d7ef6ad828498a773d99ce22bcb3701fc9a96e12bc7799", - "index": 1 - }, - "script": "493046022100b6b69653ea289bfa25bf71b7aeed86a070136b84a13662850a8e00806140be58022100a34ece221db2cb9b90a6ae5f8147fdb54fff3394fd5e334f79fb7a305d3114800141040685ee97330b73d172f0e36116ce3c63de1f17f77fee56c0c4066d8ade29c71eb4ac204f054fae55e837703ef3ee25f73c6cd6601f4935232b73785cd05a7cb0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1101370, - "script": "76a91434bffa7b589c48f21ce9f36c11dfa529622a743188ac" - }, - { - "value": 7184429, - "script": "76a914754d6bef1ccacfe778d4e9cfd7cf8d3ea8729eec88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "82ca8cea3231d27efd6237cbaf37507a26e2345dbfad376c47776e5b351e2a9a", - "witnessHash": "82ca8cea3231d27efd6237cbaf37507a26e2345dbfad376c47776e5b351e2a9a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 250, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "87490fbcb220e1488582045f36bcbaf5ec2e74ede28dfc6cf119511538d3bd0d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299881, - "value": 9304634, - "script": "76a9149bb5b8fbbd84ebde4eebff1f9429a166872c60e188ac", - "coinbase": false, - "hash": "87490fbcb220e1488582045f36bcbaf5ec2e74ede28dfc6cf119511538d3bd0d", - "index": 1 - }, - "script": "4930460221009d671cd5d471adb29ef56e2834bac174793bc5a34f3f3b31ebb43d055ffec3f4022100d006b1cb44fa5d9b9a7d2c5d487eaa4eb10e7d961db629c9c9d620835934410f0141048aaea05170de8de41b1f23aa1ff72e14c09caed0a5a2d50790a57bc24ba8952a49911c6e793fba5f7b592f601a6bd14c10e1ee719c6318da7561c8869045511e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8000000, - "script": "76a9141362af1b9b8b8a63ad26ce80dccd73b54741e80388ac" - }, - { - "value": 1294634, - "script": "76a9149bb5b8fbbd84ebde4eebff1f9429a166872c60e188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "69fe925b4dd1581c41382606ad94a23213b89d1f204b658f2a1148059753ac04", - "witnessHash": "69fe925b4dd1581c41382606ad94a23213b89d1f204b658f2a1148059753ac04", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 251, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d935d5b80d9ebcbebbc1eefdb1c54bfd9aa1df11ef6f19af22e9f823fd198b29", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299867, - "value": 3090313, - "script": "76a9141f1e3606459c3e48be39ded57a0d01e1b3fe84a588ac", - "coinbase": false, - "hash": "d935d5b80d9ebcbebbc1eefdb1c54bfd9aa1df11ef6f19af22e9f823fd198b29", - "index": 1 - }, - "script": "493046022100c988e3590da66c7f3918db91750ec43d817b7352b88c7f0da29496d8033b225f022100f39deb410012de3e1530ff2f86e42b1a3e2cbefee728728eca1fefaedd849469014104c70e5ba5dc59ad32ccf7c28d43c957a54bbbb112c8a9ce471e717677cebb8741afbe9dbfa3afd8414dbc5212df5fe36a9c489f7c01fac7e3192cd512cc415e1c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2423014, - "script": "76a914b891a424d36f8b151a3c8849824ec6eef284208e88ac" - }, - { - "value": 657299, - "script": "76a9141f1e3606459c3e48be39ded57a0d01e1b3fe84a588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c9f44fd8e7da7146faea3333b87fd5ce43898e92483bef616791c298750727ae", - "witnessHash": "c9f44fd8e7da7146faea3333b87fd5ce43898e92483bef616791c298750727ae", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 252, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "46e328575f03f84d33fc2812f1fb254701dc7b0ab1bfad71c32005fd6d615dd0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 154234127, - "script": "76a914d7e2f7dc589805cc35acd69917b8b50bc8e2d25688ac", - "coinbase": false, - "hash": "46e328575f03f84d33fc2812f1fb254701dc7b0ab1bfad71c32005fd6d615dd0", - "index": 1 - }, - "script": "493046022100b4cab34998168abc0a34d572bac12d4bd5db6ec9468aaad01f89d5f143040791022100a59f62b82a953e91cde9fcc49d238be2c6bbd3e82d068c623d020afc961b3e7f0141043f298e70bd14602db14f9aebab331f31478fd17932369f06cf7078e5712748538d97dd878afa4aa70b1d445148b463525d8bc1ca33dc185324857c55fdfa0ecf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 71600000, - "script": "76a91406724f1efd2210192719ba63ddff5966078f2ef088ac" - }, - { - "value": 82624127, - "script": "76a914d7e2f7dc589805cc35acd69917b8b50bc8e2d25688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1ccdeaddb5f3e8dbef55877c356286ae5091982876a8f603510c4cc5a6bf883d", - "witnessHash": "1ccdeaddb5f3e8dbef55877c356286ae5091982876a8f603510c4cc5a6bf883d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 253, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c9f44fd8e7da7146faea3333b87fd5ce43898e92483bef616791c298750727ae", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 82624127, - "script": "76a914d7e2f7dc589805cc35acd69917b8b50bc8e2d25688ac", - "coinbase": false, - "hash": "c9f44fd8e7da7146faea3333b87fd5ce43898e92483bef616791c298750727ae", - "index": 1 - }, - "script": "47304402203963c39227b0c39b4f14a0c89b5adeca392c487b6c0e852381c73c3c0783f8a0022075618f1452e1e360d61a024a315f2c75c0589339685bd5d6c16ead38d138473d0141043f298e70bd14602db14f9aebab331f31478fd17932369f06cf7078e5712748538d97dd878afa4aa70b1d445148b463525d8bc1ca33dc185324857c55fdfa0ecf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 26432882, - "script": "76a914b85db9015f80317ddf83ec214fc800a01a72e6db88ac" - }, - { - "value": 56181245, - "script": "76a914d7e2f7dc589805cc35acd69917b8b50bc8e2d25688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2e4886a6598f9d72ed2e12962535cddc8c6724585ef334df799004e351f00b63", - "witnessHash": "2e4886a6598f9d72ed2e12962535cddc8c6724585ef334df799004e351f00b63", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 254, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c8b6c0a36591f5d27dfcae0043bdee32025ec968a63ffafa5fae28aaefe5e9b2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299977, - "value": 5909423, - "script": "76a914d4cc87aa968ded6159e3977288fbeab404c55e6d88ac", - "coinbase": false, - "hash": "c8b6c0a36591f5d27dfcae0043bdee32025ec968a63ffafa5fae28aaefe5e9b2", - "index": 1 - }, - "script": "493046022100cc0395f028cdffd7db8902ee9d98037a9d55448b60c7a0f735c61b8a6e3dc2280221009be489211cdcb314b534002530cbeffcadf914a92d3636bc3553997b2f7868b6014104dd8b2e57950abb2db798db7ffd64b654f7ac98acf8d9f0d3dba26379fbb606710d14104082d5c2b500b74dac11318d3f9023f2c339eef840750c1260191a8459", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4898507, - "script": "76a9141bf32fd0dcda2c4520e9afe40b808382e66358e788ac" - }, - { - "value": 1000916, - "script": "76a9146558272fd380f66018a7aac9fb0ea2716eb2c58c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c36270b66bb5dfa23705ccc60b5704c1ebaedba4f69e98c2873192860df11c2c", - "witnessHash": "c36270b66bb5dfa23705ccc60b5704c1ebaedba4f69e98c2873192860df11c2c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 255, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f8e2c9e66cddf243156b56b93cade9aefff9fbf57e6490965c9103814bc4d528", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 115190000, - "script": "76a9144c738e6b29087f4ddbbd60a3381085be6565124588ac", - "coinbase": false, - "hash": "f8e2c9e66cddf243156b56b93cade9aefff9fbf57e6490965c9103814bc4d528", - "index": 0 - }, - "script": "47304402200fc192d5b3517468e084cfab78cee21ec95a273f8bb56a9a206e45035b6d541a02204e962f4adce7db9d2ddd99d48be91f5761260b03cd31546e4e0219e0c19103d4012103eda49e07cbefc9de47db505b3d700eefcd3e7f4310277af97506fc296a0b3491", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 42570000, - "script": "76a9147285548034a89436aec5e1970d34e1516d34546388ac" - }, - { - "value": 22610000, - "script": "76a9144359a4025a8d4e644ded9a3785e16a2da34234ae88ac" - }, - { - "value": 50000000, - "script": "76a914b920c58148f0030a48f1f93d8ba8c1b7df0c7ae288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b0db1eb42d06722fe8ccd0b176200780cbe1d58a2ccbe2bc3385778426445d43", - "witnessHash": "b0db1eb42d06722fe8ccd0b176200780cbe1d58a2ccbe2bc3385778426445d43", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 256, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "50b308a53af350026caa7c037174ef3233534cddf6c18420ccc73bb840e23e9f", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 22000000, - "script": "76a9141953b04e59fd30b812dd4bbe5ef22df0f3a3fb3c88ac", - "coinbase": false, - "hash": "50b308a53af350026caa7c037174ef3233534cddf6c18420ccc73bb840e23e9f", - "index": 3 - }, - "script": "493046022100e99996753241b760458bc04f25cd2690874ddd7690629a14a1f1b97d8f7c5867022100effd17eafa2bbc8ebcc3c35a1411887df9db193905279c315a6081686f906083014104718d794c7407857d0789ae6bfb820a74a17325fc5f7b4c630f431c726c1592b225736e6396eb120302e2f886c965d43bb3f6a5dd09d940e2b3c4c88765cea49c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 20000000, - "script": "76a914b6ec0e1941b07a89e9d13711b98cd8bedd3df04d88ac" - }, - { - "value": 1990000, - "script": "76a9141953b04e59fd30b812dd4bbe5ef22df0f3a3fb3c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "960f8dafb590e8a1dc894b5c7c91f354806b47619b487f45cb5468611a28f771", - "witnessHash": "960f8dafb590e8a1dc894b5c7c91f354806b47619b487f45cb5468611a28f771", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 257, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "174d935731d119ddaabbccdc59858cad6f6ea52b1268f602e93bd7445994f822", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 12845612, - "script": "76a914663a6875c51af9695719ebb20870dc727a71a3e088ac", - "coinbase": false, - "hash": "174d935731d119ddaabbccdc59858cad6f6ea52b1268f602e93bd7445994f822", - "index": 1 - }, - "script": "4930460221009933db5738757c5038f38c46d8bbf6e7b1d6e56482d7b1bcb588f6a8c3126a7e022100f12f6121bf11bd4aca4f6db5690114c83bbfa5f0685b80fa04c38f9a294b984a014104ee46bd5ddf14716980a35b1e55f14f22e44ba6c0f30391f0ab3659ba2469b9caed98785d724434d3a62cfd744419556225a2d493e38c2397044b178c88561b2e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1700000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac" - }, - { - "value": 11135612, - "script": "76a914663a6875c51af9695719ebb20870dc727a71a3e088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d653bf013a522038cb00b121ab1bd2cc46b0530999504eecbdeca19e8c7bcf3c", - "witnessHash": "d653bf013a522038cb00b121ab1bd2cc46b0530999504eecbdeca19e8c7bcf3c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 258, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ceeebf9630c6b939ff57e4dcec990dd2d9f792715e0a98b3c8d2e29f581c99b7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 113339, - "script": "76a914b70acd4adaf63cfbbe5b267a849fc9de81f0c0ff88ac", - "coinbase": false, - "hash": "ceeebf9630c6b939ff57e4dcec990dd2d9f792715e0a98b3c8d2e29f581c99b7", - "index": 1 - }, - "script": "493046022100b0e242306c239a5478182e2ec8df49d7b3b793ead04fd3e76391998fb515fbd8022100a9437572af2e096b6913015c35af9a08236d36ffd509641393ade89579fe9f9b014104debace441b5f0913ecc7c5c13abca6b8e5fb55f3badccf749bc71c8cd3f9bb8320671704cc7de021098d5cf4ee8ebe206ab0f0d864fd0249a07e5e238c5608b3", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a914a6cae03273e3b222b0ba961af4edef985afb6e2188ac" - }, - { - "value": 3339, - "script": "76a914b70acd4adaf63cfbbe5b267a849fc9de81f0c0ff88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a31ac72ea45ee4202f3245970eeee184e857f48578f33c01884ca3cb587bcb3a", - "witnessHash": "a31ac72ea45ee4202f3245970eeee184e857f48578f33c01884ca3cb587bcb3a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 259, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f3b7656e82208908d29d4bdb70bbecf626152a3368ce0f17532dbea0ebe0eb35", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 67475033, - "script": "76a914ef7cd1e582b1f964cad30f26e677e6fc6efe1c2d88ac", - "coinbase": false, - "hash": "f3b7656e82208908d29d4bdb70bbecf626152a3368ce0f17532dbea0ebe0eb35", - "index": 1 - }, - "script": "483045022100a5127e90182de8ac16644b68bd3ca082c87a8ef0aac535b9488f009ee52f5f2e0220192cb3d641ad5e11d3ce393da20e43c56d91b64c3e84a8bf4f4aeedbc9d5f313012103fd126359c8b3e890a731f8aea3cf1330cf44ed8be155f3c4c4f40dea0dc55798", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 27042124, - "script": "76a914a7a189c5b845dd660252d756604b3bff1ba59e1e88ac" - }, - { - "value": 33622909, - "script": "76a914c166138e76bff4ca8b7b74e32c6502e323dd856d88ac" - }, - { - "value": 6800000, - "script": "76a91441aabc9ba8e803d9418dadcf79ca95adad0c298688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "956cf452111df32a32c12e30d4e9ccb2734b1e91f317bcb462a43f3985a0a891", - "witnessHash": "956cf452111df32a32c12e30d4e9ccb2734b1e91f317bcb462a43f3985a0a891", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 260, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a31ac72ea45ee4202f3245970eeee184e857f48578f33c01884ca3cb587bcb3a", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 6800000, - "script": "76a91441aabc9ba8e803d9418dadcf79ca95adad0c298688ac", - "coinbase": false, - "hash": "a31ac72ea45ee4202f3245970eeee184e857f48578f33c01884ca3cb587bcb3a", - "index": 2 - }, - "script": "48304502210085581df33e16a15ee57df37feeb3286cf6b3b5dbba262ca028e19dd155910f8902206f0e8771e20b83e5994f2f7fd33dd0974fa0f8ced7a44767e306687f7842f6e8014104e05c542111b58bb2ba9ba193a155c21746d875695f475c5a9a04c5a3ea02dacb74e63725391cdb0c047b03b268219e5547a84abfc97a8dd861df4ba6dcd1e722", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4400000, - "script": "76a9146dc7c0e4bf5583ea138c1d47f52ef6fc1c03829588ac" - }, - { - "value": 2390000, - "script": "76a91441aabc9ba8e803d9418dadcf79ca95adad0c298688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fe4c0431c4bd2d4692ec5144cc72268452f56c558e2853cfac7c4a18636c31bb", - "witnessHash": "fe4c0431c4bd2d4692ec5144cc72268452f56c558e2853cfac7c4a18636c31bb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 261, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4e48982a02b6713052415d247ce4f3b90361eba4bc29469c170a82b0d16e40e8", - "index": 124 - }, - "coin": { - "version": 1, - "height": 297987, - "value": 37077, - "script": "76a9145a30419ab4d99c549bc812127f769a8e0580f5e688ac", - "coinbase": false, - "hash": "4e48982a02b6713052415d247ce4f3b90361eba4bc29469c170a82b0d16e40e8", - "index": 124 - }, - "script": "4730440220314f93fe2ac323b14f142db14c99e1179de1ed9ca601ab6e4c87b2e7611c543b02206b987575585fbd8a025ef7c865b1ad7212504336421659db822f18812377d6950141045f2f5e1af54b5d69ef1613e4af6ca8103a9d2b65ff2e1e597950b9f590a1fd14d9853b95c40d3fa3e9a2bff2337da4d55f3e8c7f6d904c69d6452e86d4b5e00b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "df91f2539f7cff93d7f466ee16671d475e03805285996aabe2ced48baabcd91e", - "index": 139 - }, - "coin": { - "version": 1, - "height": 299087, - "value": 34606, - "script": "76a9145a30419ab4d99c549bc812127f769a8e0580f5e688ac", - "coinbase": false, - "hash": "df91f2539f7cff93d7f466ee16671d475e03805285996aabe2ced48baabcd91e", - "index": 139 - }, - "script": "483045022071bc7fda22b23991b995d984051e83a7b289ae728794b4a99acf4e23a4a4a6ce022100ebbbdd90f5ff98c586d25e828992288c7b459eed97378d6cc9a5756784ba32d20141045f2f5e1af54b5d69ef1613e4af6ca8103a9d2b65ff2e1e597950b9f590a1fd14d9853b95c40d3fa3e9a2bff2337da4d55f3e8c7f6d904c69d6452e86d4b5e00b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "89a24eaeec8590a696d23ca29f467ceca116022c2d1e639f47d8fbbf48f99478", - "index": 9 - }, - "coin": { - "version": 1, - "height": 297652, - "value": 10767, - "script": "76a9145a30419ab4d99c549bc812127f769a8e0580f5e688ac", - "coinbase": false, - "hash": "89a24eaeec8590a696d23ca29f467ceca116022c2d1e639f47d8fbbf48f99478", - "index": 9 - }, - "script": "47304402205f50c3d65089bfd04ebd6d642d5401c13af842456da1d66f34baefe481aa5c11022063d698404c40bd3dae87f2e7c505fb98355f8416f265e1215e643c64521b25440141045f2f5e1af54b5d69ef1613e4af6ca8103a9d2b65ff2e1e597950b9f590a1fd14d9853b95c40d3fa3e9a2bff2337da4d55f3e8c7f6d904c69d6452e86d4b5e00b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "64470d3bf13c50d4f2378e7f50101d698ad6597831e570a389bdac12b6536e63", - "index": 144 - }, - "coin": { - "version": 1, - "height": 299317, - "value": 6795, - "script": "76a9145a30419ab4d99c549bc812127f769a8e0580f5e688ac", - "coinbase": false, - "hash": "64470d3bf13c50d4f2378e7f50101d698ad6597831e570a389bdac12b6536e63", - "index": 144 - }, - "script": "473044022059721332dc7c9a9b41aa554598e6e940288505e86b7afead1dc05c90315eb19c02202537a9bf2422ddda927ef0858b7c9dce42ecee8c4edae199e23a1c095c91f37c0141045f2f5e1af54b5d69ef1613e4af6ca8103a9d2b65ff2e1e597950b9f590a1fd14d9853b95c40d3fa3e9a2bff2337da4d55f3e8c7f6d904c69d6452e86d4b5e00b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9b58787ddc94e5dbaafef3419e9ad1044b43d3ce52e26b8cb7229ce86c1d12ad", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10755, - "script": "76a91413a9638b2bc3da07180bb8be7a14567d46fc2f5b88ac", - "coinbase": false, - "hash": "9b58787ddc94e5dbaafef3419e9ad1044b43d3ce52e26b8cb7229ce86c1d12ad", - "index": 0 - }, - "script": "49304602210082cd3e4247f30245340a56f88833f6f95f08a7434ff2ca3df2d29b8b6a613edb022100f38d0bbc9249caee9d8ebf9ce92cc0dd1db6d672553a84241d01a1bbf369610c01410401f1eb52be64bf0a01e827e9ae2071a9669377ce562fee911e970f6706c1233a6a1bc2ce4a9d51441fdc91df38fd2bf2a1dd9a0370d53a3a8093d72047cd13b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d0eda35dc246d70581a78d58e50031ad3368f2142c0bdf0064571ffdceec8259", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 57452, - "script": "76a914311bbb9844de9cc952ef6c24318a7c82bb75ce3988ac", - "coinbase": false, - "hash": "d0eda35dc246d70581a78d58e50031ad3368f2142c0bdf0064571ffdceec8259", - "index": 1 - }, - "script": "483045022100bcaebc697b078d45664ecfe474ff792f6e1a1648d6868a63be9b56b800b36884022049704ee9265fe0fddebe99613697bf65348129c4a2c77d768e21cd3cd98873bc01410496cff7cc27469012490d95c7c5c7189f5c53abd3b2419329f5b96d5cba3702bd25c29d9403e67c04bf5a45272cb0a387406816be5af47a26d02927c85b58d58f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a9149a5175b09049b674b7b5b659230ff78adabc819b88ac" - }, - { - "value": 17452, - "script": "76a9145aac97b4f430fdfbb12f1e19680fdd1e54074f5c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "73dd6bd64e371d910cb43c8cba3615e052f1979fd4e2209045a45e60b220e6fd", - "witnessHash": "73dd6bd64e371d910cb43c8cba3615e052f1979fd4e2209045a45e60b220e6fd", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 262, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4d50fcadac303a75b90aeae53cb3dedabd33fe77d6621fd26bab93a56db5b17f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 91568904, - "script": "76a914d5a634cc7c2c4478d3167526bde5ab17e3079a0588ac", - "coinbase": false, - "hash": "4d50fcadac303a75b90aeae53cb3dedabd33fe77d6621fd26bab93a56db5b17f", - "index": 0 - }, - "script": "493046022100a311f86102f630f7f083e758447dafb9d78791ab387ebe42264224f1055d3284022100aa3154b1358863a510d606dff6b0969e6c2a6403f59f20cd32a1414213322688012102eddf84e64b18c4239289710039b277e1981afd26e46c33457972f27f8b737875", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 203663, - "script": "76a91461284f721c52b35b390a993c2574786299d56d9988ac" - }, - { - "value": 1642197, - "script": "76a9148baa20222b40d0df0983d12ea837bcb1a1aa2d6f88ac" - }, - { - "value": 85916615, - "script": "76a914ecba1f348e935944fad9c8d731cac0975fb168a488ac" - }, - { - "value": 3796429, - "script": "76a91416e5c621741c98f1a1f8fdea171de449e5e0903c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "df0df5927461c0640e291303bed558e029b177b0341eabb5ea2369d6adb746a2", - "witnessHash": "df0df5927461c0640e291303bed558e029b177b0341eabb5ea2369d6adb746a2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 263, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ef5cb271c0a6713765e37a38ac83c89576961e60f564948ee5fce43269b62aac", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 50000, - "script": "76a91471045f0ebc56873501033435df2931de7867277988ac", - "coinbase": false, - "hash": "ef5cb271c0a6713765e37a38ac83c89576961e60f564948ee5fce43269b62aac", - "index": 1 - }, - "script": "4730440220259c499c4e2ed6030e9bf70327553d0bf93dbf01dcf16fe90bd2e0d1b98def9202200598eacfcc6ba1c5403b04287977c2bb3d23e69063488a07ab12861e7725b4fd01210264af1414a01efb0c0381767acc16cf5f271ba49d3a3272b60520da7c95a85c2b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10860, - "script": "76a9142fca5bb48ef3f0b4f4ad6089229fb4c72f809d0388ac" - }, - { - "value": 10860, - "script": "51210264af1414a01efb0c0381767acc16cf5f271ba49d3a3272b60520da7c95a85c2b211c434e54525052545900000000000000000000000100000002fe293fb30000000052ae" - }, - { - "value": 18280, - "script": "76a91471045f0ebc56873501033435df2931de7867277988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "93f44874e4f0ac55143bc43787370e7335328c5e78073c54ce097852b09c163f", - "witnessHash": "93f44874e4f0ac55143bc43787370e7335328c5e78073c54ce097852b09c163f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 264, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a527777401b6226df9b475bdd604fcd0c788efe86b34b9569aa6c430a54d2b45", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 9990000, - "script": "76a9141b66ec7e15fb997a12437c6ee738caffb2c20bf188ac", - "coinbase": false, - "hash": "a527777401b6226df9b475bdd604fcd0c788efe86b34b9569aa6c430a54d2b45", - "index": 0 - }, - "script": "47304402202a23e1f94f8096180c21661d4c2d830e4c7514d93676ed197a1345f2c8d508b10220077c54e22896bc4562846809f907cfac5f7306bd32b370b7b433ea16319657e2014104a20f6afc38b6651fc4157bc2952250376df54ee93111433619fd388f29d8e16eaec8c353a0be7e03351665fa3dea4fb221eba11ea9840bd121ca6ec46d15b2e0", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ef53a89eb4669d9199844eb61b1264606665786fc04f5c5b1b7c6d23fe6cc450", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 36600, - "script": "76a9143dbaf28bb5dedbb39a72f261f5eb6b7720db4ca288ac", - "coinbase": false, - "hash": "ef53a89eb4669d9199844eb61b1264606665786fc04f5c5b1b7c6d23fe6cc450", - "index": 1 - }, - "script": "473044022017a2df36af5ffde06a2e02bcfa201ec0fe5eb3af61f1808458cfb30f8a83232c02206f96bffb78a775d745bbe2172584e1fe7428c1b14e8a874ed3980e0f3906084c01410430eb0627e96950a23274147fcb42a21ffb29f9deef4197101f60f447b7f137edc5a10a7f66fe29654aad256b0c7e68066100e05c2394c8d813b0e08bf6f65ffd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "47d0496574e703fa2400cf432068af6789907e1297b953958a482fd09bafa425", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 97439, - "script": "76a914f191e4163cae81b0221f3b77bd7d26b15f9d96b288ac", - "coinbase": false, - "hash": "47d0496574e703fa2400cf432068af6789907e1297b953958a482fd09bafa425", - "index": 2 - }, - "script": "4730440220518706919eaf1d56511c37b119a11d690311cf3309b36cc46f6cb6a4da55c87602207a81dbebbb9d4d499b87d39f751e4a259ed1f94f8948fdd1e7a0e1546c27fad8014104fc1a919c47c986666daa5715ffc024906f2d02c3ace83a2355926f28184aa2954ff1f600a3cc4e7e8f9d98c07259a823d08b14ba0316c4ee204a40a077c1106b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10026600, - "script": "76a9148dc8942f8b0a2a16aea83a13713fe89ff85281ed88ac" - }, - { - "value": 77439, - "script": "76a914aa7ce2637640a00bd792acfa493b3e1ca99379da88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d582986875c017e9ccf8308e7fab725f3751d6af60bb68c03101c24a5e9bebbe", - "witnessHash": "d582986875c017e9ccf8308e7fab725f3751d6af60bb68c03101c24a5e9bebbe", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 265, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e0b73d77e8a3e375dc74de675cebbc9dbce08b536810643c284cfec44bbbf5cf", - "index": 131 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 5707246, - "script": "76a91461783e6bcc1cba0154f76b3110e888173da2a81588ac", - "coinbase": false, - "hash": "e0b73d77e8a3e375dc74de675cebbc9dbce08b536810643c284cfec44bbbf5cf", - "index": 131 - }, - "script": "473044022063eadb3079a1434d63baf8536a3870c2e800d2ef5da485e6bb9fdb0c766df3f502203474987130ee0d57388cac3060291f3a3f3aeaed0a3af5585a1621e9d1e68d600141040952242c6c86577a3e399add2d46e2c7f0c8ab00ed1bc2d505f52e4f900fd560f3bc921f5f43505d2b700fd50e67082173321b3ae41b685ab17dfa8185d2ef4a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 50 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 5699108, - "script": "76a91461783e6bcc1cba0154f76b3110e888173da2a81588ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 50 - }, - "script": "48304502200ebf21c75e1106a16054d9bfb546d7f8ee1bee8916da47319eeccb3dd9e175a902210084f96189990fdd5c5616a004f912e4ac624410cb3748ecd6a6e5f61f87ea2d660141040952242c6c86577a3e399add2d46e2c7f0c8ab00ed1bc2d505f52e4f900fd560f3bc921f5f43505d2b700fd50e67082173321b3ae41b685ab17dfa8185d2ef4a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7c8c0539ce911a62977b0302d31689926466316f46d43f647b7141e67b66ce5d", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97491, - "script": "76a914e979f17d39248dfcd6eb59ee61ab6e697476952188ac", - "coinbase": false, - "hash": "7c8c0539ce911a62977b0302d31689926466316f46d43f647b7141e67b66ce5d", - "index": 2 - }, - "script": "483045022004270173af41b5c68726f6eed3e027b16f151dd31870290eb49b04842065550e022100a0818536187ce8fca23aed1d3cad1f0a72903de62098c7c30b9679ec3fd44ccf0141047bc7ab950328c883d20a6d76d015208da2e90f74f49c39680e6ededa60b27c7e3996164ef2a53bdce7f5aa66377320e078cfe6257c2d366ff340f07418ddd3c6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11406354, - "script": "76a9141b383f5afb738a8e8c3acd9aa0b3ecef7c98a6be88ac" - }, - { - "value": 77491, - "script": "76a914249244181c84e4a29dc0ebcd1d9a464c46b8b10a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "73d46ec04381099858e54f5cb378e43f0d705c86d1659f3cb363c079c8155c6d", - "witnessHash": "73d46ec04381099858e54f5cb378e43f0d705c86d1659f3cb363c079c8155c6d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 266, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c65cc917b9826fd4d1425512f436324b882bd3a6cbbeb51a5e288a88093c67a2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299858, - "value": 2237000, - "script": "76a91471b8452f49797b8bf1a33784c29d93823d4f6b8d88ac", - "coinbase": false, - "hash": "c65cc917b9826fd4d1425512f436324b882bd3a6cbbeb51a5e288a88093c67a2", - "index": 0 - }, - "script": "493046022100d69526989fa11225f387fe40051a532f851d91c6cb45d89b647c3ebc46e5901f022100d8ad24b147b6bcf1c244a22425fa4fa242d75b80968ea237129f20bfd6da0c300141047f47c5e4ec8a8b51857896562cb99cf4ec4239b851c5ee6eef7d28191b10e9f8bb713f7a5398f0a896b03751ab12c869c3303cde771c650d0cc61a01d804db14", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a5542088fc35cd54fdad395e755c245e782eb43f0ff492dfe5a555abbb004d11", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 22080000, - "script": "76a91429c370819fab8a712a450a79c41be09d471469e888ac", - "coinbase": false, - "hash": "a5542088fc35cd54fdad395e755c245e782eb43f0ff492dfe5a555abbb004d11", - "index": 0 - }, - "script": "47304402203b0bf7f5555c1087cef631f11a1af2afd1e4c254ff2838d89e5a5820d63d5a3a022074bbc056125b12c9e4f2e71072973fe366b484461a2af2954d6992174e3bb5e5014104b1c7cab3b386d5646e3499c331ac19eb356b44843e02093b41a8c95535fc0e3cdf817444c2bd8402e33c0e0e8d8ab2cb5a3a9f18505747e98dae305945692d05", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c86c27d397aaa82a5c2c79f30b809947e60d9d2961f5859ab6a8218025acf9fb", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117449, - "script": "76a9145f48e98994413acea6e3403b9562d99b299a40cf88ac", - "coinbase": false, - "hash": "c86c27d397aaa82a5c2c79f30b809947e60d9d2961f5859ab6a8218025acf9fb", - "index": 2 - }, - "script": "47304402204859f55fea55f302b403bf8ccb85159b50ea9fd331e6a0a700f72bc02d1e461f022060b52dd4b394a3a0bc90946d7402e012ec1308beedadfe7589874bd59b07a87501410411281942d22817c6551bc28ae1ba8e632a0be0153464965d29a04a8d6c5e33e1035a35e1dee9dcf772fa619adfc05ae6341e40073338132eeb1cfc88ec288f5d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 24317000, - "script": "76a914b6061bd4a4ae317a66500874ccc7396dd8d04bda88ac" - }, - { - "value": 97449, - "script": "76a914796f8999c9697ba796bf41f40f4341ed7983884588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "50bc9aabe9d3b78de346b0b1829e8b6ea9bb85a5e44871a480ee538f945cbfc2", - "witnessHash": "50bc9aabe9d3b78de346b0b1829e8b6ea9bb85a5e44871a480ee538f945cbfc2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 267, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "be9cb422b6ca069cb5b4bd14784b7022d32cad7e24f0266f2102a13b3bf6f289", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299967, - "value": 2200000, - "script": "76a914e5c46993b640f5160a1811bf5b0f8bdea6f7fdd088ac", - "coinbase": false, - "hash": "be9cb422b6ca069cb5b4bd14784b7022d32cad7e24f0266f2102a13b3bf6f289", - "index": 0 - }, - "script": "47304402204fdae1573e0c06965f2e4a2b803650d7254e687dff53cb7c5cf335c1269f0f1e02206b291df555ce01d0f718521e8ec30cb37f685f22012a60b4fb5afb4aa240bd980141043fabdc90da5c1607aef8246cbec5a1f9fd808cb8b0d3f3cec6cdc6dc9cff7efd761aedb1ca2b332c89e6b68fc2f1ab677ac341874ad25764d91ad8a079133e2a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dcba5ebd169268cbd66c9d2218fdb25ca66eaef6dcfacfce5830e2c39e4a9da8", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10990000, - "script": "76a914e649a9ba6b7361e973f54ec40420580a40e82a2488ac", - "coinbase": false, - "hash": "dcba5ebd169268cbd66c9d2218fdb25ca66eaef6dcfacfce5830e2c39e4a9da8", - "index": 0 - }, - "script": "49304602210091c95fcef524688e583454be0ee714ce23d84ad7c4069d310b1d10b046d80c6c022100aa93fc20e4e4c5b8d659a6dc45d40df2b7511579444ff7d70eede1668f7168fc0141041bf45bc096abb5fea6f9d89906d43aac3a9d70fc936afd718fe5794862fbee25454eae97f85b495c063428a2820cbc3b2cd1cfb5ad28d0938fe09a690b5b20a4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cb846477055a86c4528bb1e98f871128dcc7a46319efd98ae2a8590b2cc12247", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914bfdb9edfc3f8952e7c0daa26a4e86dfd0e857b6288ac", - "coinbase": false, - "hash": "cb846477055a86c4528bb1e98f871128dcc7a46319efd98ae2a8590b2cc12247", - "index": 1 - }, - "script": "473044022057088131de8efba0009388e252fd062d25d3e971a802c83f323ef31dc2602ac302205579f898b1c89974e9623bae1b01b5086d698498dc87695ec8ec7ec3a8e51d760141045f3578f1ab980d5f0fc5026b5b5a1cb086b8996bba9469bcb57fb9e12fac4e8d7db594517875c53ee0d476a4bae507acf4cc40b4741744871ffb44f78e373a27", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 13190000, - "script": "76a9140d353a9008b6e1c068557d2cfd08eadb4a47641688ac" - }, - { - "value": 117491, - "script": "76a91423f20150770cae3cde4058bee3c244c297001ec188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6699b374dd446b856dc61a50390eae95e3011ba39577789162c22e18ca11782a", - "witnessHash": "6699b374dd446b856dc61a50390eae95e3011ba39577789162c22e18ca11782a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 268, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f348af4a3ff3ccc48e3f164b54b526cd827ea682c5efe85ceb9040b89c88294c", - "index": 16 - }, - "coin": { - "version": 1, - "height": 299888, - "value": 1000000, - "script": "76a914646558f7ab244b7e9b2c9a9c35408c51886a719d88ac", - "coinbase": false, - "hash": "f348af4a3ff3ccc48e3f164b54b526cd827ea682c5efe85ceb9040b89c88294c", - "index": 16 - }, - "script": "47304402206e12c97ce736b8997cb5366c9c17c31a903a52f33379aa3d923075f099972e5b0220022b6f2fad9b4d0b78da62c2d013001fc4f712565d27fd418fdaf89fbaf2ca740141048a64ff22c459a08133a3a2f32160c7b82109fac3045e1f077ff20a6c347e806465a7c762d0292986eb253e92ff521d57987e394f7b8fa981907e0e5ddd7e0d98", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "485c13c47394a65c0fef1d79a229163b552379f8af7ceed47f3c4b9683c31bc3", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3690800, - "script": "76a914d371ae82de32e0c8d797b789124dac36aa166d4c88ac", - "coinbase": false, - "hash": "485c13c47394a65c0fef1d79a229163b552379f8af7ceed47f3c4b9683c31bc3", - "index": 0 - }, - "script": "483045022100ffe417e96c29effb665699520cdf9af6724bbee5bcd5f5297a15ce0396755e5e02204e579c6e6424ef9b6951e41442cd9698444c5ce5da28485f74ee88ebf7d1adc60141049862ced532b234d375131cbc0120a819bc870ae14bfbbbf49094fe03b0e9dfb7a7a92bc1bebdfa011875b0ca1b77b2558d3160ed29586ab310e97539293e9d92", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d89069615df4296c36fc4e6aa5987ea636f9151f159c013fedc37dfdc81371b0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 117489, - "script": "76a914f390b510acea649c171c1c7f6fbdded44cc5170088ac", - "coinbase": false, - "hash": "d89069615df4296c36fc4e6aa5987ea636f9151f159c013fedc37dfdc81371b0", - "index": 1 - }, - "script": "4830450221009b731a55d8ec0d11c39951bf883219fe3acd62b22e2d55edb13ca34f829facba02207f26a062b12617163ed6e364f5263f2d03925078a17079c1866d0489fbf00e52014104dc93c1c947efc8700d86649daaf7ca0fe9c17acef5a9ae31e08d8af69b2b064ff76e3defd4ed5550b27e4268850b676ea3c258de2130dd969e07a89ef44b2f93", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4690800, - "script": "76a914808c0090b820b4875aa1a11dc0da10cd5939184488ac" - }, - { - "value": 97489, - "script": "76a9144bc95de8e6c6077f77df325b6dcbcf863cb48a8988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9ee393f480118322dabb3717752047e3800eca0701e26e989dcfbe1ba10b052d", - "witnessHash": "9ee393f480118322dabb3717752047e3800eca0701e26e989dcfbe1ba10b052d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 269, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5953bd7a98b8377b71e30089cac6f97a2c6c708b0f5d68a2919f0b5dd79e79bc", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 309990000, - "script": "76a914afdc07b810f707fb0dfe937fc5bfecc3707c6c8888ac", - "coinbase": false, - "hash": "5953bd7a98b8377b71e30089cac6f97a2c6c708b0f5d68a2919f0b5dd79e79bc", - "index": 1 - }, - "script": "48304502210089cf344ad9c8c7b317b5efcded57983f92ad366e03554cc011bc05f89d2af1eb02201f425e23beb2a873ad949b1c39c9066a7a85c02245d5a688e5111a2d28c535d90141041b4ecb8d49527d0e7f4f88944d9a2c4d04a055c7f25dc7401cd5fa03a1e66fc0bed69f1b8f053459e912d7de5181b3c35f7e8e238ad1e680aa71c6c4b99db314", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5370a2d912fab83830d372d992fa7e6dadf5b4b5e99e14a7269866a5a1fde0ed", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 161990000, - "script": "76a9146bcd2a581e6d8e03338d6a2047018a4baf1b1b5488ac", - "coinbase": false, - "hash": "5370a2d912fab83830d372d992fa7e6dadf5b4b5e99e14a7269866a5a1fde0ed", - "index": 1 - }, - "script": "47304402205c256118b7594678e90ab3db94f73fa3c9396ba604bac53c4ae3f80e2dc305200220342ea795a5a0ad81b5a4f090600b04131e0d4d2adff0dad1c97c427122d14f18014104a4ada2f02439fd0188ee2f2552212d8d108994b7057d6bad6caed7bcd1d47c597224337e85a650170bb17e277c98599d3f796c2ec69bf69f4ff1b3e92afea0ea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fae857cd8cc42bf81ac08ed2c03cfaa4b7169cdd837b9abefb07807aa74ae754", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97491, - "script": "76a9148ca26e615433c7cb8422f3948880eabc80e40dc988ac", - "coinbase": false, - "hash": "fae857cd8cc42bf81ac08ed2c03cfaa4b7169cdd837b9abefb07807aa74ae754", - "index": 2 - }, - "script": "493046022100ab2d8fa9415071fd6340b5b34fce8a503acf585c8890e7df7a0833cb892fd7e4022100a06816a5a4a9d1936a3a5101509581ae1cca578c660fe9e7d082d8df76545bc40141044f5ec4d36596758d84456f99ad80cbbfd95155fbbac503b792646eb33798515e24169c87faef5169e12c2493ba4be2f069fd74754a538e5015b8e60577ebbb49", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 471980000, - "script": "76a914533f04e7c4697c4b9b31f4f11b5ebf570527cbf988ac" - }, - { - "value": 77491, - "script": "76a914deb47cacb27bd6b7ab51bb6bfd013f33dc91a5d888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "633f71c99e6609bb10bee4a624fb565fac13e7da1208f201ea79238a7fba04d7", - "witnessHash": "633f71c99e6609bb10bee4a624fb565fac13e7da1208f201ea79238a7fba04d7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 270, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "311dd262b5f6e6885e29843ffc632f4ddbd879e1cc1b435048ac8840aba99555", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 4621760, - "script": "76a91460c5a98de87367dbccb5e8b5dc1707147f5dc37888ac", - "coinbase": false, - "hash": "311dd262b5f6e6885e29843ffc632f4ddbd879e1cc1b435048ac8840aba99555", - "index": 1 - }, - "script": "493046022100b6e143721304f435642cc14df7bf8bb1cb9cda72a874f7604d9c14a59d215e76022100decf0ba6e86fb15a224754e188aa3243590a66e5780aa2f86b93736569f80ce30141045ec6f603012ec9fd93197cfc2f5e41f553250b64aead3df0a6f29aeba8e679694bb5fdf1cad133825fe1ee7c7b905eef02be2f77d4cae997f2e3b20257dd4644", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "12c69c3dfcadbcf29f3fbe8e1a207fbfa8f87eb3f26bfc2026f35f6c7c001ee4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 14744753, - "script": "76a9145043b238e85fadd84f987649ae2d8df698ce58dc88ac", - "coinbase": false, - "hash": "12c69c3dfcadbcf29f3fbe8e1a207fbfa8f87eb3f26bfc2026f35f6c7c001ee4", - "index": 1 - }, - "script": "48304502202b9b1ac7ffc4ac2935d95afe5ee08783f020e1670b672563684b80e57b21a88d022100b7305a5c4cb4508974078a64dd15c48a2a30b21e4387b645a6b1d7a5b2a101fc01410488d5eaab91eadd835bfbe5727be2c17774b9917a9a0b54bfb70e1c78cdd476c5026532e3857902f68f7f41a06a8e9a3b44a37b6b585828511c6701002f98fc7b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "35cbfd2d0cebddea1645348683c33416ddd010502983177a3cda82fb6e42378c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137454, - "script": "76a914b7c2c96cf5e145eb67070ef4f7c60fdcb291166488ac", - "coinbase": false, - "hash": "35cbfd2d0cebddea1645348683c33416ddd010502983177a3cda82fb6e42378c", - "index": 1 - }, - "script": "47304402204a226c8a09a135bfc139fede24c9e5dfce91675d82b685dd49ab9d5944382adf02202cac93860882eaa657aab01b8ab29b5a1148a756aca4b484d31d82666873ea16014104efa08d6346f20ba0c78e3da83928141e681fbab5f9be0cb432f09304d24e28fbcddd37be5ae0e606418455f08cdc77d8b15127d63ab922902312665f12477d8f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 19366513, - "script": "76a9143c697d06f37a97319912b668c9a958148b9d2a6d88ac" - }, - { - "value": 117454, - "script": "76a9149b30b7abff8152d927b5a1bc72b2645d18ac184e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5d39df0bc99960f6cba04a0ed68e99d205a7f2b63c3b1cba9bf170d4406c9c5f", - "witnessHash": "5d39df0bc99960f6cba04a0ed68e99d205a7f2b63c3b1cba9bf170d4406c9c5f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 271, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "08ca65fa66b0bf40a1592ce891760adf057139900a9744b9fddfec5312884645", - "index": 7 - }, - "coin": { - "version": 1, - "height": 290442, - "value": 11500000, - "script": "76a914e579764def91a1481239d0a86febcaf4c97b26dc88ac", - "coinbase": false, - "hash": "08ca65fa66b0bf40a1592ce891760adf057139900a9744b9fddfec5312884645", - "index": 7 - }, - "script": "493046022100c6016f918350d9458e1c7cfd338585f8439e51ca3b81a36eda40a6709d73e130022100e6aaddde83d6fc3613787ebfd269538f6ae52ae3b7b3347610e9a60bded2ac9801410413347c1549e8f2785f386da297a017c62cc56ca7e59cbc3ef48d9e4c04d3230397688ca3c30f21c785eb03d9ae62c87418441eb16df19e93df94001c73f6f62c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "667b4412280e674ae223be50bc4931c3696f06d29c2068600ce3674964a3e799", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299973, - "value": 59645123, - "script": "76a9149c1d82c442c2bc3b3f79a2bf126a22723899a21f88ac", - "coinbase": false, - "hash": "667b4412280e674ae223be50bc4931c3696f06d29c2068600ce3674964a3e799", - "index": 1 - }, - "script": "48304502201811f0ec25823d258a7aa16965bfca649b65deae8046ba7dca959652f9ce992b022100f3bd2a32005d156b7a97c7db91ae30ec9b4b39318ebb71904414c702da8d8efa014104144ddbdeae76a97c0567023ce6ab210f9d707c24dfd49114a676595fb82d7327b820e5754fe610d3ab4c985aa61ad9401f95efc63119747577be1fc276e63e1a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b45908eba7743bc8f76bf64cc96043195bbb84d67f219eef5e480036661c84a6", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 49066335, - "script": "76a91451595b182a8823e2af7105c8a9a8d631a5a6e7b988ac", - "coinbase": false, - "hash": "b45908eba7743bc8f76bf64cc96043195bbb84d67f219eef5e480036661c84a6", - "index": 3 - }, - "script": "48304502204e41a3dd2106a71d57fe752b5456d03db31032364934759db2ecb42b457b01d2022100c1fe679212c8e9767d0f1075000e8fa6fd58165259f33ac7f1534dcc61a459600141046be3b1190c0e3cb9f3941a662ea25c59d5eb14044a91b511a592ae516d402a408b9f35925cdf1841ef15c383aa380ebc7dbacf11e677f344cc8c6d029a14851b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1001043, - "script": "76a914fb6448a2a03e08c8cf4cbe222fe2e101bb99257788ac" - }, - { - "value": 119190415, - "script": "76a9147f3746db863bae743278e23353788d1042479d3388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fdf80c889f89b4c13234ce66b078dad70c1301fed0150e393a671dd74a655c8f", - "witnessHash": "fdf80c889f89b4c13234ce66b078dad70c1301fed0150e393a671dd74a655c8f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 272, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "772ba5e3e88e45e028e5870922f6d20cf59e8928361c5406a91b69f69c7dfb80", - "index": 44 - }, - "coin": { - "version": 1, - "height": 298199, - "value": 24206, - "script": "76a914643af3c2c74b7415f03190c0f3dd5c95c33c3b8388ac", - "coinbase": false, - "hash": "772ba5e3e88e45e028e5870922f6d20cf59e8928361c5406a91b69f69c7dfb80", - "index": 44 - }, - "script": "4930460221008f8ef7757eb295aca5e9eb84378ed7ba7611ac31336262915775599dc7d66ee0022100edc8c28a4ab2e368d7c7e058b95c63d6cce3a4cfdf7b7d21708bc6fac0c243480141048e45e0c18ebbe92ef2c4d60b4731e96f84502f49f876bb374258087ee85a6f8bcce839e8d9d2912c1b1ecbe9fc6c4e3d4f2447855c487519cabbd98d592ca6e2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d180c380600455b93e2710007b29fd2cbaf4b2ebbc15344175126ba52fda6b7a", - "index": 45 - }, - "coin": { - "version": 1, - "height": 298441, - "value": 5770, - "script": "76a914643af3c2c74b7415f03190c0f3dd5c95c33c3b8388ac", - "coinbase": false, - "hash": "d180c380600455b93e2710007b29fd2cbaf4b2ebbc15344175126ba52fda6b7a", - "index": 45 - }, - "script": "493046022100f96606499d2a83cf09ce63deaaffbd8b72854344aaee14fdc84fb7d76f6f52a5022100dfdcc2a3399a6f5baba38dc4f2d76e6e856f0f505bc00adc42df942d9c6f8c4e0141048e45e0c18ebbe92ef2c4d60b4731e96f84502f49f876bb374258087ee85a6f8bcce839e8d9d2912c1b1ecbe9fc6c4e3d4f2447855c487519cabbd98d592ca6e2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bd2dcae7b3e42564727874f4de33585c9441f4f970837001620824d22171836f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 846065, - "script": "76a914643af3c2c74b7415f03190c0f3dd5c95c33c3b8388ac", - "coinbase": false, - "hash": "bd2dcae7b3e42564727874f4de33585c9441f4f970837001620824d22171836f", - "index": 0 - }, - "script": "48304502200b9b423e25d4bab690567cd511b07f9985bffe60ad517f2c59a60d5101abc2320221009f83fc6a4f3906aeba90686c6acbf3cf70fa14a61a9425519a925cfab7695c0e0141048e45e0c18ebbe92ef2c4d60b4731e96f84502f49f876bb374258087ee85a6f8bcce839e8d9d2912c1b1ecbe9fc6c4e3d4f2447855c487519cabbd98d592ca6e2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000, - "script": "76a914612e4fadce1ef0eac9ac6d8a0bbdfe20e6a6cbd088ac" - }, - { - "value": 756041, - "script": "76a914643af3c2c74b7415f03190c0f3dd5c95c33c3b8388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dab24570202b9559b5c310da245f8ecfe5050d8d4c4f1d1d6d242592b3b49712", - "witnessHash": "dab24570202b9559b5c310da245f8ecfe5050d8d4c4f1d1d6d242592b3b49712", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 273, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cebda43ce6c5444f4fc37db33736e47613d49d98b03f80f89efd7fce5e25d814", - "index": 23 - }, - "coin": { - "version": 1, - "height": 299580, - "value": 102571, - "script": "76a914becf73d8e4259a5fa84b70b050ec3e66527fdde588ac", - "coinbase": false, - "hash": "cebda43ce6c5444f4fc37db33736e47613d49d98b03f80f89efd7fce5e25d814", - "index": 23 - }, - "script": "483045022077375880583ffe07ff01bc4e6b28be313d922447a5fd3ba8db85f94a0fbf0b81022100f3dcd7a5175e42bdd2f16ac62339e6786232ecfefe28035b8834475e0a7d865d01410464227e11f96aade1a3db4d1170c792c18b34af9a4070040afabbb650bd29f2bf217a814f78b98696ffe06382af4ef10a87272d46a13200ea6b8db5c3503e47fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bb742e66eb9da26e4297f96ccc584d07604337aa600c67daa9c9b072c46c0524", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299612, - "value": 1042610, - "script": "76a914a89468dd0680258ebbd17eef89da9a3cfcba4bd588ac", - "coinbase": false, - "hash": "bb742e66eb9da26e4297f96ccc584d07604337aa600c67daa9c9b072c46c0524", - "index": 0 - }, - "script": "493046022100a3d350c5518ddc62e8d0de3a8b3d0074dda5aee63863d2eac52ccd49c41bf876022100ee09f009cdc4bc3393c1b94b5eff214583cb18f113079962a1a8e96cf3448c17014104913f2fcb5ea9cfddc2b46ba2cf0ae5ff0f7211b107b5b5bf9206422ca2629092f823f83a0ebf38196c78c490c72faf5af3e9da79ef4643151e15fcf0265909c3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d9b1372d6ad132ec504a7a39f83a3173d8b93f82c537207a2b43d7cd1d441d23", - "index": 27 - }, - "coin": { - "version": 1, - "height": 299734, - "value": 1538709, - "script": "76a914becf73d8e4259a5fa84b70b050ec3e66527fdde588ac", - "coinbase": false, - "hash": "d9b1372d6ad132ec504a7a39f83a3173d8b93f82c537207a2b43d7cd1d441d23", - "index": 27 - }, - "script": "48304502210095b18cfeb7d97d40cfdc0468ed2b834ea6fca76b18d8fad5f5284411998c3f5502204e8f5b83d7eec03946aacd4079626ac06eca77d5307f4e1210b8de903ea7566e01410464227e11f96aade1a3db4d1170c792c18b34af9a4070040afabbb650bd29f2bf217a814f78b98696ffe06382af4ef10a87272d46a13200ea6b8db5c3503e47fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dec49c040603c615a51dc64dce1a401ed9564055feac4c81b18cb425b37ef1cd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299776, - "value": 1198600, - "script": "76a914a89468dd0680258ebbd17eef89da9a3cfcba4bd588ac", - "coinbase": false, - "hash": "dec49c040603c615a51dc64dce1a401ed9564055feac4c81b18cb425b37ef1cd", - "index": 0 - }, - "script": "48304502203de7fc5c08ec97cf8734e310eca8ae4c304b169e61ef50f7ba2b719fdc82c3b4022100ef5ba35c764073a59913a0b5c337ebad97b4b856bc631c5c0b994fb3e6bba44b014104913f2fcb5ea9cfddc2b46ba2cf0ae5ff0f7211b107b5b5bf9206422ca2629092f823f83a0ebf38196c78c490c72faf5af3e9da79ef4643151e15fcf0265909c3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9b724cd2006b12ced38f14eca52c3eb3a5f26a006ba53d2ba49b04a10e777f13", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299814, - "value": 288533, - "script": "76a9144a7a75b76ecb264d5fc8de9b2962972c56e7cc5688ac", - "coinbase": false, - "hash": "9b724cd2006b12ced38f14eca52c3eb3a5f26a006ba53d2ba49b04a10e777f13", - "index": 0 - }, - "script": "483045022100a3378d6fbcdae4278dc62dfee2b06d2600d4dc8d3a71ecd334b76b54da86574302200b673a87d50e3ba4cb7c928b7dde03cd20842c72b756b4f22a42e01e782a1f98014104b59b747189877f688d2abbba8b39cf52a2ee13d1826b159028def01931f9be859c4986bb3c9dcd57f7b2ac5cba5f6f27518b6102aa9f0894a63dd7c0ef96ce7d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "573f4ebe401f762e8943707e3ed3c2fa75cae5f9f2d01d503f228a772a73c66e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299859, - "value": 2961040, - "script": "76a914a89468dd0680258ebbd17eef89da9a3cfcba4bd588ac", - "coinbase": false, - "hash": "573f4ebe401f762e8943707e3ed3c2fa75cae5f9f2d01d503f228a772a73c66e", - "index": 0 - }, - "script": "48304502207f6ec92eae3d446999ce18aecca95ab30ea16e0a823ac34ac72ea086b513b07a0221008d912c539dd6a7a88c299f7fc880f657adf7304a7f22c5011a6ef249c746c64d014104913f2fcb5ea9cfddc2b46ba2cf0ae5ff0f7211b107b5b5bf9206422ca2629092f823f83a0ebf38196c78c490c72faf5af3e9da79ef4643151e15fcf0265909c3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3f6dfa147ea17976be6d889cc49521823692de5a0d74fd971cb36f263eb9dc9e", - "index": 32 - }, - "coin": { - "version": 1, - "height": 299894, - "value": 609952, - "script": "76a914becf73d8e4259a5fa84b70b050ec3e66527fdde588ac", - "coinbase": false, - "hash": "3f6dfa147ea17976be6d889cc49521823692de5a0d74fd971cb36f263eb9dc9e", - "index": 32 - }, - "script": "483045022023343511e0b82e089d9b1f209fe5c76058b05c41536890c071109c2d4ede6584022100d7ef737dca17645e7b52f4867594db33771d7aa2a1589a52201bf78148b7d31301410464227e11f96aade1a3db4d1170c792c18b34af9a4070040afabbb650bd29f2bf217a814f78b98696ffe06382af4ef10a87272d46a13200ea6b8db5c3503e47fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "35f244fe1c02d86695c662b4392ccede1403692d4bfc5f565930ba1fa9fe8e02", - "index": 160 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 1971673, - "script": "76a914becf73d8e4259a5fa84b70b050ec3e66527fdde588ac", - "coinbase": false, - "hash": "35f244fe1c02d86695c662b4392ccede1403692d4bfc5f565930ba1fa9fe8e02", - "index": 160 - }, - "script": "483045022100cc2647ee6ae664cb9515d7d73292763b3ecb79bb7a1e4932b56afebaa8351f4a02207acc553171a0363275cd87dbdccec5e26029a89525b21eb06ea22d10f3a58ee601410464227e11f96aade1a3db4d1170c792c18b34af9a4070040afabbb650bd29f2bf217a814f78b98696ffe06382af4ef10a87272d46a13200ea6b8db5c3503e47fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "57d62e51ea08382152699122e27acb029a7e897439127c0dfccd68111e8e653a", - "index": 217 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 915404, - "script": "76a914becf73d8e4259a5fa84b70b050ec3e66527fdde588ac", - "coinbase": false, - "hash": "57d62e51ea08382152699122e27acb029a7e897439127c0dfccd68111e8e653a", - "index": 217 - }, - "script": "47304402205b542b5f6253e894443554b93ad156820f3053ff80c855aab98720c104d3a49802200df395dcb8e26a776e0c5abe8724a402bf27bc80f5be7994c063c77e2c00615901410464227e11f96aade1a3db4d1170c792c18b34af9a4070040afabbb650bd29f2bf217a814f78b98696ffe06382af4ef10a87272d46a13200ea6b8db5c3503e47fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "691e435d856e5859ce8c4dd9b1ecfb56cd559577bb87ad261eaa9775c971bd7d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 157444, - "script": "76a9142fafdbd19ea9cb90c7bbedccfe35afdd06e2317d88ac", - "coinbase": false, - "hash": "691e435d856e5859ce8c4dd9b1ecfb56cd559577bb87ad261eaa9775c971bd7d", - "index": 1 - }, - "script": "47304402203bb54d2c505fc965e73d02c6732c1f3597ada01ce12493107228adcf106b4b0e02201cfbb3bfc876665c2a2e8829f7857068d3002877d8f10c79971e71672f71b9340141047e686ead89e47a70ad22b479aad77a8cadf38f0d2bc859ec9d57bddf7d8e8fa5066153405e3f6350bfb068e9d3fa6b7ea982896c3e90cde771969f69f134ada1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10629092, - "script": "76a914061fc21293e9b56f762974d59661d05196352f0588ac" - }, - { - "value": 97444, - "script": "76a9141c3b5f566fae121c3f60d7cf1a3d6fb93c26f27588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "29778598db5cf170f8bb06ebf66fabf083fe7fafdb3aa507dfbb3aceb3642bb5", - "witnessHash": "29778598db5cf170f8bb06ebf66fabf083fe7fafdb3aa507dfbb3aceb3642bb5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 274, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7786b1fef695745ca47211e601d0a89feac273a448fe11ec5372d4608fcff520", - "index": 129 - }, - "coin": { - "version": 1, - "height": 299867, - "value": 1510192, - "script": "76a914d4e20181f2ba4d6d9ec54ffbe9e5ef7a79c117d688ac", - "coinbase": false, - "hash": "7786b1fef695745ca47211e601d0a89feac273a448fe11ec5372d4608fcff520", - "index": 129 - }, - "script": "47304402204fd2fb35064bc1936968891f14740138034adfea39979e7c178455576d55997d02203651b769914f7b58a8c4aa1aa92017efee26245ee9027b7b10c8b396fdc4af56014104076cd3b57b59401bc43ae7e8999d4c2d6f71a1b56b8d29a16ab62e6116b3030d2a5899a84eff71108ccdd6e38f44707a0313abf4ea580f161562e6502755baa6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eed19a476c34fe2c40ac7778f305471bb38528c344dcb363510597beeaf61149", - "index": 130 - }, - "coin": { - "version": 1, - "height": 299882, - "value": 1597822, - "script": "76a914d4e20181f2ba4d6d9ec54ffbe9e5ef7a79c117d688ac", - "coinbase": false, - "hash": "eed19a476c34fe2c40ac7778f305471bb38528c344dcb363510597beeaf61149", - "index": 130 - }, - "script": "483045022100a7bbedd48d83bd36bc2bfba4955b18694df17faf97454ad28095e08df20289eb02200c13b995fa8023c93a05f346019bb7f55e2fcc1d1f8194b01aebe1e30f7ffbb6014104076cd3b57b59401bc43ae7e8999d4c2d6f71a1b56b8d29a16ab62e6116b3030d2a5899a84eff71108ccdd6e38f44707a0313abf4ea580f161562e6502755baa6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 59 - }, - "coin": { - "version": 1, - "height": 299934, - "value": 1648926, - "script": "76a914d4e20181f2ba4d6d9ec54ffbe9e5ef7a79c117d688ac", - "coinbase": false, - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 59 - }, - "script": "483045022100adb5eab9d82bafefd04f342cb6b8edf9f619d80ddc1409ca4a0d0557eb4361ee022008324cb2e2f9e561a4256452fb3bab9f173dbd6dbc5b3e840d53176063864a05014104076cd3b57b59401bc43ae7e8999d4c2d6f71a1b56b8d29a16ab62e6116b3030d2a5899a84eff71108ccdd6e38f44707a0313abf4ea580f161562e6502755baa6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3db341c76192192c56350abb22e4b039311b1aa92abff213b759aea75020c54d", - "index": 136 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 1614345, - "script": "76a914d4e20181f2ba4d6d9ec54ffbe9e5ef7a79c117d688ac", - "coinbase": false, - "hash": "3db341c76192192c56350abb22e4b039311b1aa92abff213b759aea75020c54d", - "index": 136 - }, - "script": "483045022100d56dbcd9b8b4158a16831f1b82b9dd75a19f1349f53ba92dd02180026433712e02206c799212908966f5811b12e9bb313a39cd3376232f8f3c00a7e7b04f3123cbf6014104076cd3b57b59401bc43ae7e8999d4c2d6f71a1b56b8d29a16ab62e6116b3030d2a5899a84eff71108ccdd6e38f44707a0313abf4ea580f161562e6502755baa6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 44 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 3368904, - "script": "76a914d4e20181f2ba4d6d9ec54ffbe9e5ef7a79c117d688ac", - "coinbase": false, - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 44 - }, - "script": "47304402200d82152187c2c853ebd91ee09c42cbcc80017da27e5a86f2bca8faa88ac5013f02207c468127d2f46cdd0ea966020a2cd5f8126937833720d4d0c72b67d905528916014104076cd3b57b59401bc43ae7e8999d4c2d6f71a1b56b8d29a16ab62e6116b3030d2a5899a84eff71108ccdd6e38f44707a0313abf4ea580f161562e6502755baa6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 132 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1742648, - "script": "76a914d4e20181f2ba4d6d9ec54ffbe9e5ef7a79c117d688ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 132 - }, - "script": "483045022018a972b079fc210f08a4a9d1a75bbb2aee60ea6a08e93409166d3c6830d50dae0221008fe5c97d9238559027b3c9b1d47ad412436eab02308f5b1e78fc8634324435bd014104076cd3b57b59401bc43ae7e8999d4c2d6f71a1b56b8d29a16ab62e6116b3030d2a5899a84eff71108ccdd6e38f44707a0313abf4ea580f161562e6502755baa6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b654cc570a64adfa18bf101ac799a80f40b16e922f20344150eb6a4db5818cc", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a91451366b096b793530b214cc2bac20a5ee3ac5fd9788ac", - "coinbase": false, - "hash": "4b654cc570a64adfa18bf101ac799a80f40b16e922f20344150eb6a4db5818cc", - "index": 2 - }, - "script": "4730440220528c684a980f889353dc9325480665a9fdefd3693acd3911b154baec566e581d022022fdbdd47691cd94ce66001ba13911d4d28fc3f5fd5954377799895e2b59b5a90141047586cbd4bbc043f170e18537f30da0ff805f4e4056a8c18560fea7a869aebaa4e657aebe41706aaa4bb6c8abdfbc0758d4d18d47ead7ccc1f3d1023b2092237b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11482837, - "script": "76a914581510d916a33aa88decf8abfee4244100bc631188ac" - }, - { - "value": 97491, - "script": "76a914888ddd1a80202301874600bef5821cac8dd8fc4688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5e493035338c4ec38fe4800d6bad1d198cfb3cda0c4b6d161a491a6c9f91303f", - "witnessHash": "5e493035338c4ec38fe4800d6bad1d198cfb3cda0c4b6d161a491a6c9f91303f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 275, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "eed19a476c34fe2c40ac7778f305471bb38528c344dcb363510597beeaf61149", - "index": 102 - }, - "coin": { - "version": 1, - "height": 299882, - "value": 1696503, - "script": "76a9141efd84d31371664e858f50a4e9f87a6aca8d3e6988ac", - "coinbase": false, - "hash": "eed19a476c34fe2c40ac7778f305471bb38528c344dcb363510597beeaf61149", - "index": 102 - }, - "script": "4830450220793a15bb7c6a739f762d0f9bb9367068b3bc31bf0726a3a95763e8ab5e710e08022100a11f671872ad74bfc3985ef9492d49d0461b421545836567117a1975e3ab2e56014104784b83cb44d867f169a9b6dc75940a653cea9460cdef5d104bb837203d1056d505db427b731927ef05275d1b77c387f3dd0d3b9ffc1124be981c4003c51affbc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 109 - }, - "coin": { - "version": 1, - "height": 299934, - "value": 1639846, - "script": "76a9141efd84d31371664e858f50a4e9f87a6aca8d3e6988ac", - "coinbase": false, - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 109 - }, - "script": "48304502202240c4f30e1e2eb62be8e01a030ecdaa4ae4c1c1a800f9ef1ee5c384044d1946022100d6ee6f5e61bb0659b20c9e6a9c9c54cc1406d704d24bbb917ce583db92a54de3014104784b83cb44d867f169a9b6dc75940a653cea9460cdef5d104bb837203d1056d505db427b731927ef05275d1b77c387f3dd0d3b9ffc1124be981c4003c51affbc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "12805d07e80e8ed46fe7ed9e218c580d70b1ffdbdef61ba18dde8ab3b5d88045", - "index": 69 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 1000000, - "script": "76a9141efd84d31371664e858f50a4e9f87a6aca8d3e6988ac", - "coinbase": false, - "hash": "12805d07e80e8ed46fe7ed9e218c580d70b1ffdbdef61ba18dde8ab3b5d88045", - "index": 69 - }, - "script": "493046022100893659c1d468d85a10dda2559e19888282d90865854ffcb3009d99a866a7795c02210086e57e764318b2c7f0668238b71782b612fdb8c75fcc5c89a997715a4caf6d0b014104784b83cb44d867f169a9b6dc75940a653cea9460cdef5d104bb837203d1056d505db427b731927ef05275d1b77c387f3dd0d3b9ffc1124be981c4003c51affbc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3db341c76192192c56350abb22e4b039311b1aa92abff213b759aea75020c54d", - "index": 108 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 1693063, - "script": "76a9141efd84d31371664e858f50a4e9f87a6aca8d3e6988ac", - "coinbase": false, - "hash": "3db341c76192192c56350abb22e4b039311b1aa92abff213b759aea75020c54d", - "index": 108 - }, - "script": "493046022100bf16e9ceb3725d4ee3f47c46207bf1fbc16051757f9a7e7c209a97b1eb6f5315022100cf66b20d93c120203bf747663761c656bb0c6bdfbcaa083973980401c7e800c2014104784b83cb44d867f169a9b6dc75940a653cea9460cdef5d104bb837203d1056d505db427b731927ef05275d1b77c387f3dd0d3b9ffc1124be981c4003c51affbc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 112 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 3389637, - "script": "76a9141efd84d31371664e858f50a4e9f87a6aca8d3e6988ac", - "coinbase": false, - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 112 - }, - "script": "493046022100ea51211d67976001c3afc822e39516fff395efe94df39b4a86035ae3fbe144b1022100e6f96762303c9e9aa74792226c2b79b4f5878ba6676547c8255d1078cbd0f2c4014104784b83cb44d867f169a9b6dc75940a653cea9460cdef5d104bb837203d1056d505db427b731927ef05275d1b77c387f3dd0d3b9ffc1124be981c4003c51affbc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 113 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1735127, - "script": "76a9141efd84d31371664e858f50a4e9f87a6aca8d3e6988ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 113 - }, - "script": "483045022100e67dc9a55c21bdc923ca6a30cc9c109d97907c4aab92f871b1c76d23cfe9366f0220037538f86592b1fde8442870da977d0e79d6a49739ecbc03ea52b6d58c12363c014104784b83cb44d867f169a9b6dc75940a653cea9460cdef5d104bb837203d1056d505db427b731927ef05275d1b77c387f3dd0d3b9ffc1124be981c4003c51affbc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8cfcb2ac8e8bf54e98986a5a3546f1c465cd7ed9055a621be0ad1a285222218d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a914cccecea682e7278fcba33cdeb5198a2fe8db48f588ac", - "coinbase": false, - "hash": "8cfcb2ac8e8bf54e98986a5a3546f1c465cd7ed9055a621be0ad1a285222218d", - "index": 1 - }, - "script": "493046022100e155c3dd142e776697f1daf0de5ac4d8cb029c077c8a1ac65888b9146be3ce83022100ca0a6b377c2fa56e2fad11f1301728c06ef68f8b5ab6513aac23a61747e5f725014104af04f9c76f51b2326899089f2f542ce92fee32f440fd4f45bbc4b8e15ba48a72073e9601b95c74a7a58da812ab696501811253e91834a26a0414d05d7578e1e7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11154176, - "script": "76a914011076a0de3450760f5ce109c9d5e5f1f7e3581488ac" - }, - { - "value": 97491, - "script": "76a914dfa5d7b4ded036e8e77bb8a5826a1cd99dd4c9ac88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5773341daf3cb86318ee629f51996c70cb2b074bde2c909431c2e942dda45d5a", - "witnessHash": "5773341daf3cb86318ee629f51996c70cb2b074bde2c909431c2e942dda45d5a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 276, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6c2afe3ab93d849f9651175a7216fc96d52e24b21cae80097500e47e151b9037", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1010000, - "script": "76a914dec45e657b24c5cb4417bf6b1adbc466677d968d88ac", - "coinbase": false, - "hash": "6c2afe3ab93d849f9651175a7216fc96d52e24b21cae80097500e47e151b9037", - "index": 0 - }, - "script": "473044022042e6af7793b187d8b8a8e21a02f9517b88f7b4620e0ac00a3772fa1c5484ea25022051ed081c8788b9a9bf9f73895c60fa34270bcf4bc831a8c22fd646d308c064470121038bce75485d1035cd29e56ae5cedfb2c2bfb44c3037793a622ed231fbddd3f59f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "da808268ef90228a195bdc74eb86a5565f86fc2a1013a7bd2ea8c14338bffae7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 38990000, - "script": "76a9149bf549bbe4f62b0fa6b299ef152d600543920d0088ac", - "coinbase": false, - "hash": "da808268ef90228a195bdc74eb86a5565f86fc2a1013a7bd2ea8c14338bffae7", - "index": 0 - }, - "script": "47304402205b98f59c1c58dcab29905c56b0ab4101232500b810f26f8136bee02d418fa63902201a0d5decdf631eaaac5e1b7b385c5ff877899f3d09109ed24fbb197004090fe801210343612c84b58199cf04731e4dbaa1e8b062afbfa449652c7d58ace7bc92e5128f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 39990000, - "script": "76a9148af646acc740e28c56ac3c49fb858569c99ee07b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "002dbe6fb0abf7fdf2ec00c565aa93e3789de6c09f9a4c352eb7e41c48745dc8", - "witnessHash": "002dbe6fb0abf7fdf2ec00c565aa93e3789de6c09f9a4c352eb7e41c48745dc8", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 277, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "39cc5cbff4a8f32e6b2b195743433a2d91bfebd95122e23d296d9cd4ba97a016", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1762868, - "script": "76a914434ba8f5690c860b42d41a4d371e83686e01c89288ac", - "coinbase": false, - "hash": "39cc5cbff4a8f32e6b2b195743433a2d91bfebd95122e23d296d9cd4ba97a016", - "index": 1 - }, - "script": "483045022073dec8a3dd637791f3995d88797a679dd9074dcf7ca7ab26ecff353012f439f0022100a754b21a7e0ceebabba9055c0ed9dffffa58e4e881ed2a4c54f10fc688b3c23e0121034291d35abe74f3d5327bdfdda087e1844373e58da19e6019d75dcb723664df1b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "43db3bc5c7f32290070a36323fb23f7ff7ce51a5c612328b7a19a753e594b619", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 2798167, - "script": "76a914434ba8f5690c860b42d41a4d371e83686e01c89288ac", - "coinbase": false, - "hash": "43db3bc5c7f32290070a36323fb23f7ff7ce51a5c612328b7a19a753e594b619", - "index": 0 - }, - "script": "4730440220196bab39e5f0af0e26532a3be4a1521adb9bf0b762b9b43146dc7aefb5dfeba502206863ff10671a48b58cccb71d6c58380c16accf74f0575cb2774e684bcdd9ea180121034291d35abe74f3d5327bdfdda087e1844373e58da19e6019d75dcb723664df1b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4551035, - "script": "76a91495c45958af57ca886b5fb5c80abe3a549d804f0088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c398587668f11ccf46725627ba35be99555cad4a655e9976af2de032c3c61514", - "witnessHash": "c398587668f11ccf46725627ba35be99555cad4a655e9976af2de032c3c61514", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 278, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "43829f98f2b237bed0b5f6627c1f28aab636102d5176d134e4e40da6160331a7", - "index": 53 - }, - "coin": { - "version": 1, - "height": 298845, - "value": 1139828, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "43829f98f2b237bed0b5f6627c1f28aab636102d5176d134e4e40da6160331a7", - "index": 53 - }, - "script": "493046022100886f06fdb75e3a999c33f61e815012dbdc3ad5ef9304185adf568c92f27407f8022100f4f321091cdc69f9b14a62bd2e57b19786bdddc78784195adca06935b66c905d01410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e56777177aa89185cd6a1c17d6b51a89d53041f95fb7ac40e1030e272eeaf874", - "index": 45 - }, - "coin": { - "version": 1, - "height": 299028, - "value": 1092928, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "e56777177aa89185cd6a1c17d6b51a89d53041f95fb7ac40e1030e272eeaf874", - "index": 45 - }, - "script": "483045022079ff4a51177d4236beff6325dcbd80dc6a31aa2eacf3be77d66eb13eb67ccf660221008421f9faf6f36d5dc4901b6bf0f85c8d48fe6671c93868ee358f39e25e930cc601410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e6dfbd11e2b8c240f998b23a76c4e8c08376c761e346ff097ee71ff12bbea1bb", - "index": 56 - }, - "coin": { - "version": 1, - "height": 299115, - "value": 1038194, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "e6dfbd11e2b8c240f998b23a76c4e8c08376c761e346ff097ee71ff12bbea1bb", - "index": 56 - }, - "script": "493046022100c6a1e3f15e8c546c028bc011c551a62d857823e21da442bdd83d52e825b1c541022100af453ba49d3c16da0a1ae2c3777656a0120d6a6e51bfba087ca25d818855e38801410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4628d81a464dfc13b21c21e0d78c01bd75897aed98cc3c554ed8753c88513e1e", - "index": 64 - }, - "coin": { - "version": 1, - "height": 299179, - "value": 1096533, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "4628d81a464dfc13b21c21e0d78c01bd75897aed98cc3c554ed8753c88513e1e", - "index": 64 - }, - "script": "493046022100a2c24ecffcc45653cbfb907b5a6b83ee1e16dc19a6b5da5193a615264d484230022100afe3b17806215d9a16d5442a6ac4e86c02fac97898aa95a66789500dc128341901410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2294ab087d8b5cbbdc70c704c60c220093cb4e5738b4957d04c7817fd984ea17", - "index": 46 - }, - "coin": { - "version": 1, - "height": 299270, - "value": 1118458, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "2294ab087d8b5cbbdc70c704c60c220093cb4e5738b4957d04c7817fd984ea17", - "index": 46 - }, - "script": "483045022100fce53dbebbad7ecf51619274637e4568372984704260404b7f79ee0ab8b6304a02206abcf402eeb4c465a3e516ff7eb8f9de39c8ca6e0cc8c9fc3083ff3b0474cd9601410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e5f38158fcbec00206cfff7fbf27a0d0bc6ffa11a60329212da91bbc4acfc178", - "index": 148 - }, - "coin": { - "version": 1, - "height": 299428, - "value": 1098573, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "e5f38158fcbec00206cfff7fbf27a0d0bc6ffa11a60329212da91bbc4acfc178", - "index": 148 - }, - "script": "473044022045d8f6a9bbdaf2fff66ffc72d8282d23466799664260bb0e179727d916e7f00702200986a9a3eea702871feea1b9dc2dc9d780d8535ddfa2ab2360373e25b3fead4f01410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c675f716bae8815d3f02a1fcde8e5067f0db58ef31d73dca660af82490b631e5", - "index": 48 - }, - "coin": { - "version": 1, - "height": 299660, - "value": 1014512, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "c675f716bae8815d3f02a1fcde8e5067f0db58ef31d73dca660af82490b631e5", - "index": 48 - }, - "script": "48304502200db23e29830fb09da38ab4b8bbeb9dfaa0d802374c44f4d9d0a79ce1013deba60221008952b7e0abb7572626d618ae12f5010ec1abcc720de6594a559cda0e26ad435501410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ca9f4b16cb3638b65883eecc7a3de55c96da079e94096629fe3c3174d5611b80", - "index": 55 - }, - "coin": { - "version": 1, - "height": 299795, - "value": 1064978, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "ca9f4b16cb3638b65883eecc7a3de55c96da079e94096629fe3c3174d5611b80", - "index": 55 - }, - "script": "473044022008f1f217318860d1e6761a581a3d22a5cc42fd4036f77b37b9d614d30aa3b7bb0220024790656da399b29f1400df602d7c8a1078088e89e793b2fbc79277b5f82cf901410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 4 - }, - "coin": { - "version": 1, - "height": 299934, - "value": 1145196, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 4 - }, - "script": "4730440220147496814617b4e965bd58b124c1ac89c4cbceabd70123fd1ffa7ef1330cf103022061c9a841ed5238b458e9c2a965020d5128884a940c4efb0491748fac7da54aa601410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a276ab8e71f9349020a826d20f3d593dd8c72c018178ace54073f08c5cf8af2b", - "index": 48 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1041717, - "script": "76a91459967caaedf4d61cfcca001800a4e167cdb7063788ac", - "coinbase": false, - "hash": "a276ab8e71f9349020a826d20f3d593dd8c72c018178ace54073f08c5cf8af2b", - "index": 48 - }, - "script": "493046022100c7d07071bfd3bbb24d922d8e4200518c52c44383ff6800bb9e5ef22c8b153b9e02210099c33c40279e7a7ff8e3c443657b367e9fc446db9728591e234377652bfca12c01410487a3bde1362bfec32cd177266472098c94660461f805c35148ccf5c9b2ff085536d1a3261a967cc54dd2cbcc742493f7db8744ff1b2e706650f5c2557b2cff3f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "36ea80823e1132ba521279edf6f0f30d602edced7699f5027ee29c676f4b2f5a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77440, - "script": "76a914daff5f9b97826984a513b033d1ab3e943ec52b5288ac", - "coinbase": false, - "hash": "36ea80823e1132ba521279edf6f0f30d602edced7699f5027ee29c676f4b2f5a", - "index": 1 - }, - "script": "483045022100d8815c28d2f75063b0c8c501eccdb4442f859178fe5f6d59222cfaf6ebd076aa02201ad8209250e3e9177ee88ba487c6f443292ee2d9d78906086fb44a6062ebef8b014104eee53617620a28e95fd533dd28253d8a471fddb70221ac0bb2b14120944aee8e4379dcaad6caa31122a29e3e311d4aadb67d277b1c5cce4a0430a8e304293dcf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10850917, - "script": "76a914126b9ad432ff046b405b634b7395f4d902cf011288ac" - }, - { - "value": 17440, - "script": "76a91482ef2a46d38324dd9b06d87a2ac9a36786a7d95488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d152f08118010b71f79bbb315e0815097069cad1608edf683bfe713efca670fc", - "witnessHash": "d152f08118010b71f79bbb315e0815097069cad1608edf683bfe713efca670fc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 279, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b54fdcb65b257aa04f04255683c728da74a404a36205a8b367491bb9112c2d40", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 761409655, - "script": "76a914dcf2440817495e38a34a45fe49877dfb4a57f1c388ac", - "coinbase": false, - "hash": "b54fdcb65b257aa04f04255683c728da74a404a36205a8b367491bb9112c2d40", - "index": 3 - }, - "script": "483045022066fd4b6d8b44e31f977024b604b82dd91817f58c73fefe531a02ccfd5f5c4255022100d126f2b799ecdb440a55b1709a83621c20a112c79330aecd54633aed3fb0f40e01210305a29061071b961830c67966119a32bb8e188b0a82d6d76ada04a2f103183887", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 740736369, - "script": "76a914ce264bd2578ee548576bd7917dd8dc78e86ef65c88ac" - }, - { - "value": 10096772, - "script": "76a914cf1f3536b1a860893a2859e8cf42e7167324914888ac" - }, - { - "value": 4985845, - "script": "76a914f99b3aa1ec19dd4a9732fe06e2b822f6f3fb787188ac" - }, - { - "value": 2577737, - "script": "76a914b8e08bdecfef828b40ef7d34185ec2159260f3a088ac" - }, - { - "value": 2000432, - "script": "76a914f4ab290de39fd9931d0903b3eed37adcdf8ad83788ac" - }, - { - "value": 1002500, - "script": "76a9142ea32201fb4a034bc860d70728dfddf9699ffad288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dd0715ebd60131df4880f276ccba4b55740978b759fa09f9ff4223947a6c0542", - "witnessHash": "dd0715ebd60131df4880f276ccba4b55740978b759fa09f9ff4223947a6c0542", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 280, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "70f4fecd524ede51bf720c927f381eb96b0d4f1cb87a60f2254137085a28b7bb", - "index": 202 - }, - "coin": { - "version": 1, - "height": 299294, - "value": 214918, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "70f4fecd524ede51bf720c927f381eb96b0d4f1cb87a60f2254137085a28b7bb", - "index": 202 - }, - "script": "48304502203203edd5005da848ca4e0e845cdc8dcc2f59b211b4596170eab6c228943e64f4022100c765c66a593a95c8018bf24bd9c137a7526bb1c790660fef686c3ee608852274014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7cc653806a9f27af5d7e492c6fb3085776aca3477447cbeab57c511efba3aae", - "index": 860 - }, - "coin": { - "version": 1, - "height": 299394, - "value": 293678, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "e7cc653806a9f27af5d7e492c6fb3085776aca3477447cbeab57c511efba3aae", - "index": 860 - }, - "script": "493046022100c48d9c8aa5ec02b64429da58ef4edafeef3bb7ac81f6fd238417fb8c0c587d75022100bed923ec3b027ddb4858468e63d44ee917b7343294e1d154d0dbbb9f1cc9cb2e014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bdd261fc99eae91e23faca29ac3ee9a3dfdfaf7da475555b42be095c47de4517", - "index": 295 - }, - "coin": { - "version": 1, - "height": 299485, - "value": 878203, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "bdd261fc99eae91e23faca29ac3ee9a3dfdfaf7da475555b42be095c47de4517", - "index": 295 - }, - "script": "493046022100f363dc619c1af62968813fbe311d97184cfe4e813bb1140d8777998df7c34fc1022100d83cc56143f2ba505fd6c78d20c49b4581d2452a4fc27854008c3de836a29f06014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "17d8ca4a6ea7a29b8882fdffc0e5962cf9937031cabc9d52b66cade12937a231", - "index": 253 - }, - "coin": { - "version": 1, - "height": 299602, - "value": 906932, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "17d8ca4a6ea7a29b8882fdffc0e5962cf9937031cabc9d52b66cade12937a231", - "index": 253 - }, - "script": "4930460221009353d754515fb16a44a39c8c077fa40bfd135700668b9507731d7f168ed78ec4022100b6383713110d11e7cded7457bc5bbf3766c0dd4f95bafcd87915b612a946ba16014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "28f47647d5fed7acc6279ebed126a153c44e0963c21a3d89d27eece24038f090", - "index": 276 - }, - "coin": { - "version": 1, - "height": 299686, - "value": 858673, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "28f47647d5fed7acc6279ebed126a153c44e0963c21a3d89d27eece24038f090", - "index": 276 - }, - "script": "48304502204d16d18d2d9a6ff0f4702ae6fce4099eddf743ff6dbdb7900381f59a3cce529d0221009cff0869961687a65f3f71860acf62436f85ff3a6f731dc6659f2e8c798fbe9b014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ced3e4d04da6b8a1400bda5f848150a862c745784162c7adb730f2d307cc6a1", - "index": 316 - }, - "coin": { - "version": 1, - "height": 299728, - "value": 863506, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "4ced3e4d04da6b8a1400bda5f848150a862c745784162c7adb730f2d307cc6a1", - "index": 316 - }, - "script": "483045022100cee5008a484464551d46c0188196a3b57a219ea4ee82b165f7914bad697c42a202200a788611cf3c20960fd85b760cc3646331ddcff66ad6aabecbbd1555a8c953e3014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fe42554bb2bc26ae4ae1e26f2229fefa271ff11e85765a1f05385161d46d96c6", - "index": 290 - }, - "coin": { - "version": 1, - "height": 299767, - "value": 830073, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "fe42554bb2bc26ae4ae1e26f2229fefa271ff11e85765a1f05385161d46d96c6", - "index": 290 - }, - "script": "483045022026933555c09e2356ad40e7436b61c83145b003d90769e189d8f796bf80f1c3af0221008ee0d10e586359857f9c9a2d3cd50e181cbc105076d7bbcb798956c2f40a28fc014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bf9eec8083992f731e17acfc30e4ef372df077e79f7f1d41525ee9a186aeb005", - "index": 307 - }, - "coin": { - "version": 1, - "height": 299811, - "value": 782377, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "bf9eec8083992f731e17acfc30e4ef372df077e79f7f1d41525ee9a186aeb005", - "index": 307 - }, - "script": "493046022100ce05e9309177a063b1cf35ed851f59dba67a75274ba1960b6822baff009018f1022100f0fc95cf7af5e8e6f0a409a84b38580527cbd3d2c2330640abb5ccf0eb739df7014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f3ac1a2e544cbfe761553c4a779559cd64f6a416d426c0c01b249b2cab516059", - "index": 301 - }, - "coin": { - "version": 1, - "height": 299856, - "value": 840851, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "f3ac1a2e544cbfe761553c4a779559cd64f6a416d426c0c01b249b2cab516059", - "index": 301 - }, - "script": "47304402205e6ce2e7d0c2dd13b0d1567c1fcbdc50cfe5311f314de2123e4fef3fd0d678d002200096a624d3f9b815c8d3062a2754edb9d630f334c83f7b303d99c50953afbc17014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "83b27bcc0002f3c09066da06b56e2323681781983daede2bbe4b760b06627765", - "index": 179 - }, - "coin": { - "version": 1, - "height": 299888, - "value": 803582, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "83b27bcc0002f3c09066da06b56e2323681781983daede2bbe4b760b06627765", - "index": 179 - }, - "script": "47304402206bd5f587ac9ff7ec9366ba2e4c706a0ba2e62813bea9fcf0cac5a59126610c91022019baee2c6401013bd1ad9b61b2020e0a9e84b61de54853222635b917d39644b1014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c8fddc149a37ad1e4fde3050a9c69f6ac84d71ac4a3f8619b90fc6c98aabf5c1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299916, - "value": 376639, - "script": "76a914ccb0d3cce180ff1b80a61cb69f92d8de38bb749a88ac", - "coinbase": false, - "hash": "c8fddc149a37ad1e4fde3050a9c69f6ac84d71ac4a3f8619b90fc6c98aabf5c1", - "index": 1 - }, - "script": "493046022100bbd15506b3bb7aa2dd9fdd8074237794d2652471c081dd918ca4d2da7ccda38902210093bae0c8163e6da7b51ffb14a5c0569277ae8d1d6e9c332670d16b4f709209c5014104f0b25b7783449e545c524611dffcbcbb93957d4f02e89d8e768e50bf26f4605d9a78418aa47b9ab73a73442410f7a629d9d4edf40bf76e40d841edd51cfb405f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "95eb632619f829d566f69466cae0c03640ca3c7f8a04ea0d105d3729c233ab0a", - "index": 289 - }, - "coin": { - "version": 1, - "height": 299934, - "value": 855311, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "95eb632619f829d566f69466cae0c03640ca3c7f8a04ea0d105d3729c233ab0a", - "index": 289 - }, - "script": "47304402203ffff93a4ded0bb2b68e03adeb3fe5faf91dabefe27660860aa3db8f3815dc4c022072b18161de1ff867159a5e9f1826e9b7b91eee03d99fe8a5ba9d895dcb24f066014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c857e3ab46e30be796e241322a4fd1a105935ce359aeca6ce61751ea03588799", - "index": 171 - }, - "coin": { - "version": 1, - "height": 299977, - "value": 882544, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "c857e3ab46e30be796e241322a4fd1a105935ce359aeca6ce61751ea03588799", - "index": 171 - }, - "script": "48304502207899b252545c701a2cafd9fc4bb45983e19c6af826b193e6fb96a16205364b4b022100c81f36e102d9bfa510442ac15fbc0d8b81b1a64aa8025743fb5834382aca5e22014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "57d62e51ea08382152699122e27acb029a7e897439127c0dfccd68111e8e653a", - "index": 192 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 857359, - "script": "76a91441fb01158444f080924e364c094bc35d1811f64a88ac", - "coinbase": false, - "hash": "57d62e51ea08382152699122e27acb029a7e897439127c0dfccd68111e8e653a", - "index": 192 - }, - "script": "48304502200485a5e2e2ef809f1a8f661e90f11926f252fdd0c2e96448ba883189199365c8022100fff055fd0615d2eded20ded701c95f58ddde3812b1bcd742f29b6f06c20269c3014104a85d428748700dfc1cdb2a798be889640d34c393ee67db074b07d7dcb9c82f273e3ef049dc2cbb315bfee6170d917cfb978adb89cb053848240636de1f345da3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c02200cd03b2848b2aebec162e66d3247fe8f986c3b298a7e3dc4a30cee848d6", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77491, - "script": "76a914798c63acd13d947a6b7e2b2d01502e1162659e3c88ac", - "coinbase": false, - "hash": "c02200cd03b2848b2aebec162e66d3247fe8f986c3b298a7e3dc4a30cee848d6", - "index": 2 - }, - "script": "483045022100e028a1d332a8118eac74dcdcaf4117daf1f519bf36749e034ca86766ac6420f8022044a130bddf8af3efbd319bb1b94ea0a7a5fb95cfb621e7b4310d63e2793eedd5014104d0d4e45bbe2876f6ad46e3f49bf6b3b1828bc01fdf45a1832b73406983ba1f6502d8c4cece56e2afe51100e983f4eba4d2810d22eec147347a551183b41f2626", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "470c82630cf7547978314860d4a765d17c5d069a58d2812148313c85edaa0a7e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77491, - "script": "76a91485aeb3e83a1ae8ba59333fc1aa32a94e7c6d12e688ac", - "coinbase": false, - "hash": "470c82630cf7547978314860d4a765d17c5d069a58d2812148313c85edaa0a7e", - "index": 1 - }, - "script": "47304402207d7504e7c4bdececa2e417c61cdf78bc74cf37afcb4a1cb84c4b280710402d410220339d9107da6402b053c4cb9aa5ae5d30baf8436042798327961312f81b289d41014104e7bb3cbd61f48acf36ff1f181f606b6d913c9dabb8177eb3dfb9b9e749864d827752c815c285e5fd9071619728cda374b254dc32643d7807f0cd94ec4f4d95e9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10244646, - "script": "76a914361e8411e4365d23156fbc82d91592721e44d41188ac" - }, - { - "value": 74982, - "script": "76a914a02355a0eb70638c97422ac4ab912c5f7bf6049188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1a02e7fd2a252ed146435ef1791b806996773a14f5e8f753df8bc3467104d664", - "witnessHash": "1a02e7fd2a252ed146435ef1791b806996773a14f5e8f753df8bc3467104d664", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 281, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "44fe88adbc2c6e3603a339650a5dc654d4a17896e0ec636dc2bbe0fa2b3b127b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299872, - "value": 72400, - "script": "76a91492f3a3d4415fbe4588fd15d0cd5a7552a7ab849088ac", - "coinbase": false, - "hash": "44fe88adbc2c6e3603a339650a5dc654d4a17896e0ec636dc2bbe0fa2b3b127b", - "index": 0 - }, - "script": "4830450220156b3ae16973d78bd04ecab70bdeb021e4a4bb930fb23b797123ee098295000b022100f7384c716a061e98e76c9edbdcab170c042322ff72fb1922155141e2791193620121020e8d328f7badd0578a110e2d0aa4ead56fa55eb516582d35d33970b7ca3c033b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5460, - "script": "5141047900000078da35cb3b0ec2300c00d0ab4466edd004371f16c41d18b3d871024314a3aa085588bbc3c2f696f786a263ab6383131ccca5777353953cf2f87b327741047d195aabd9f579ce032658eba3ef57fd152c228e99b1459ec5cfb8a04f3e4a0a969a2025a2e6622517988ab7dc620ccbd13a142ed511c2e70b960028140000002102f884647516015a0f5861633406a0c8b2ef2d8967aa61a97a5fc2b14bf0ce23ba53ae" - }, - { - "value": 56940, - "script": "76a91492f3a3d4415fbe4588fd15d0cd5a7552a7ab849088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c767ebc67e43c761c9d2276d995cd4235cf94a48a7be1f72b44dd74fcc8a882b", - "witnessHash": "c767ebc67e43c761c9d2276d995cd4235cf94a48a7be1f72b44dd74fcc8a882b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 282, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5576233216cff1c75d6018d4148370e80cce68fbeb2845083045431d355b4925", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299692, - "value": 11847974, - "script": "76a9149992fceaddc583ef6171fc5333ee7f77df2f3dc088ac", - "coinbase": false, - "hash": "5576233216cff1c75d6018d4148370e80cce68fbeb2845083045431d355b4925", - "index": 1 - }, - "script": "4930460221008231961f6e64143110b0336f14ff686e315b0085a98332fc505b466f32ed35ed0221008ba367d6e0f63fb7a484838327920407fa622e0b7c0fd4520e0ad573e35b33110121037101cae85b2c3f6ecad718156cefa364d5c436948f0f3a76738d86399464d200", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f4d751284e1afd3a6637a830085f258ab8d2f7d60c4c21bf2e9cf9c65e556262", - "index": 82 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10073, - "script": "76a914926c6cfc4851ddb8dd8bf7ca02bb8d4dc805b35488ac", - "coinbase": false, - "hash": "f4d751284e1afd3a6637a830085f258ab8d2f7d60c4c21bf2e9cf9c65e556262", - "index": 82 - }, - "script": "4730440220090a4c1f5ed103a07f8cc7e3c4a0f8d436b7bb28667cc64a35834f0acd3bd0ad02204711730730158aaea9fd6f8f648244ff645cedc88b07e2032d2fc7cce7cff2e80121024ed3c5b1d299fa86f43cff241ae1131d157010825bcd185871073f2a95260f6a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5962010, - "script": "76a91476a70cc55832c997b2d559a89e5d0f41468bbc0288ac" - }, - { - "value": 5885964, - "script": "76a914a312e284754c239d581532ef7f19f2459110d0ee88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a1f91ef6c0cf36d2f2632da3e8fff3497b6ba30e8191a7be2ad82917ff55a81d", - "witnessHash": "a1f91ef6c0cf36d2f2632da3e8fff3497b6ba30e8191a7be2ad82917ff55a81d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 283, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "938a28e89904a325fab604146f0dfe57a0be14da0b3940075d61cd0bab165cbe", - "index": 1 - }, - "coin": { - "version": 1, - "height": 292371, - "value": 383560, - "script": "76a914b74b23b751d7fde101b9a2577f370f802f67485588ac", - "coinbase": false, - "hash": "938a28e89904a325fab604146f0dfe57a0be14da0b3940075d61cd0bab165cbe", - "index": 1 - }, - "script": "473044022027c9c2fde4e533097ed1f62aa2dddee10166bfc49e9333f22fe683277d9b3a8302203bce162768f759404227882ebd1d29ec0fced320a04b91fb2f74af3fabeca2e20121034c3e19d81b46c5a9268a24c5ce016e866462c46778698b18a5e3f782138721f2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "60557e1c7632a33b58701670ed46480f26d7c256b79d097059c58ffa3822ef97", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298734, - "value": 9431600, - "script": "76a914b74b23b751d7fde101b9a2577f370f802f67485588ac", - "coinbase": false, - "hash": "60557e1c7632a33b58701670ed46480f26d7c256b79d097059c58ffa3822ef97", - "index": 0 - }, - "script": "473044022068be46734cde6422cba60666c3ae7c4cee1d8a2c6035c29e6e135b98aba35af90220009008910eb4179d3b899b5629025050be001021cea4571a14c287b8c4d439480121034c3e19d81b46c5a9268a24c5ce016e866462c46778698b18a5e3f782138721f2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4687700, - "script": "76a91426091c3fb18c5d7240154932424bd13216885e1388ac" - }, - { - "value": 5117460, - "script": "76a914b74b23b751d7fde101b9a2577f370f802f67485588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5c92531edf7b441ad27e876afcc0252aed04bde4b481833a03a9c95ab9df392e", - "witnessHash": "5c92531edf7b441ad27e876afcc0252aed04bde4b481833a03a9c95ab9df392e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 284, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1e57654dd8a2ae8cd43eaed316fd714058e944ab3b7000c8ea8e90183176cf73", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 790000, - "script": "76a914534f420c13b4af49c9cde2dd34f6dd78d1996dc488ac", - "coinbase": false, - "hash": "1e57654dd8a2ae8cd43eaed316fd714058e944ab3b7000c8ea8e90183176cf73", - "index": 0 - }, - "script": "47304402203437c48baa7db1a12ad25d4f6871d30577faa1a19a4175544216a3aa12f40795022033482acbbe0c8c6993eef76368e33571bc5202181a90efc1550513a264ddbf3e0121027d9ffcf6b145351c02c252dfcc679de664158b613a4181baa321ba8667e8b9ff", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "29d27a7b3a400f499875b02ba876d64b5fa5b6c06544e4ccddf567a5794bb93a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 590000, - "script": "76a9141eccfcc9230789a1daf9b1ca278bce7d7fd93d3188ac", - "coinbase": false, - "hash": "29d27a7b3a400f499875b02ba876d64b5fa5b6c06544e4ccddf567a5794bb93a", - "index": 0 - }, - "script": "47304402205caab992b536abdf2f8562664d085ec4bf100cbe7e0a421a878ce050ee6d252e022057b3f396463a8dc4ae7c529ba9b0006637ff9691a8dcbfdc5e0cddff723fa1be0121033398733d287a8d188607c14245a369ca89dc9c3057d84f1eb41bef2b6db6e097", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1170000, - "script": "76a9143a3c573b1f2da608c4c1cb97cf8a6401b532735588ac" - }, - { - "value": 200000, - "script": "76a914da5dde8abec4f3b67561bcd06aaf28b790cff75588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f1c97673d21ceb6a799aec54bb5f781c9630098aa1b0e1fd0b9e9cd47646cd9b", - "witnessHash": "f1c97673d21ceb6a799aec54bb5f781c9630098aa1b0e1fd0b9e9cd47646cd9b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 285, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f4614bb1ef0f0f9ac51603c39b1538161038a76556bd08ed5439cacd8c9e8e06", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 947000, - "script": "76a914192631d280209f63886c0c591d34af37c3597a8188ac", - "coinbase": false, - "hash": "f4614bb1ef0f0f9ac51603c39b1538161038a76556bd08ed5439cacd8c9e8e06", - "index": 1 - }, - "script": "47304402206e6c40dfa5e6ab5229c380e8fec33c299f1452b4ea4dc9955586504006508142022027640ddc4851fb840155132c24c19a4eae1d3a858ae86513ff58787e7a964fc0012102e1146e3b32f554a750bddfbffa9ab9c1fef49d73f9881ff9fd28821dc0b1dc94", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "db42149ea14687b58ed30d085c27c649a1623485d201d8c547e441671a00aef3", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 1957000, - "script": "76a914192631d280209f63886c0c591d34af37c3597a8188ac", - "coinbase": false, - "hash": "db42149ea14687b58ed30d085c27c649a1623485d201d8c547e441671a00aef3", - "index": 0 - }, - "script": "47304402202e575167291d0b32015d39488183838b21065cd781ad458a91f927b6ec4df6040220351212694924b866e83e9669486fe3e3b8c43fa34e5f578b64f4fe57d5cde2d9012102e1146e3b32f554a750bddfbffa9ab9c1fef49d73f9881ff9fd28821dc0b1dc94", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000000, - "script": "76a91406f1b6703d3f56427bfcfd372f952d50d04b64bd88ac" - }, - { - "value": 1894000, - "script": "76a914192631d280209f63886c0c591d34af37c3597a8188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c02ddf214fba2a42651e6f1008d3962ad0286cd47feb15a2068d2832fb5618e8", - "witnessHash": "c02ddf214fba2a42651e6f1008d3962ad0286cd47feb15a2068d2832fb5618e8", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 286, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b2c333a5cf5aafc5b8a3074a6756624395051b0e99e9dd0d9b36abefce408afd", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1334690, - "script": "76a914554f654f42bb81c871ea7e5c29a74359a4b392ec88ac", - "coinbase": false, - "hash": "b2c333a5cf5aafc5b8a3074a6756624395051b0e99e9dd0d9b36abefce408afd", - "index": 1 - }, - "script": "4730440220758d3a957beefdf54903c622168d77bbe1839b65545fa06c15e16fbcb71ee99a022012ba9e504cfa17a8f618503c2f13ed2e0764bc0b075b2be9d07110d765118c0d012103475f35e3c73a97c164f525e0a4f33f58feda9396dd63c297dc5a2fe910f34e23", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "56d28bdb6966fa01fb428fa19afd78c68d62b86aa1d11af9d856b6f148b11e1f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2033193, - "script": "76a914994423799a675229719c51ecce74a9c46eb706cd88ac", - "coinbase": false, - "hash": "56d28bdb6966fa01fb428fa19afd78c68d62b86aa1d11af9d856b6f148b11e1f", - "index": 0 - }, - "script": "473044022070ed981bdfc7279cbd5911f8b5e6d417bf9bf0d9262a0bd27ed412f0d87e1ea802206e25a9d074b052e36c191d0ef52b6d9753279a9d11c0e96825b7a6e6863752d6012102aeec73a3d0280513c5df237a25ff09df85b27f2410e0f73bab95f1eb5d601a43", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1490000, - "script": "76a9143305fc8e435c26696944ac2e9dec97490972939088ac" - }, - { - "value": 1867883, - "script": "76a9143e5f9696140288cc421752c601527042551ef2dc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ca7a6cbad1676b3b096be7584af7ebac5d2c5ff5542f271a230377778f115b00", - "witnessHash": "ca7a6cbad1676b3b096be7584af7ebac5d2c5ff5542f271a230377778f115b00", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 287, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "60f6f7ccfe96ee03db59230a88c70f9ac2d26988c749b9b8ecebc28407f46d7b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1400000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac", - "coinbase": false, - "hash": "60f6f7ccfe96ee03db59230a88c70f9ac2d26988c749b9b8ecebc28407f46d7b", - "index": 0 - }, - "script": "47304402201a1a0478e05c9868305a4a3d3659501170a16078a7dfc87d1e016b7d6398f095022051e8f38643b7b7c12d5542eae6dac661d20db33042222bef2e40474dc8ef8f6d012103afd34045d7080e5f3d8fc0efab187951caed4b06571c7cc617d01d9abe8b36b5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "316fb7544f2689f32ca74404b6f9187cc79926a5eb44eeeec62d5a0c9d572003", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1680000, - "script": "76a914cdd6cbd410b70ecbca00b02d0f962b710a7fdec488ac", - "coinbase": false, - "hash": "316fb7544f2689f32ca74404b6f9187cc79926a5eb44eeeec62d5a0c9d572003", - "index": 1 - }, - "script": "473044022060a7ff0e2144eed256eea951b0f1f13b5d42a2da78f06c2a807ba7ea5231dbb602203b4ce95c63045be16a7f0adb4b5709b4c09bcf4a91af535a74e835642a717527012102e6b43d1e214b69683b25be7a393e0008727b47b84a16a4f6bd5250bac26b6463", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2450000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac" - }, - { - "value": 620000, - "script": "76a9143dfeb05e14625b32bfe7be9c5454e599dc2d74b788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2c1c1d82549653e82b59d5bfc97c371ee9f26d06638b1d914aa86ec859544a93", - "witnessHash": "2c1c1d82549653e82b59d5bfc97c371ee9f26d06638b1d914aa86ec859544a93", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 288, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "109bca5b016157045b98ea03fec5ba339e8328cbbceb203a0d7c42cc19dec752", - "index": 0 - }, - "coin": { - "version": 1, - "height": 288590, - "value": 12000, - "script": "76a91444d9de47d5e56ff63cda7b957b0cdb05e51248c588ac", - "coinbase": false, - "hash": "109bca5b016157045b98ea03fec5ba339e8328cbbceb203a0d7c42cc19dec752", - "index": 0 - }, - "script": "47304402202f0e6ee84a4952c8f9ca34928f879f07e8367192af19bba29948a92b4bb2ea1602201818b99897a72e338a3e79629361d76dfb6ff4a59a3258961b6e3cd8dcfa63f9012102e2bcd0f305e9bfd38d57b1d7d96a73723451c62aaa02f5050ddd1330db404a62", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9a0135a7d24d8ab9e356b03bd119659bb7e039d13bf5e4ca97ef912011813946", - "index": 0 - }, - "coin": { - "version": 1, - "height": 288918, - "value": 23300000, - "script": "76a91444d9de47d5e56ff63cda7b957b0cdb05e51248c588ac", - "coinbase": false, - "hash": "9a0135a7d24d8ab9e356b03bd119659bb7e039d13bf5e4ca97ef912011813946", - "index": 0 - }, - "script": "483045022100d537027aa34f252d74213b75e6206b530aaea9b6295e14e889cc04cd0cbbc8cd0220584e5cdf995daa3639d88e29d9f5089d6b1996d72c723b5866f8abe3fd10aa1e012102e2bcd0f305e9bfd38d57b1d7d96a73723451c62aaa02f5050ddd1330db404a62", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5000000, - "script": "76a914d94eb17daa055c61c81b651e337d4840c659589988ac" - }, - { - "value": 18302000, - "script": "76a91444d9de47d5e56ff63cda7b957b0cdb05e51248c588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c3b2f57b3b56ca4f88757b8b133b8e451e20bce28937cb44d50ba244620c75a7", - "witnessHash": "c3b2f57b3b56ca4f88757b8b133b8e451e20bce28937cb44d50ba244620c75a7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 289, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e7ae40fc16e8b9fe6917088b1eaa76a1c05db664acb0137cf3375ea7d902645b", - "index": 211 - }, - "coin": { - "version": 1, - "height": 292765, - "value": 1540975, - "script": "76a914c32d60f2d5f2954cea7482cb969267e4cfa46d0388ac", - "coinbase": true, - "hash": "e7ae40fc16e8b9fe6917088b1eaa76a1c05db664acb0137cf3375ea7d902645b", - "index": 211 - }, - "script": "483045022100ac5d45bee5bc4568217bfe224b89b61f85b0a8020d4c73855178f7069384d69a02205a7c29fdb9437264bbb6f2e12ac01590b3856512e1b3def015f1f3aa2bc893520121035c684d9716aa7b5aba92787441a4dfff5956d00cbd53e4feaf9c0b94c2867be9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7836ef023c3e328c2b1ce5a656e1e26e9b02b3e535363d8239540465196ea90", - "index": 8 - }, - "coin": { - "version": 1, - "height": 289805, - "value": 1104408, - "script": "76a914c32d60f2d5f2954cea7482cb969267e4cfa46d0388ac", - "coinbase": false, - "hash": "e7836ef023c3e328c2b1ce5a656e1e26e9b02b3e535363d8239540465196ea90", - "index": 8 - }, - "script": "47304402200d122b0027a895df41ab039b5518c0621ba61a7f90e15f9de2cf166156f78b8b02204d80f5f0291fe4be99de1e84181a746b1a26f4fbe8e4f98b0b30d4ccb21a821d0121035c684d9716aa7b5aba92787441a4dfff5956d00cbd53e4feaf9c0b94c2867be9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1520000, - "script": "76a9146d1287f39566ccd60e8da35676291b94aef06fe988ac" - }, - { - "value": 1115383, - "script": "76a914c32d60f2d5f2954cea7482cb969267e4cfa46d0388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "91b47401fec564f051a8251a4427473f2c21c6de32012feed1e25078a35e1cb4", - "witnessHash": "91b47401fec564f051a8251a4427473f2c21c6de32012feed1e25078a35e1cb4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 290, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "35a2bff5f83f71e49118b0d8af19dec50f71fc6b4b446ce5aa5f25cf3b2b4502", - "index": 1 - }, - "coin": { - "version": 1, - "height": 294159, - "value": 80000, - "script": "76a9148fe7f60336b1fe51e161165e2990c97b65c10b0688ac", - "coinbase": false, - "hash": "35a2bff5f83f71e49118b0d8af19dec50f71fc6b4b446ce5aa5f25cf3b2b4502", - "index": 1 - }, - "script": "473044022029520b1679797135906131089a91d18fc726e1dfb73aa97cddb73283dbd4d28c02201376f01592d34910c4095c8f9f3b4f638047c36391336b20ec5be397bf8f2d67012102b9516a2aa0c77338990e57c626e5896a1aa22845d0ec26c0c8c728526cbb9297", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e6fcdc83df62cea267868120a8aa9162087509f4518ce1a2b187ec2e94519b87", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 45000000, - "script": "76a9148fe7f60336b1fe51e161165e2990c97b65c10b0688ac", - "coinbase": false, - "hash": "e6fcdc83df62cea267868120a8aa9162087509f4518ce1a2b187ec2e94519b87", - "index": 0 - }, - "script": "483045022057d3a3f8a436cc5fcc5e853a32c45cd6d12c6dcbe6156004b1c1ca45568ca7e00221009e7e5d8ed623333950cecdd6a469f0bcb14f83f64d2751fb5f95963fa36dc17f012102b9516a2aa0c77338990e57c626e5896a1aa22845d0ec26c0c8c728526cbb9297", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 44000000, - "script": "76a9148385618ddde5d14e1b43f1ebbcac5056e892579488ac" - }, - { - "value": 1070000, - "script": "76a9148fe7f60336b1fe51e161165e2990c97b65c10b0688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "aacedf4cb563527da63777b72c2af68419ec779cbc5cb257d94679a8a93fcafc", - "witnessHash": "aacedf4cb563527da63777b72c2af68419ec779cbc5cb257d94679a8a93fcafc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 291, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b2ebb384228d5883392122a40054faeccd13271e8c8a696139612e0a561039a9", - "index": 41 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1723167, - "script": "76a9148f788dbad2aaa8377f8d272521d2c4cae5562a2788ac", - "coinbase": false, - "hash": "b2ebb384228d5883392122a40054faeccd13271e8c8a696139612e0a561039a9", - "index": 41 - }, - "script": "483045022100ebda1ea6d3d3ae968de510e8f9eade73f79eb820e02240880be64a64080930410220713fb550354c467b9fe8004a7db55b06e43aeea49fbff098efbae482d098da010121037d0bcc54e5347955e7fd5874cb4bc118439bd39de2e88632c614ea49e6c67e83", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "faccda56c64a67ca18141c21d12d23f3bdc2cd941a4b869c5c6baa7ff331f68d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300022, - "value": 99988000, - "script": "76a914d1d7358b55b8f3a29eb9086f8672ac156a87704f88ac", - "coinbase": false, - "hash": "faccda56c64a67ca18141c21d12d23f3bdc2cd941a4b869c5c6baa7ff331f68d", - "index": 0 - }, - "script": "47304402200893ad0278b41c26fb3603631201672519dbeb841c1a2d70b18bf14e669f56b802204f5155e95f536c0548c94c3b0e51901281fce63567b103b38dd02da2bc043fb10121026788a63be63c5ba64390986972cf3b43445960fd9dfc610be5020832d2d235c0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000000, - "script": "76a9147aadae60821e6a67ec1f43c85bef4fb9acf01b9488ac" - }, - { - "value": 1701167, - "script": "76a914b434be0dd11b2f1784ce650959f6433f947fb0d788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3b133257dc71de271625b010f4e550104363d9a336375f61f38bc3fd8885b03d", - "witnessHash": "3b133257dc71de271625b010f4e550104363d9a336375f61f38bc3fd8885b03d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 292, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "472efa2efc0b71df6e08ce0fd02f8ba9f383b431c7e10661d9b8b242321ceea2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 34000000, - "script": "76a914917e6547b809746cc1161ed919ae496b8172c17b88ac", - "coinbase": false, - "hash": "472efa2efc0b71df6e08ce0fd02f8ba9f383b431c7e10661d9b8b242321ceea2", - "index": 0 - }, - "script": "483045022100b11ccdec3fea18eae8f7c4beb6f4c1e6c3544b0e670b0fad4d5a18c9c9eb9d9402202290aa9bbd025499436e44334d7fd6a0c84fa6c75115e488bad311f24131941d012103bd8130bc46abf211104d2d85181e0c04fd13456261161c45a5c3736fd3276b19", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a6f478bfc8fc17a25ce21a7599d9fe36e7d590b0450d54586d8b35cc15d21930", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 28780000, - "script": "76a9149b3290a962997deaefaa23a9483bd996700204f188ac", - "coinbase": false, - "hash": "a6f478bfc8fc17a25ce21a7599d9fe36e7d590b0450d54586d8b35cc15d21930", - "index": 1 - }, - "script": "47304402202ed115ca0ec62a72049f77d4292245ee9020542f6a044ba67b9a8056dfeacd5102205b8ba164af753f8ff4414cfde11b2d03ba0a2f94a8024d3f3bcf1d1a2b5898290121029703da9cf1b031f8919361e3eba3b572ffef08f46b043e85fa98b1bac1967fa6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7500000, - "script": "76a914cf5a97ae78c6765c53c13924442ca1c5c47b9f8488ac" - }, - { - "value": 55270000, - "script": "76a914132a7a18c3c1da3c1993dea0f61d203bcc1b760b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c5909b36e84ce28feca7661d4f7c7f4bd15f5e662bcb0893ebdd064ef7b8ac4a", - "witnessHash": "c5909b36e84ce28feca7661d4f7c7f4bd15f5e662bcb0893ebdd064ef7b8ac4a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 293, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3b133257dc71de271625b010f4e550104363d9a336375f61f38bc3fd8885b03d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 55270000, - "script": "76a914132a7a18c3c1da3c1993dea0f61d203bcc1b760b88ac", - "coinbase": false, - "hash": "3b133257dc71de271625b010f4e550104363d9a336375f61f38bc3fd8885b03d", - "index": 1 - }, - "script": "483045022100d1f101628a136f61b2b49ec35f3211b9142d386ec79f9d36b8de91e9ad0ac47102203e762b4c18552fb78e3fa8c61180cb11c82d3d965b4cef49b34493e46fbf97720141041e681e75178d798197913f40f6f2b61453165b1deb995598e43b42b36a01375fea026498313295a7451dadde2ac5d036a23c67a883c3a8fff490bbb983e3c436", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 55260000, - "script": "76a91448d34cbed6c62c2552b892af410981b8b4972afd88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8d6571393b01506db4619b6a06588de4919adc75cb35f8aef87cb6c605370923", - "witnessHash": "8d6571393b01506db4619b6a06588de4919adc75cb35f8aef87cb6c605370923", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 294, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "265fd49a74a03295c4b340f1c6eadd49556da016a5c64449f61c0d66d86699a7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299912, - "value": 1068477, - "script": "76a914005caa12264f97d1858d6f641e8470d19d3cf84b88ac", - "coinbase": false, - "hash": "265fd49a74a03295c4b340f1c6eadd49556da016a5c64449f61c0d66d86699a7", - "index": 1 - }, - "script": "473044022100f70dc8c65d86ccda7d30c98922f3213ffda953e7bce93d1d4159abd80e410621021f21387b2d825cd092c19aa0ef297e63fc548c8c836d99dc793df1c0d727eaa00121039101094857215d7cf414d407fe748de80820d1bdf620cb4ce18cc1f2dd62ac92", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "659691216fdae0aa6810d8c7ffe6e97e3b470a8eda85c5846180fb88456fdbc8", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1193456, - "script": "76a914c2c43391052c4f4ae4fbf15147edeb105580d55688ac", - "coinbase": false, - "hash": "659691216fdae0aa6810d8c7ffe6e97e3b470a8eda85c5846180fb88456fdbc8", - "index": 0 - }, - "script": "483045022100cd1223a556667ee850dff82b37aef59deca66d5ffe5f8b7e525465032cc79d37022039bded52fa047de906f5960d4313ec4df8526b4665f5f0e7419745ad367ec10001210331434643399d51a6465095f5909b7274878adafb6525e0d3f77a499b78d8478a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1313654, - "script": "76a91435a5be358c3208dde222da1d1c6110c250f85b7988ac" - }, - { - "value": 938279, - "script": "76a9144b5d3234d8c5123af2153d82f054e4ba2f0173ca88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fde1f1b7e916203e44ac403a387499b2c9a189a6917bff131dcd70cff805ec47", - "witnessHash": "fde1f1b7e916203e44ac403a387499b2c9a189a6917bff131dcd70cff805ec47", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 295, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "86ed787450c5066628e797167794a518ab4050aca3a04415b68ec5f7328b9e95", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 8630000, - "script": "76a91413e11dead3d4f7083299a318633a99d9df113b2c88ac", - "coinbase": false, - "hash": "86ed787450c5066628e797167794a518ab4050aca3a04415b68ec5f7328b9e95", - "index": 7 - }, - "script": "483045022100c0c4f479ef282fe7321cb50622e5ca8f8c80ba05dc2f066b8081d7a82744dc2e0220234771656ea0b9b155d5c9ed08d1d2d31068f19bfc57be30e78f0f7da9ca4755012102a52bcba59563c3af2e5fc34a3abbaaf088acf6e88d747d95fb1dac5b10774406", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a343005ba755c40b279175891125ef172e4011e36e6aa0b529d309dad0c35048", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299225, - "value": 122500, - "script": "76a91413e11dead3d4f7083299a318633a99d9df113b2c88ac", - "coinbase": false, - "hash": "a343005ba755c40b279175891125ef172e4011e36e6aa0b529d309dad0c35048", - "index": 1 - }, - "script": "47304402207875b1003b8a0b3695cf84e71d077c851ca2eab806c9708c6bd04f902e4f1a3f022042e8867b24aa24fb5b24c2cc0745b83652de7054a8edf09d05184538deda5a7e012102a52bcba59563c3af2e5fc34a3abbaaf088acf6e88d747d95fb1dac5b10774406", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 7660000, - "script": "76a914b06ad61bb95bcadab4050811f8901e1cbe07a78188ac" - }, - { - "value": 1082500, - "script": "76a91413e11dead3d4f7083299a318633a99d9df113b2c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ed4e37630636dd289a7bf806a8d6bc48b47b646c522bed2183e44ab0dc638059", - "witnessHash": "ed4e37630636dd289a7bf806a8d6bc48b47b646c522bed2183e44ab0dc638059", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 296, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c06afe1e69d9e156e1ac4a858a64e00e0e155f569b3112452ee3a3631a0006a2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 700000, - "script": "76a914c02e21fe5835ce5361611cde12184b490a13447188ac", - "coinbase": false, - "hash": "c06afe1e69d9e156e1ac4a858a64e00e0e155f569b3112452ee3a3631a0006a2", - "index": 0 - }, - "script": "4730440220531c478bcf6a0ffa0d67e6e2d91b70b22bc955a2dab9b5f62b97bc530b299cb402206938d14c3d8a2739995ff0c61d4f993ee505c3dacb3beabef57d4070990044ce0121028d2ac663ff325b4f411b3e5f846366df1eaea6d1ee9b0ba6c896aeaae4f781e0", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0827f5ab595944a8a0e53ad10a91311b5a6813826dc2c919faea10288bcc0372", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299909, - "value": 494920, - "script": "76a914c02e21fe5835ce5361611cde12184b490a13447188ac", - "coinbase": false, - "hash": "0827f5ab595944a8a0e53ad10a91311b5a6813826dc2c919faea10288bcc0372", - "index": 1 - }, - "script": "483045022100be2b9add4ae6bf24ef455a5a58b1b5ded7d4e049dc2d748762625497b2871671022053a9d9481374349cb8d190dc130c1e43779b6cd7f8e9bac2071112294dd5c9360121028d2ac663ff325b4f411b3e5f846366df1eaea6d1ee9b0ba6c896aeaae4f781e0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 881096, - "script": "76a9142ecf3308cfe238b1a16bbe87d6e966c78878cb8e88ac" - }, - { - "value": 303824, - "script": "76a914c02e21fe5835ce5361611cde12184b490a13447188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "97057b2d13aec42bc81dbaf5c88cb5cb4692133a0d81aab7dd7530dda4f39df3", - "witnessHash": "97057b2d13aec42bc81dbaf5c88cb5cb4692133a0d81aab7dd7530dda4f39df3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 297, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ed4e37630636dd289a7bf806a8d6bc48b47b646c522bed2183e44ab0dc638059", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 303824, - "script": "76a914c02e21fe5835ce5361611cde12184b490a13447188ac", - "coinbase": false, - "hash": "ed4e37630636dd289a7bf806a8d6bc48b47b646c522bed2183e44ab0dc638059", - "index": 1 - }, - "script": "483045022100a48b55f699579f63652367691aaa346988eeca005a1d5f48142c1909ce6a42ca0220490948a77fa8cd01ae7ad2689ce82be31e0a524f9b7dceff1f50a641c00c7eac0121028d2ac663ff325b4f411b3e5f846366df1eaea6d1ee9b0ba6c896aeaae4f781e0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 220274, - "script": "76a91433c730a953aff27bdc67a4dc546edf1355d4a0e888ac" - }, - { - "value": 73550, - "script": "76a914c02e21fe5835ce5361611cde12184b490a13447188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9934ee52aaa3f1bfd008a15c3a8ee17defd3dcb338051c1054d363ca51ebafce", - "witnessHash": "9934ee52aaa3f1bfd008a15c3a8ee17defd3dcb338051c1054d363ca51ebafce", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 298, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ad921b089d5bf5660b2377240055d6d62c451e8e82b54741f88b473db55c2c92", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300006, - "value": 950000, - "script": "76a914f46da1a391c96e45eebc58d7500ff079e961c27788ac", - "coinbase": false, - "hash": "ad921b089d5bf5660b2377240055d6d62c451e8e82b54741f88b473db55c2c92", - "index": 0 - }, - "script": "483045022100db39d85d7656437176a73798346fab49006a3bec04fd846bc42a479a1cd7c4bc02206e688bcfa0c1452555de5d01aca68d0417ac3919ce9d5343d3a5dd0032312bec012103050931e5304081bf6032b2802593775cee2cea5daa27e0756444fd3eb72774f1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7ad3c2f8a919fab1d707a37757a6a73db341772843949dc421eaebe66528a94d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1000000, - "script": "76a914a1666c8d6c517d27f49711166d7f075ed7a0b9ec88ac", - "coinbase": false, - "hash": "7ad3c2f8a919fab1d707a37757a6a73db341772843949dc421eaebe66528a94d", - "index": 1 - }, - "script": "473044022066b776af77c222242fb573df64eed7ec112fc5ef4aaf4c8e6e12c4dda0dd302e022039031ec299a77528b45448300534729cef693efd991f3be3a3408f8a3c0d38ff0121022126d5f7b096f28692d11e5c3973c30ded085f4f821e67683a716d9f384ecbc5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 911500, - "script": "76a91479f245378f8a4b62ccb730f88223f4ee58ef550388ac" - }, - { - "value": 1028500, - "script": "76a914bbe7b2f91f674d20726b065f1917724e914978ad88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ba6ceddee3d4b4b752181c10c1934c43e0e0d1be1e8a348b8c17639d2cc46e43", - "witnessHash": "ba6ceddee3d4b4b752181c10c1934c43e0e0d1be1e8a348b8c17639d2cc46e43", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 299, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "472efa2efc0b71df6e08ce0fd02f8ba9f383b431c7e10661d9b8b242321ceea2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 930000, - "script": "76a9143e5acfca9f74ffc8392d86c4a73071d1046c94e688ac", - "coinbase": false, - "hash": "472efa2efc0b71df6e08ce0fd02f8ba9f383b431c7e10661d9b8b242321ceea2", - "index": 1 - }, - "script": "483045022100cd3e0a5de28c8be410a8880a01ecadfa064d8de2570786e038697f19981405bf02203a7bd284a94771e6fb13dd067d0cfb576570b486f78294dd9ef143a82f950e6c012103f99698956bde948b21003dbdf0b8b2f770b3472dc4361d6564013ecc3df84bc5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0b3ec64a91f7c379ee23225d4b782bbe25323dbd4f525eef7b5011adb8532d41", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 15000000, - "script": "76a9148c63c41972e73aaab09649e24169e8f65fbac4f188ac", - "coinbase": false, - "hash": "0b3ec64a91f7c379ee23225d4b782bbe25323dbd4f525eef7b5011adb8532d41", - "index": 0 - }, - "script": "47304402204a42d7b396ac2c99bc666c18d4824854eb34d6356aed70bb465ab89c613c4cbb02204105b3546c143c87985f9cfde85ab3e3f8ef8aadae6f3ce18c5afe24e7d211550121028ed8f7e94ef2cae74d8c77c112efaec1e4304ea47d358e72dfd7c21a24ec4f4e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 15600000, - "script": "76a914917e6547b809746cc1161ed919ae496b8172c17b88ac" - }, - { - "value": 320000, - "script": "76a9143e5acfca9f74ffc8392d86c4a73071d1046c94e688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e5c397aece37160ca30b84f84aecfafd43a239d6f55686e47788316641e1b035", - "witnessHash": "e5c397aece37160ca30b84f84aecfafd43a239d6f55686e47788316641e1b035", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 300, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f532f988c05936f5a9dc4cb98312170d20ccb4a99925341a4678f62a8a69e04c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4173821, - "script": "76a914e709c720dfa6efef20895dde2f4d174860c591e888ac", - "coinbase": false, - "hash": "f532f988c05936f5a9dc4cb98312170d20ccb4a99925341a4678f62a8a69e04c", - "index": 1 - }, - "script": "483045022100966bc20486b6f2994a85ad2cb1251b9388e051c3f6df5536963a0ffa6afe60d002203500873507e8245fd0cff5481ce0ba8c0444b26ef2f8c28bf8aee8da82f827af0121038358cbd8b115aa7741232b30258b1c508d7720de877a0581d15e1377ea475949", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d45eb219e89b89e52cd8c05a19e8a91997e78ffbde50572f220964f652afe670", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 3513667, - "script": "76a914d2642b747216b7e5ffb5ff47b23243278b57691f88ac", - "coinbase": false, - "hash": "d45eb219e89b89e52cd8c05a19e8a91997e78ffbde50572f220964f652afe670", - "index": 1 - }, - "script": "473044022076a4cd306ff8092488806d736f5538cb10e981489a9e6dad6cd19f2acf9ee17002200a8d27d1ea4c78b15e9028de9b61ae38bb9739e311db6b8127935d625334c76b012103f369944fa7f3c7e845eaca720053d53d72c3e528145f1bd6088be1c62533a022", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4990000, - "script": "76a91411bc765a1e33ee0449c81eef21ea0fba31ea2c5088ac" - }, - { - "value": 2687488, - "script": "76a914c577c400ea30f337b59228c8734c93720bcb74de88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "96d40c7bf21006aaa587712c05ac908984c5d28d829afd2cb291ed47d56dd5d2", - "witnessHash": "96d40c7bf21006aaa587712c05ac908984c5d28d829afd2cb291ed47d56dd5d2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 301, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3e072881a1e965ccabb705f2495e5c6ad85d81f868299bb83d3f848876e73820", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1500000, - "script": "76a914626ebedca70103f5c1e06ed5904f0bc478a263df88ac", - "coinbase": false, - "hash": "3e072881a1e965ccabb705f2495e5c6ad85d81f868299bb83d3f848876e73820", - "index": 0 - }, - "script": "483045022100f53ee6f4b4d84d6a033763853697281e7e93e53c09968ed8fb09b933259571bd02207c50d2166dda7b78a2df74724587cd56e305ce91b13c6e6daa31fdf0c49e9b02012103cba05903e33c1522407602b64d91ad92d7bc33df9cd74d5a97288d5379296128", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "391e2668170a0f3f6e321103f8f8a458e61b35bfe582c0c7a59c1150787024cf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2880000, - "script": "76a914cdd6cbd410b70ecbca00b02d0f962b710a7fdec488ac", - "coinbase": false, - "hash": "391e2668170a0f3f6e321103f8f8a458e61b35bfe582c0c7a59c1150787024cf", - "index": 0 - }, - "script": "473044022023586f315b28e53d3568cfbd5a2264d4275e6e3d56697b8a8073f2875674370e02205adcdd8a7af801fa8e716b5bfae14bade2b1fb1ef4c38a855d354dd4c4b72bca012102e6b43d1e214b69683b25be7a393e0008727b47b84a16a4f6bd5250bac26b6463", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2625000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac" - }, - { - "value": 1745000, - "script": "76a914fb2cc2d580e8db8440810e9f4ba58ea8f86b59a188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "003f8ccbc80850a6c43c5de8923b2b1e1fa25ea4e4e7a9e3a3d6d7a3ea30005a", - "witnessHash": "003f8ccbc80850a6c43c5de8923b2b1e1fa25ea4e4e7a9e3a3d6d7a3ea30005a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 302, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3d7da636d765043ef15bbd1a8af9945216ff4aabdefd3f7fd9593aaf2d2570fa", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1144383, - "script": "76a914271ad45fcecc102c174699d7ac51e98bb6d971cb88ac", - "coinbase": false, - "hash": "3d7da636d765043ef15bbd1a8af9945216ff4aabdefd3f7fd9593aaf2d2570fa", - "index": 0 - }, - "script": "473044022049ff54f8b26202f7eb201e66f43f643e177bac323f07e844a4d21f3ef340aa8102206bc224e5889ecd4c5529c710f0101a2c68cd74fb3debbd02e1722c12c2c8ed5d01210314a77c93c0f493fb193db3d2b55fb903e9d9a5aa9711ed738c5229c6abfdf010", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "47fcfe588788306c5c7df46fb60c5d40020edc9bbfd099b0a7341fa89039513c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1064693, - "script": "76a9140eb31b65d6e37a7cb7e7805edf5317d58e57084188ac", - "coinbase": false, - "hash": "47fcfe588788306c5c7df46fb60c5d40020edc9bbfd099b0a7341fa89039513c", - "index": 0 - }, - "script": "4830450221009f483da74def05e362844a3696f0301f0dead90fbd83a5b8817d826238a73da40220786c58b5ffe96579ab603c0e3812efbbe74f54194109f2c5b1ed8fbe1d24ffc5012102cbea41f2fc66a830a445848a27b778a3c85c13b4cbcb7c6427ab6dca9cf84495", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 211467, - "script": "76a914beae959d7a988ff3542e0d4c50c3869e8dad050a88ac" - }, - { - "value": 1987609, - "script": "76a9148ef8d266125723304cdc8659c611c6d8173eb6de88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b19fd8f868f7bc3cac4dd32ca88d981f72757098d70242ff36fe4c56b18d3fe7", - "witnessHash": "b19fd8f868f7bc3cac4dd32ca88d981f72757098d70242ff36fe4c56b18d3fe7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 303, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "936a13776b3fae1bbe744b69e23b214f415fbf1be201241a0d7f1443a4ddc20a", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 100000000, - "script": "76a914cbb27b27212a73221826992d4472a34616c467ad88ac", - "coinbase": false, - "hash": "936a13776b3fae1bbe744b69e23b214f415fbf1be201241a0d7f1443a4ddc20a", - "index": 5 - }, - "script": "483045022100c0229454dfe3865ae09b7567f3d015ba71e672bddcfa409870a6a6dd09eafd3502205e2e2974cbc9f778941c0f880e2af09e035370a3a691d99fe8b99fc0e4511f800121037a8d57c3ded5ac2f7f77a77d8a17ac8be5a3f245155987fe2dd302b71889f794", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4f8999d2dec3aaa6d6b44469f80750f009cd5abedb70dd3895ee9eaa6cbf769c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 57870000, - "script": "76a9140b9c2e6fc8f72f235bb06ca0d4d3225ea919d57788ac", - "coinbase": false, - "hash": "4f8999d2dec3aaa6d6b44469f80750f009cd5abedb70dd3895ee9eaa6cbf769c", - "index": 0 - }, - "script": "483045022100c5524909a019f7b73617a681ffc2bf61f5169f7b4451d7e458e6bd8637d8e06c022049730b2fe8fea85d1f6549cbf073637ab96546c5612d86767d45a78845c7d359012102ef135603bc65d9eb87cec363e7f8d799233612d0040c2bb256d10b4b3efdb405", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 140300000, - "script": "76a9142a33303d0d7bdf7bf14c7b1651d770b23e00ae7d88ac" - }, - { - "value": 17560000, - "script": "76a9141a5ef76417af7b95642f2b892c67da61edd0a22188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "65f46855e37170c9764cb46097b58eadb6f0ac3be9db6ecb4284d37af6999fd7", - "witnessHash": "65f46855e37170c9764cb46097b58eadb6f0ac3be9db6ecb4284d37af6999fd7", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 304, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8f5a12956aba65f1cd79e24ea85ca18a6aad7997272d7c7b897231ae5387fc2e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299640, - "value": 100000, - "script": "76a91426077c33a8675d2ea6d47df122696b21bf8f33be88ac", - "coinbase": false, - "hash": "8f5a12956aba65f1cd79e24ea85ca18a6aad7997272d7c7b897231ae5387fc2e", - "index": 0 - }, - "script": "48304502210091ead6c6dc9b9e4343067ff98724142a368358580727078b1f7a718674f44f4202207d28fb790a16a9dd0bcddd3756f92fd95ecb355e6bc4cef07a707e19e89e739c012103b4673b383f465958c0edc538adac06f3b4a128b51dc37f3539d3d87f78d788b8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "66bae9d00260203f9825b99df886a7f906a402a294df288ca3aa9abef70e4cec", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299934, - "value": 1001662, - "script": "76a914fe487bf5b78d05a445e983cfa220a57dc211972c88ac", - "coinbase": false, - "hash": "66bae9d00260203f9825b99df886a7f906a402a294df288ca3aa9abef70e4cec", - "index": 1 - }, - "script": "483045022100ba16f09e857fa3f1ebd96221f1d5817bbb29e2f33b85e6970dc56bd953084af502200634275498d69676cf463752948b5a0247c9550e8a125633773a654fc0101d11012102f829a6f6b58330230d81a249a36c8ce0ad79a3f19ae9d093ce009a0c2567539d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1071662, - "script": "76a91440f2b5893ca0e6b1ccf97eff4c1837717c33cd3888ac" - }, - { - "value": 20000, - "script": "76a91444b725860b4858f20adac3753ca5b3891d1203bf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0b52a563082fcba08a7b45d51199dbc84dc086abc7a68cfb4080e27251663107", - "witnessHash": "0b52a563082fcba08a7b45d51199dbc84dc086abc7a68cfb4080e27251663107", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 305, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b810fbe95b301fbc57a963b7e9b072da0f1beb91b76e7f01c779f79faf722aec", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3702782, - "script": "76a91470b9936818531f01400c4fb73e8af9ad383ab8f988ac", - "coinbase": false, - "hash": "b810fbe95b301fbc57a963b7e9b072da0f1beb91b76e7f01c779f79faf722aec", - "index": 1 - }, - "script": "48304502201731c19aec06bfcd6330b0e27d31525b3c84171ad26d04eeb76f8d66e34fb9750221008b969a21d6e2f2372769c65d940ef029e91c25fa53361a8acbc16d4aecf935be012102cc5a1d49324ad55bc1ed281689f075fb31c65bef4b8252e0c05cf57e931b76d4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "981f2b25a6befd42989090d25fa39b1a53fbc3e8b73b63578bde718c8ed0e268", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298126, - "value": 11818, - "script": "76a91470b9936818531f01400c4fb73e8af9ad383ab8f988ac", - "coinbase": false, - "hash": "981f2b25a6befd42989090d25fa39b1a53fbc3e8b73b63578bde718c8ed0e268", - "index": 1 - }, - "script": "483045022100ca9dc4b55f4c29362e95cff4bc5112fd2d9c5f94563eeb732655b0c1179bc1c802201d058b39d7d464b7e883c9a1c41a4708062c2d94ef9e853377412ceccd4c3d3b012102cc5a1d49324ad55bc1ed281689f075fb31c65bef4b8252e0c05cf57e931b76d4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2202000, - "script": "76a914d309884cae56be2ce3117e818ca26893b02e439188ac" - }, - { - "value": 1502600, - "script": "76a91470b9936818531f01400c4fb73e8af9ad383ab8f988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ec5aa9d042c54bf07ce2aa03f07625f1daa36cefffa828495c495a293648f7eb", - "witnessHash": "ec5aa9d042c54bf07ce2aa03f07625f1daa36cefffa828495c495a293648f7eb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 306, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0b52a563082fcba08a7b45d51199dbc84dc086abc7a68cfb4080e27251663107", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1502600, - "script": "76a91470b9936818531f01400c4fb73e8af9ad383ab8f988ac", - "coinbase": false, - "hash": "0b52a563082fcba08a7b45d51199dbc84dc086abc7a68cfb4080e27251663107", - "index": 1 - }, - "script": "493046022100a29c8809a9dcc6be694efff507c3416937de2f4c63920fbe2735afb941cdafad022100a89dac61a09160dfbf7cb4b8fd36782f2ac72a6ef23d49afa84264e5f51ec855012102cc5a1d49324ad55bc1ed281689f075fb31c65bef4b8252e0c05cf57e931b76d4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 660600, - "script": "76a914948be395d86880f8f62aa410ec2ac4a5f1ed3c6588ac" - }, - { - "value": 832000, - "script": "76a91470b9936818531f01400c4fb73e8af9ad383ab8f988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7174fa91c86c3baa8ddd8d4b4f74931452b3c90b1e0fedf8298d0d12d63669ea", - "witnessHash": "7174fa91c86c3baa8ddd8d4b4f74931452b3c90b1e0fedf8298d0d12d63669ea", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 307, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a3db438757d7d33d9dd20edbcc17b40af1c0435c2df67a4bf238d00f70eca888", - "index": 242 - }, - "coin": { - "version": 1, - "height": 299657, - "value": 13000, - "script": "76a91476fd7fe3b5d14cd8bd16c3f4eebfe41ef7a5522488ac", - "coinbase": false, - "hash": "a3db438757d7d33d9dd20edbcc17b40af1c0435c2df67a4bf238d00f70eca888", - "index": 242 - }, - "script": "483045022100bc8e6823399d1a6c96bb602006242f77c2a913b746cf87b3ab5629c99eb6dbe702207d48b59a571eeda115053290c7d4b2216d24f89fde4fa444dff60e8323935f400121020aa39b918ef29813310a90603242c4b3b6f666206ca0bb79eda473d7651ddb9f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "efc5f392f9f3b50a5ff6ea6a94f9bd0b4109e47eaa8b078bcac764d217fbc92c", - "index": 224 - }, - "coin": { - "version": 1, - "height": 299826, - "value": 57000, - "script": "76a91476fd7fe3b5d14cd8bd16c3f4eebfe41ef7a5522488ac", - "coinbase": false, - "hash": "efc5f392f9f3b50a5ff6ea6a94f9bd0b4109e47eaa8b078bcac764d217fbc92c", - "index": 224 - }, - "script": "4830450221008691fc52e1afbb3b4f53cae70b4c55fa3826b528b77ac39f5b87d8feff44829202200c4034444b9e635f2795efb3f5f5154f84500dbefdb957cbcdb31522e6d4755b0121020aa39b918ef29813310a90603242c4b3b6f666206ca0bb79eda473d7651ddb9f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 54000, - "script": "76a914eb1f8095f939767b978903f7fad33f2c2c44a55388ac" - }, - { - "value": 6000, - "script": "76a91476fd7fe3b5d14cd8bd16c3f4eebfe41ef7a5522488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3a77676c4bbb93e8cd9259269bebaf981c5e364d750e43d607f15f86c1703708", - "witnessHash": "3a77676c4bbb93e8cd9259269bebaf981c5e364d750e43d607f15f86c1703708", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 308, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2a66592f731f882cf45ea1e0cbac5dc86281776237e6b6d34eb49d119c85c4ce", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 1600000, - "script": "76a914d368f73003ce05ebfb34de92588d16c4aacd337d88ac", - "coinbase": false, - "hash": "2a66592f731f882cf45ea1e0cbac5dc86281776237e6b6d34eb49d119c85c4ce", - "index": 0 - }, - "script": "483045022100e832a5e8904237b0938a9c8dec58b4ea729d06a9be792164c967968446e1331302204e8fb02eda70aeb35e4d8e4d83714329bd894cae0fc1b6e28d08a4ff5b4ddf69012103a1644c552200d97720ddf96286c4cd1d259c3982e85163c67e92d9e5b7f3d47c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "68a5bf33c4b487d2015ee78e8a9591204c682a144f093b03b7139fdc9339e211", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1385444, - "script": "76a914ef352d5c25eb28792b4e780dd08cb00b6d198d4688ac", - "coinbase": false, - "hash": "68a5bf33c4b487d2015ee78e8a9591204c682a144f093b03b7139fdc9339e211", - "index": 1 - }, - "script": "48304502210092b053b29f4e79b0b74e6ff864ad29c59018a81ad8c293c9351c3cf01f62145802207bb518ba3c69e545c8955558955c18e34b2e3b70101f6339fe44ff0582cbca3d0121033234bca1ddf5a666dfe96978d0c77d62ce5ac7d5084533757753035619ed26ba", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1075444, - "script": "76a914c1301c42de7ae3845a4bb496fbc020ed02f255a988ac" - }, - { - "value": 1900000, - "script": "76a91452918ae76514dc08ce9c3515e6c540e9aa26aa6f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "147fd3316e47bda359a4daf299f7e71b91e5bd78928748699e132a40e1fece94", - "witnessHash": "147fd3316e47bda359a4daf299f7e71b91e5bd78928748699e132a40e1fece94", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 309, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e1508d44f7809bdc36564a08ce6593a402897a36f8f22a81c33da5bbff67f652", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1529263, - "script": "76a9143c1ef9d90331a71018287347a041a9b5169ddb0a88ac", - "coinbase": false, - "hash": "e1508d44f7809bdc36564a08ce6593a402897a36f8f22a81c33da5bbff67f652", - "index": 1 - }, - "script": "48304502210085e0096e6fc2c7e72c1d5dd08f1c0ca2cf0357cd57be78ed5d67e5ed5ac30d62022048b17bd9d8f7c13be57322cfec5de66d62504d33d5c0c992404d9bde0a31e265012103aa170e86fd71d2226171f5c170c96ac27a12947f6c7e37fb83f3a49cd9fe21c0", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "00aff150c1d03212b8cb52ee7a0b5609636f26e9219760f1f7bb82363096fa88", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 691286, - "script": "76a91451cd1dbf2012e7ccf95ee2682fcd701260ee016988ac", - "coinbase": false, - "hash": "00aff150c1d03212b8cb52ee7a0b5609636f26e9219760f1f7bb82363096fa88", - "index": 1 - }, - "script": "4830450221009c0027ae55d1aa716173e174ea6097663171c8f223882d1efcc58d62692924cc02200d5ce84159f775f3a8a7b89fe309b3bfd30a595c90a4f198f64c492a8e9da4100121020ef771f94c3693816908a0a8f0c7b3d399079a71aeb28bbb58b36ba8efb15f66", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1228719, - "script": "76a914760769fc4ce2d412120fb78912f25890d7e5297088ac" - }, - { - "value": 981830, - "script": "76a914d70bfc02a63a58fac491c547008b68cf4df29f8588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "af4a205d9309b423e1201498d88d8cb8bd663b88762a72325e9987c7d9b8a914", - "witnessHash": "af4a205d9309b423e1201498d88d8cb8bd663b88762a72325e9987c7d9b8a914", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 310, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "363f4acf6641b3dac1088a0ecf0817f7dd78a3ab163a9ae7ec3d0b61659fd6dc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 96017376, - "script": "76a914cb8e4270b294ca60175d6c95fdd14bb9d744af7488ac", - "coinbase": false, - "hash": "363f4acf6641b3dac1088a0ecf0817f7dd78a3ab163a9ae7ec3d0b61659fd6dc", - "index": 0 - }, - "script": "493046022100a7126bf2b5b652585e50251ef0f57a7f59fae6a2a388b9e4ddb0c221a2e37aad022100804211708415b58b4bec3dc690b12010a96619daf753dc32b5caf585e002852e012103b65b3cef23a61e530ccf9f539e2da0797f771b06d17ed8d6207687fc29545485", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eebcb87e772392de06e9c253d36550824e9485b173c91152cca3c62e762ebb05", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 96469977, - "script": "76a914b4094108c1b859d631bf333d977314946ff23ddc88ac", - "coinbase": false, - "hash": "eebcb87e772392de06e9c253d36550824e9485b173c91152cca3c62e762ebb05", - "index": 0 - }, - "script": "483045022100f6be2672595b41c6cb16cd9384ff76fdfb9ac096d1e0580e1505342442992d8b02202b658179de66781bcdd9741a1c1c65c3eb8957f6a16e2a58000c5ef300a27b190121037ab3cd9c03f3bc938b113457ab4ca361a91945f2d8ad42c43f3fbe970898b629", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 83657353, - "script": "76a914d1631196761cffc731739b2717248ec1116d72f088ac" - }, - { - "value": 108820000, - "script": "76a914f7600257ff7a3870c1641ea60ae2ce08aada86cf88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4b40b06f0b769a672d67a22185a45af4746fa9d4e46d5b7bcfed4461aaeec96b", - "witnessHash": "4b40b06f0b769a672d67a22185a45af4746fa9d4e46d5b7bcfed4461aaeec96b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 311, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9b9a80c2ad0b55144c64d95c2209740174ca6e768ca93afbeb35a8fb4e6f710f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 8260000, - "script": "76a91412d1f05eec1607889a5cb3049b7686765a3d1f0788ac", - "coinbase": false, - "hash": "9b9a80c2ad0b55144c64d95c2209740174ca6e768ca93afbeb35a8fb4e6f710f", - "index": 0 - }, - "script": "483045022000a93bc272a3c556747b371fa399220c458aee8ffd69d81f4080490a648a1b150221008f7066eb53ce3d1628fb0db6d6207ee5696dd965957f3b06342251344eea62720121021692120692b055f1b0ad6c32fc15c55e2a7df270eba65cadd0f460a586a8e68f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6c19142136834c10d5ebbc4b826ed3b8d85127848db79fc487658809d8f28b05", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 67890000, - "script": "76a9145d26b6b577a7ac894d6d68fbdda2b71816dfe01888ac", - "coinbase": false, - "hash": "6c19142136834c10d5ebbc4b826ed3b8d85127848db79fc487658809d8f28b05", - "index": 0 - }, - "script": "493046022100c5ce24ed2936fe25503af658181b0fa5185fab9bd84bc9d76f1daaa8d129dbfe022100d1b0fbaef94d356ffdc8ca9517e32eabcfa706a850609043d6d323a189963f00012103e4c008c481c5e7df9525e869dfec86a7b65f282020669ce70106f75038d6afac", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 70000000, - "script": "76a91437faa69a870ffc46eb5f5c1a2818f65e26d8d91888ac" - }, - { - "value": 6140000, - "script": "76a91435f9a2f6b2f99f8686dff43f295f735a2da25de188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ef5ddfa319ad8b5f065e84b4ee7357ac2cb58289243763bab6411aad3be461de", - "witnessHash": "ef5ddfa319ad8b5f065e84b4ee7357ac2cb58289243763bab6411aad3be461de", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 312, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9b57ac989f3e035437c696780c96c88618b9c3909d27e604e6b117e9aa491b6a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 5554544, - "script": "76a914cc663f0f150be469a49946ff53bf59dc4b1f60e188ac", - "coinbase": false, - "hash": "9b57ac989f3e035437c696780c96c88618b9c3909d27e604e6b117e9aa491b6a", - "index": 1 - }, - "script": "493046022100aa329679159d333dbb53af026efd373dd6c68fae1136c0fc40fa62f4a6b7dc20022100b9e8de72f4a849ecd21ea1cc04d1239934e9fe3422d050474a5140b83fe039e10121024be38a0564f0f4ab33cc65ff1ee5216bfbad88c7710f373900fd66f46f4318b4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cfca707b9edc24bda7aa34de9d6fcc875e9f41ea84cf6bf858d9040fe42a288e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 98370000, - "script": "76a914c4faac8ccf1be5c9b7472025b93bb24ffa68f21188ac", - "coinbase": false, - "hash": "cfca707b9edc24bda7aa34de9d6fcc875e9f41ea84cf6bf858d9040fe42a288e", - "index": 0 - }, - "script": "48304502204470206c55a08cf2f7cb301ea93ce3629d7139e849873a9ab4cebad1d5a8e306022100fb37810d4fb9aa18c1dee0f6b8cea8da56ff11d7e5f06a5df133b0929ec2d389012102414c98b45f1c1dc6e29a72514c0b5d1411be9e41abb01d2f6e80a3f2700a86a2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000000, - "script": "76a914b198c8d267a0840436bfb076ac0e6ca1ede09d1288ac" - }, - { - "value": 3914544, - "script": "76a914b097df61d768e8eda3023d9b434287b605e3d2f788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "736a40b153ccfeae6cada21933fcdecbd03435e9f3523dd9e251c679ffefd8ee", - "witnessHash": "736a40b153ccfeae6cada21933fcdecbd03435e9f3523dd9e251c679ffefd8ee", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 313, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dfe1e1c401b06fd8c1179467ead67d417104335f5ae0aaf2674763a5add9edca", - "index": 9 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 2191177, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "dfe1e1c401b06fd8c1179467ead67d417104335f5ae0aaf2674763a5add9edca", - "index": 9 - }, - "script": "483045022100ab3cb120942df70e5112f7a9988aaf7c7aeaea3130a36f07c79f17477013b448022009fe346056cd74370ec3f4578aad4fc501ed39a2f7110d0b00fc9c7a18601f20014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7786b1fef695745ca47211e601d0a89feac273a448fe11ec5372d4608fcff520", - "index": 5 - }, - "coin": { - "version": 1, - "height": 299867, - "value": 1112375, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "7786b1fef695745ca47211e601d0a89feac273a448fe11ec5372d4608fcff520", - "index": 5 - }, - "script": "47304402201a9e77c734bdd94025773b7cd2181697032af8921d3d0364f9e0b380830dc22a02206e54bc150f32c1422ce92cff723a9c050ba8e029cf9930a3b29cf455c5c54e70014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9695c5d53e1e328b0286ad56afa874bdeef524abf7bbeac3815ffd0c168d3602", - "index": 9 - }, - "coin": { - "version": 1, - "height": 299881, - "value": 1217976, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "9695c5d53e1e328b0286ad56afa874bdeef524abf7bbeac3815ffd0c168d3602", - "index": 9 - }, - "script": "493046022100ef3a1f08c6c7ed20193d50df6d652636ccadf7df821672c9bf31a7f909b95181022100ecce170b80d7077a3345574f7998b756feb0972696813f882e295ba9baf80e8e014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 65 - }, - "coin": { - "version": 1, - "height": 299934, - "value": 1118016, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "ffc2c3b8f9aad6aa4f8acc148ada65ea5b359e732349680022d2ea817ae0e3da", - "index": 65 - }, - "script": "483045022100aeec57ff8eb46d4826ff2e46cab99e566faa580523377677a6200da01df1d01b0220486da1797e5fafd3a012c45b5c3ab347ee1b75cc100152d8b660dab4bd4ccb5f014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d1b4a000c70aa82b33d1f9775e9a9f9520318a701176d49d469724a1c5648cfc", - "index": 42 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 1196576, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "d1b4a000c70aa82b33d1f9775e9a9f9520318a701176d49d469724a1c5648cfc", - "index": 42 - }, - "script": "4830450221008df2cbdd3975052769743452c4b479e8fef033a256432eb5fc58225f590d32930220383e8363544853175b19291735a02e76a2707d6823c73069fc87d23277415ad6014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 2217696, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 9 - }, - "script": "473044022062e45f3474b3287b8e5dbdcadc335ad51ce32ebdbe54646d76a8f33d2dd48348022002e59a2df1c4f9c071ebfc139e72d56e367c05d29443f6373d496d5c1304337d014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a276ab8e71f9349020a826d20f3d593dd8c72c018178ace54073f08c5cf8af2b", - "index": 60 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1141598, - "script": "76a91498989c2438adb2c90c3fe9004c8eb513e0d9cf2b88ac", - "coinbase": false, - "hash": "a276ab8e71f9349020a826d20f3d593dd8c72c018178ace54073f08c5cf8af2b", - "index": 60 - }, - "script": "483045022100f69ed21bbe8e7191ff8936aeb51ed10227deb458036879c14beae328496dc661022015071e99c20cb2c5f2a386deef52fd518076f489990bb0b0b41d5fd8e7c783e6014104fcc3e7fc27fdeb8fd564f1bd1bee55be46621e1d04563252703f49ab2e42658c891a041e65ae8fcf180baadb7e77f3bcb922250c03d2e2eeaba7ced4b7df8d3c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d06517c2185377d3befc33505cf4b67a9bea7f69788d4290577a36502fba51ac", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117481, - "script": "76a91496f2c471e0e9833e2ca649f6a8d359022efebbf088ac", - "coinbase": false, - "hash": "d06517c2185377d3befc33505cf4b67a9bea7f69788d4290577a36502fba51ac", - "index": 1 - }, - "script": "48304502207c9a4cad1f812742db6704ec2d24cf8759da56b41d0d33745b877b9154c0fcc9022100cfd90d02c203e868a496feffaed6566777cc8bb335dd16f8ec7d222b96ec0feb01410423b71c2a455e22f620cc74a484fe97afe9d7fd0543a57b1071dee320d55cbfa1082f39236bdda3c0e396caed5041cf7babee08ef0b956c359344bf446ad8ed04", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10195414, - "script": "76a914e932d89135af1ed5c3722c9457744c80547e4c6b88ac" - }, - { - "value": 77481, - "script": "76a91428e89b51a192297cc2a56381c0cfd0ebcd97edb388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6ceceb3e2131378aafc6e5bb41cf2ac430e2df2da046dc85f5bd132805e4322c", - "witnessHash": "6ceceb3e2131378aafc6e5bb41cf2ac430e2df2da046dc85f5bd132805e4322c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 314, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "aca3eb7f17e6146cde9c1f71881b693d93f7b9c637a21c6abe9d1be092ef54f9", - "index": 1372 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 780000, - "script": "76a914c3fe90a28145dab4a418ec50fa1b21b12ced004888ac", - "coinbase": false, - "hash": "aca3eb7f17e6146cde9c1f71881b693d93f7b9c637a21c6abe9d1be092ef54f9", - "index": 1372 - }, - "script": "4830450220342045eebe7e4dc42bba7149543c22cd9de536da96f26b486838273af75ac23d022100ef002d7bde7bd9deb3fdcf71b827219c3487fc4facd29e31887cf2acf9c932a00121031c94db97d13cf5949d3277593855a7208392650731bd9864ec597da7b320153a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "31511f6adf935363011d61f69652cede417cfc39885289e6ab9d51d30f173a45", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1200000000, - "script": "76a914bc501128b888169495c5866baade8ec6273aebb688ac", - "coinbase": false, - "hash": "31511f6adf935363011d61f69652cede417cfc39885289e6ab9d51d30f173a45", - "index": 0 - }, - "script": "473044022042af6d4fa7fe0b9c72caba8dfedb3672f5df62b301e2c046b1de53679016c0a402200097a1aee66309a6e39da482feb01bd280686b60c54b30574979953724693888012103fbd69331308b9eccaf54078b28ee4ee3dd98f6c1aa87a90fba1f649ade536ea9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 1006 - }, - "coin": { - "version": 1, - "height": 299989, - "value": 9250000, - "script": "76a914ddd25e17885e7ab5c53e7d451c7d4f4e42a62a5588ac", - "coinbase": false, - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 1006 - }, - "script": "48304502200b6acb618db4dd691e229de5fd9f5d2bbb3a841576630053b6e8fa983efc393b0221009715ea83d61274c1c91ade6a763c74888b0320c530d4d53e33bd3f9c43f7a371012102d56b96ef320e05c7ca2403038662c5012b8cf9dbe7a1e4cb23008cc2b4d15bbe", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3bdd887911622b58804d0a22eb0c2efa067958ce79f112f5a6440c3b1ed117cc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 289990000, - "script": "76a914fa31576f07f2dfbeb0d68110a90dfaa311f825fd88ac", - "coinbase": false, - "hash": "3bdd887911622b58804d0a22eb0c2efa067958ce79f112f5a6440c3b1ed117cc", - "index": 0 - }, - "script": "473044022058e65ec81c1dc53d1ba08ed5c4349ebf94c484ad88f236d9b244fd23881ec457022013016423ba34592b1a0056b5fb35b79e13c27e15c9abdd7557d18c8d77b3a9a2012102e5d66205590c5a8199b19a4e6f3ce455ad40989fa7899937c04a0981e0628d1f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b0ea7832d92a45aa15d8ad190f26810099c6d74d5ebbcd305b4a5594a7cffc9c", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 1500000000, - "script": "76a914d4141bdf3a3a385f05744946dfb465f43e02ef7f88ac", - "coinbase": false, - "hash": "b0ea7832d92a45aa15d8ad190f26810099c6d74d5ebbcd305b4a5594a7cffc9c", - "index": 3 - }, - "script": "47304402202becba8b2103b96dcc5c39112d2dadcfca3b1881a0b04f0c7010c2a40f091bb002201d587069c18014e9e18e6f97cfc95cd6ad82046429345d67afbff3bd0e73f46e012102533915519817337d975cc08ff5f553e23eac7dbf769d58380bad892456f14b3f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3000000000, - "script": "76a914a2b1a9a16ecea77d759328b341d2592cbb13e52688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1403059176e98b1124cb827d9f6f39ebee91d5f2744c0e861a9419d7a25b22cc", - "witnessHash": "1403059176e98b1124cb827d9f6f39ebee91d5f2744c0e861a9419d7a25b22cc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 315, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "44c60b3aa01ad0d196d1230ac87b7a6384d6936cccfd1a6a88688f9fe32d32db", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299753, - "value": 4750000, - "script": "76a914dd595a5fb5f9bd75f9acd5bf2554cf2ca38749ae88ac", - "coinbase": false, - "hash": "44c60b3aa01ad0d196d1230ac87b7a6384d6936cccfd1a6a88688f9fe32d32db", - "index": 0 - }, - "script": "4830450221009cc3a9c774d0e0f06337919e2ec8ead2b9effc30ed40fdb7a0f9ff66a1865b5b02203d1df624bdb38d3b0ea902fcc6187f03ed9e4d5e592eb897044ef954db26c3e0014104fc63947b4c40984b0d5650c9da3b34b7ee7e65646b363e338bd637506339896857950fb651a7a9002f27be55db35c57bc04a9e95d3f6874532f15f121a478ac9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "17d23ef2cc65a4807380c3d95f0da780f6072e6ef97a1b395fdcb3430e4038c3", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299816, - "value": 2210000, - "script": "76a914c34a7ea55ca8f30567621507258bf637fe0496a588ac", - "coinbase": false, - "hash": "17d23ef2cc65a4807380c3d95f0da780f6072e6ef97a1b395fdcb3430e4038c3", - "index": 1 - }, - "script": "473044022066f0654d5cee74c83f55070d62a9c99c06898b19ee6b596b460af86d40746dad022001bb61ff04f194ea699fea8caca14610800d7a55cf76dbe77001f263a59eee6d014104e5277d6fe85b2f80425a9c74f37433f02efa9d2fbf28ef748953afed5529c6861b3958d7a59390540e5889c66dcc9e28574ff86b0bd7603cb82f9a8ea7976aac", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6d0d548ef07d9d289eab5a79f2d4cda395a9e78a7ef4bedae95e0c4d8da963a6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4540000, - "script": "76a9148e171ce2764e859d549849dcbbe8f265833c21e788ac", - "coinbase": false, - "hash": "6d0d548ef07d9d289eab5a79f2d4cda395a9e78a7ef4bedae95e0c4d8da963a6", - "index": 0 - }, - "script": "48304502206da4b26e29cb16fa2322389f1868f47a6d9f2833ea5cdd87fbb87c8520b240740221009c7099f449fdab2098666e1dee08230e957fde2de1c3a657a73d7cd4e7c4939a01410482996a5eabd5ec541141c75d6455c65e80629caa6d857712e098453318f9bb5a38fea5a9ffa1cad0583d46b912bcae30c454c420f46642b80bbd7722a2dd09c4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1232e9776ecb2fc5a30b2bb89201c93ce575e8c300d68aa199e3a14836541c4a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97491, - "script": "76a9145f7e7a32f39d43557737c2873a527d2cb2b044a888ac", - "coinbase": false, - "hash": "1232e9776ecb2fc5a30b2bb89201c93ce575e8c300d68aa199e3a14836541c4a", - "index": 1 - }, - "script": "47304402204516febe32e75276c68af89c61fedde54a3f0d60087661b8a90ac4b4bbd2258b0220756e4e3a5d5dd86c0c34423c7e99f1e96a3e420852a9561c9ee68e0930443e290141047b7c78c693a08314fca9dd810ddd62f5bb11742f5852012241f4b97cc7f941526b6d082ceddcfdfc9294eed70f62e6ce12b8b90cc851537e342d841c94c8aefb", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11500000, - "script": "76a91436e1cefe33b55aa9f52607a1c61c0b7a61d2372388ac" - }, - { - "value": 77491, - "script": "76a9143f14fbc1a72c439b5e0d82f5be0dbef1fbdf374888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e22f550e52c242d2b4eee6afe17e653ec95965d16347a60b1f73ccb855139983", - "witnessHash": "e22f550e52c242d2b4eee6afe17e653ec95965d16347a60b1f73ccb855139983", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 316, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "61dbc2e42ee32bc83518ced925aeab11e5c977ef71bd23e07d580212a6555914", - "index": 77 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1000000, - "script": "76a91435b20146e8dbc94de6ff8bde70342e8836c6997a88ac", - "coinbase": false, - "hash": "61dbc2e42ee32bc83518ced925aeab11e5c977ef71bd23e07d580212a6555914", - "index": 77 - }, - "script": "483045022100bb0cd60d02918ef3a902f4256ec6db4de474aeb7d44a8d6ef6c761487fe3f7bd0220467e698b36965ccc0f68cee83eaa13b68bcf7871653d468e0bc51e9c5cf0b6aa0141040fd67647c72697defe2a42a4b38309463a6b4a05351891e8a60208ff8006420722bd9533bfb6dc7ba7be88d8170f99251a685b914f1ae712f7ee6eb899069194", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "591cf2b15a654e6c3cce6ae8028732f210c2b038e2c444471884903a70902b24", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3144675, - "script": "76a91403d354d728e21a71080d718f952755a0bdba1b6888ac", - "coinbase": false, - "hash": "591cf2b15a654e6c3cce6ae8028732f210c2b038e2c444471884903a70902b24", - "index": 0 - }, - "script": "473044022018c160e479a700661ae73d6d409e9128784c0a837b613ed982eee79e267f06f8022030dce4b7cd4ce05815181c296d029f5cfe0a7ba2d83c38cd1efa7225590c000c014104ca2c5bbf5009c8be187fb0e909fa57f78383dc33859c11b9e6478c2447e9253b616d90383b3350d65885b419e3fd788f12954a498219c48783eadcc2b878b542", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5944a82d22f033a74596683c59a2e85ee9679c7a9bcffad856a90a4da2df0aa2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2442301, - "script": "76a9149fe1a2a09cd64743a2b06c258b6dc9ad0783c49988ac", - "coinbase": false, - "hash": "5944a82d22f033a74596683c59a2e85ee9679c7a9bcffad856a90a4da2df0aa2", - "index": 1 - }, - "script": "48304502210094b0ddb59c42e3f64a89ccba384738941f6d5d2e6e20231e125187acbffa3dfa022053040186939e9c39b23d527972257d5ca4f77a639b900caf53d99ebdb7a9edc00141045bcd66b964117ae67b0279dfc6b217d5828e6973defa5f6897bf4c8f7c99fab833891b00d6943d73f154503cb1066a72c5dde8c2aa085ce268f2efeafe96b839", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a46c697ec23b1aa5a9e990e9e3e8142e59712c32e400057bdea3beda04097596", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 2974550, - "script": "76a9143e8d072094c6a30fc02e3081001918ceb70bad4e88ac", - "coinbase": false, - "hash": "a46c697ec23b1aa5a9e990e9e3e8142e59712c32e400057bdea3beda04097596", - "index": 2 - }, - "script": "47304402206ea655a74e289930c313415a1f02fa5fc213537f5e939071f92753ec672ba92702201a8555de29315e248e256331087423c6fb12e6351f861d5612d989e1759e8987014104295aeb934b36786a41effb204999e4649653de967f4e2ed09f905d8f580f4c6abdf1640643f79471de8d42ab410bf9a64503a18ff7dfb295d3e157efb89fb38d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8539439, - "script": "76a914b58c957912afd089bd12f605a7d0bc1ce460402188ac" - }, - { - "value": 1002087, - "script": "76a91462899db282a43a76ec1f9c5b79adb0de00aa520888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6fb7ee5e64f85b100c61767398b303bc973fc65562184317ce6d404b528a00b8", - "witnessHash": "6fb7ee5e64f85b100c61767398b303bc973fc65562184317ce6d404b528a00b8", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 317, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9491a77e0972e02c221a3da7e9163b337d77ab6962911543517ca8c9579ebd02", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 2039640, - "script": "76a9146cdd71e3ad091a8605155ab2fb5f86a83eae0d0688ac", - "coinbase": false, - "hash": "9491a77e0972e02c221a3da7e9163b337d77ab6962911543517ca8c9579ebd02", - "index": 0 - }, - "script": "483045022063919108f7ef9735d7be412dceff5b3ae4b06bcecbca1b776ea45c7b32292488022100f40330a202eb23beae2505b44ea5a94e46c9c797e7bebdb2ad7463682e0d7242014104485acb31812cfc3817b6cde014895f634567f1210f890f2b37e281cf07c5ca4bf7d38e821a794a4f3b4380970866b2ad38a36b44ca54d67e1613ce9d6edfd1bc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b48585b1405740016c69e53b040b532418990d75665f883bae454d040a8155ff", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 21976667, - "script": "76a914c207649a157ace830061429c1a8ab690cd4976ed88ac", - "coinbase": false, - "hash": "b48585b1405740016c69e53b040b532418990d75665f883bae454d040a8155ff", - "index": 0 - }, - "script": "483045022046c0ff4d048728ae4e0bf677642e954f80a52376b355da1d581169d046f137fe022100a53ced0ce70ce58cdd7d91e56bd301a5b2d2d887d89fce0010e6b66886d53a79014104557ac878b6b2cc680f5fee1eaf61fbd441b9f6d443a2b1455fe043e59923fa46fb29fa6727c95678bb8a4b3119b84d1e07ecb376622eea8a31d94a3f49f9b494", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b682f5a0d5af57b1823297e9cc16de731f3d894ddd5a93b4e35b68055ab10057", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1779874, - "script": "76a9148d5799bab064b1b630d4bd5b7868f9a4da7f69f588ac", - "coinbase": false, - "hash": "b682f5a0d5af57b1823297e9cc16de731f3d894ddd5a93b4e35b68055ab10057", - "index": 0 - }, - "script": "4730440220496de7fe91785c57ce59323d7733215a5bfde35351a24a031ce7741e98567b570220018d20381b856941c06f62a9ac0d3395c64faf423cd949070bb1f1557ba13849014104058d58519e138eb32ca1c5583c01b2ffc26c1e7da0f1384025596927515695b1ef16d9f5b55f57d2f8b65085fd5e6d9fd21f3a95e08de1d116c1a1aea9d3a5ee", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4de349e8a9166239944f75daf4e8a7c858befb86d6cb4e6035efb220e0a912f", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97452, - "script": "76a914343a15f93a76662094f2cf7a78cf6cbf51604f4388ac", - "coinbase": false, - "hash": "b4de349e8a9166239944f75daf4e8a7c858befb86d6cb4e6035efb220e0a912f", - "index": 2 - }, - "script": "48304502203218db64f670e3bfb50b7c83b37336bf22a6f345fd3c6a61eb9e549383206ab502210099f5f17a2f4c7e816a40e4f2052d2ef604fb21f893b1232d01e40a1a093cbd48014104af65fa515afa44ea55e0e8bd7182fc0a1ad9e45c27394a0b41ec667ffb1154a3488a6b1ac0a6f8e83164b171012bec97687f59abff8e7eaafab839d21687b358", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 25796181, - "script": "76a914f16b586fdea2672b25c1720a1365c7bc4605029388ac" - }, - { - "value": 77452, - "script": "76a9141b437181e8e8eec7716b5c5c00c9e7b76e8c914588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "880b4eda91c08b40ac24dd5a44089a5407f0fabd7ac46a2e527effa7c48bf683", - "witnessHash": "880b4eda91c08b40ac24dd5a44089a5407f0fabd7ac46a2e527effa7c48bf683", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 318, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e0b73d77e8a3e375dc74de675cebbc9dbce08b536810643c284cfec44bbbf5cf", - "index": 93 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 4081595, - "script": "76a9147b14e4f68b5e03ca3cfbda6fced601d4418bbc3c88ac", - "coinbase": false, - "hash": "e0b73d77e8a3e375dc74de675cebbc9dbce08b536810643c284cfec44bbbf5cf", - "index": 93 - }, - "script": "4830450220285f72d6f71f0a49fc6067e1ed98a3feb1eadce5202d5899ad5a47bcbdbb992c022100af3475c22e5c64149fca29d706b705f8ed2480880c43f725920e3400a0cea2c00141049757ee1cb2b553f694581c35f46a7ee7d7c2eb93566d55b14f530d0b90d4785414972c0d2ebbf71b97bc3bd158f1309ad5fdddb4689596ead3604c279365aef1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3db341c76192192c56350abb22e4b039311b1aa92abff213b759aea75020c54d", - "index": 87 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 5298208, - "script": "76a9147b14e4f68b5e03ca3cfbda6fced601d4418bbc3c88ac", - "coinbase": false, - "hash": "3db341c76192192c56350abb22e4b039311b1aa92abff213b759aea75020c54d", - "index": 87 - }, - "script": "493046022100c557d99c61abc75e134daad0b49776f903cc5ffd1a84e4b193bfd57e40041622022100862587ddb17cd127728fe7861aaad854f09a1a828d261fe3a2f1910c79752ae10141049757ee1cb2b553f694581c35f46a7ee7d7c2eb93566d55b14f530d0b90d4785414972c0d2ebbf71b97bc3bd158f1309ad5fdddb4689596ead3604c279365aef1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 39 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4247668, - "script": "76a9147b14e4f68b5e03ca3cfbda6fced601d4418bbc3c88ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 39 - }, - "script": "47304402202abe291b6e6322b7cffd25f88c251df56d9b48db229effa96f23d6faca47125002206290a4e0dbfaefd1e333bb61c3aa0b1640c8fd05a093c82e7965e85d8b50e5540141049757ee1cb2b553f694581c35f46a7ee7d7c2eb93566d55b14f530d0b90d4785414972c0d2ebbf71b97bc3bd158f1309ad5fdddb4689596ead3604c279365aef1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "00ad6c9b7831d6df91d42f3f1ffbf6e535b2eaf20a958d2404441498753d3fb6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97479, - "script": "76a914951130d6105d0b133ed3a5f0fc77f4843777478788ac", - "coinbase": false, - "hash": "00ad6c9b7831d6df91d42f3f1ffbf6e535b2eaf20a958d2404441498753d3fb6", - "index": 1 - }, - "script": "483045022100817f5e28d77dac55d1659e1f342a34918aaf600780ed813e7c759b0bc8aa481502201bcea18f12edae454308597793d25e0c6807675f42071192a68028fed1f47fd40141040e7446e97db57f212d62d9594921b906bdff27248617d903a9019881c647b2258892a2c31d93c258c37e06c3e8efc8fbd1acac113f4656ff8c175dca757ff4e8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 13627471, - "script": "76a914a6d6eaec67e88c7264eadbb6e9d8df7ca9194e9f88ac" - }, - { - "value": 77479, - "script": "76a914b6cbd922e25b38c26fc7546a96c6b045576b0d3088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0788ff04bad74d1175b690fd3355113fda7512f3858d1697fc6c0df85d3fa9ef", - "witnessHash": "0788ff04bad74d1175b690fd3355113fda7512f3858d1697fc6c0df85d3fa9ef", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 319, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5010ed5aea9ce56aeff00b1f3417d5ffd727f0976a6f5554b9670d220fbb0c14", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 1363581, - "script": "76a914f0f2556f0bd4b496558b0c1b24a6d757203d0fb488ac", - "coinbase": false, - "hash": "5010ed5aea9ce56aeff00b1f3417d5ffd727f0976a6f5554b9670d220fbb0c14", - "index": 0 - }, - "script": "4930460221009d21e92ba488769e5d68a355f28a77ed7fd99e020920e5250cc4129bcc0049bc022100eb59e9541fd6c1107b1aff27ee70fecccde516f344e79c31bbf74f8167e60f180141047bc6bdc76baf3faf30899ee8e1d94b996f2c7c66b347140bb987a9b59ad1246f702bbce20e83f2209a2311c0fbb75c2d08d7b3bad679f2940f11ebad34c10593", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "717357bdcc0bf5680ef356eebb5d382f4436268d8903605d53bea0ffd140f2de", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299984, - "value": 1378149, - "script": "76a914f0f2556f0bd4b496558b0c1b24a6d757203d0fb488ac", - "coinbase": false, - "hash": "717357bdcc0bf5680ef356eebb5d382f4436268d8903605d53bea0ffd140f2de", - "index": 0 - }, - "script": "483045022100ef8c43b3a413181a37380d03127281f8fd2de185f4735ac217e23d0fa987d0e9022025cde1a2c09ec7e28a6803a3992382c6f1bc7e4dd2be30967f0afa7b7efca29b0141047bc6bdc76baf3faf30899ee8e1d94b996f2c7c66b347140bb987a9b59ad1246f702bbce20e83f2209a2311c0fbb75c2d08d7b3bad679f2940f11ebad34c10593", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3e67036bad3d11a3a52f47f55b48f74872e7d8bf5b43c43cd4656eca63e82db5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 15000000, - "script": "76a914f0f2556f0bd4b496558b0c1b24a6d757203d0fb488ac", - "coinbase": false, - "hash": "3e67036bad3d11a3a52f47f55b48f74872e7d8bf5b43c43cd4656eca63e82db5", - "index": 0 - }, - "script": "483045022039de192897c1622c14e7ff2db25bf29aa5c23cdfa04d159ac3f72971509e609a022100bf82867dd03e57a2eb839ea967cc857094ec4afedf6220a3c7ace57729f6445d0141047bc6bdc76baf3faf30899ee8e1d94b996f2c7c66b347140bb987a9b59ad1246f702bbce20e83f2209a2311c0fbb75c2d08d7b3bad679f2940f11ebad34c10593", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "27cb45e23f6089a44418f2178f218a8d39edbf660adba936d06fea4e272a5fe6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299967, - "value": 57489, - "script": "76a9140d39da90648609670c976ec5e193e5cb0283309388ac", - "coinbase": false, - "hash": "27cb45e23f6089a44418f2178f218a8d39edbf660adba936d06fea4e272a5fe6", - "index": 1 - }, - "script": "4830450220495aa9da1233247aedd5e125780b28147fa809ad3cec6bc39461c5c3f38ba8000221009f43b69b770e0a8c693c5d4579242d242383363c4e5a2324044470d0a7e7a99e014104c273923b49c4c1ec475f256d323583953bb87aabd9f53b4be86800531da37f9129539d730d7e30ba355bf8c483217dedb09c62cce6ac3d856eec8973b24a35b4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 17741730, - "script": "76a9149713702c6752e9df1fd4a0eeb5c77b043dcfd2fd88ac" - }, - { - "value": 37489, - "script": "76a9149c587ec9bbb39e1aa2f0b81711eef3398ec77fbd88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "febc6fffb6d3b38b99108a6699d4352c4d1f53c4c10642d6ecd8f04f965c6829", - "witnessHash": "febc6fffb6d3b38b99108a6699d4352c4d1f53c4c10642d6ecd8f04f965c6829", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 320, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c362113f692b0eba7372f7035d5a6acaddae4331a692361376039f705a555c8a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299555, - "value": 21561018, - "script": "76a914adbfbacdb05dbe6337d4f02f2e0c25628feef30c88ac", - "coinbase": false, - "hash": "c362113f692b0eba7372f7035d5a6acaddae4331a692361376039f705a555c8a", - "index": 0 - }, - "script": "483045022100e8ba36b886d53f756f137f89b809ab72cebdc43096cdda04fb78fa02b93ddccc0220237e44601cd412c1fdac1f89775562b746876725b704bcd90a95d84667493a49014104646ee14d4b8be440e21e339cef74b547ad0fe0b42d7da28ccbc9037f43c41bc388041f2e1d17813b41cff840be908e4222be8c1daa23974985307af98a87df14", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "25159b1328907ed3b6af0d634990a4709b78f3077bef0f8a704a37e18cef32c4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299740, - "value": 4911458, - "script": "76a914adbfbacdb05dbe6337d4f02f2e0c25628feef30c88ac", - "coinbase": false, - "hash": "25159b1328907ed3b6af0d634990a4709b78f3077bef0f8a704a37e18cef32c4", - "index": 0 - }, - "script": "4830450221009cb6ecf55ec59d72c5380e63438b574cb7bea1d320bf880e6ac49768f296a722022041565b767de1fb5783b56ad07fc73acd9298a01b2305878949c6c98a1441b03f014104646ee14d4b8be440e21e339cef74b547ad0fe0b42d7da28ccbc9037f43c41bc388041f2e1d17813b41cff840be908e4222be8c1daa23974985307af98a87df14", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 26462476, - "script": "76a914ec5e0e225a193b5d37144ba9af939ae64013f3c888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "17451eed93b3bc567c4db08a1914baeaa2dbc83aa62b307013d34b6c1c632c76", - "witnessHash": "17451eed93b3bc567c4db08a1914baeaa2dbc83aa62b307013d34b6c1c632c76", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 321, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b0639afce99dd1448059f8d944226bbbd9eb45f6233607fc0f1b86a685492d97", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 489990000, - "script": "76a9144d761c6be4f714b4c910d13fbfdb7ccd07a146ae88ac", - "coinbase": false, - "hash": "b0639afce99dd1448059f8d944226bbbd9eb45f6233607fc0f1b86a685492d97", - "index": 0 - }, - "script": "483045022048a07602c6de604cff6c17912966c83d187e846b6029464d0957c7c060ab1e10022100953afdeced2b76b561a0a2071f553e4f77f0acc0b70a59f9102754cf55598ef9014104ae0b2caffe0d38224b3349c41ec75093a3f400509263ae32cd87a948d4f05e28aba9c8782be735ae6dc494c05a64bf1d440f89a718f3ddf0bca05dc9c0b3eba7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b82826842ad866f67aa2618b251cbc92a3c0616b02594a412c4e0e2fa1917b21", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 307990000, - "script": "76a9144d761c6be4f714b4c910d13fbfdb7ccd07a146ae88ac", - "coinbase": false, - "hash": "b82826842ad866f67aa2618b251cbc92a3c0616b02594a412c4e0e2fa1917b21", - "index": 0 - }, - "script": "483045022100cb5b906225ec9773291987f83ee54b975e25e1c44a804bb75918e47eebab468102204d55d986508ccd945996bbcf8a6e6c01b594e4d336041416ecedd4e38a0a6a9a014104ae0b2caffe0d38224b3349c41ec75093a3f400509263ae32cd87a948d4f05e28aba9c8782be735ae6dc494c05a64bf1d440f89a718f3ddf0bca05dc9c0b3eba7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 797970000, - "script": "76a914519e84489eb8bf6df05b669f0fb13526877682f488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9e1bdeaea158690c412c02ba636601e7ee97d7b21b5e0b3a08124809d8bd26ad", - "witnessHash": "9e1bdeaea158690c412c02ba636601e7ee97d7b21b5e0b3a08124809d8bd26ad", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 322, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d7bb81eb51e238b2db6957b3331ba28a7bdd1921c9e5ede1ce16555c6a623444", - "index": 88 - }, - "coin": { - "version": 1, - "height": 299780, - "value": 8779, - "script": "76a91488b3f7b7c52c8addd16531322e9839ef8f2ea47288ac", - "coinbase": false, - "hash": "d7bb81eb51e238b2db6957b3331ba28a7bdd1921c9e5ede1ce16555c6a623444", - "index": 88 - }, - "script": "493046022100bf90b8d971f32e0690280c31e597f04bfa0fcf22e4525d3255e25d371ecfaa70022100807b28f9f1790da17e30e2c9365695eafb4fc84d526b8945e29f3faa1b66fa610141043726ad488dfcbc2f677f014acb3074480dfdc01c13f8252f989ed3887e5b72c09268971fc4e0c3eda4e66d9e73931c1fb63bdd347981235ebdc4caa28bcc4571", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f51bcd93c0ef63ab3aaa857fc856b20e350a0dccd5c87d6e7d26eadd9de1510c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3132000, - "script": "76a91488b3f7b7c52c8addd16531322e9839ef8f2ea47288ac", - "coinbase": false, - "hash": "f51bcd93c0ef63ab3aaa857fc856b20e350a0dccd5c87d6e7d26eadd9de1510c", - "index": 0 - }, - "script": "4730440220226ab2be72a3da32868b8e1a7edfd607eb9def31a0c8ab62e0e934c9ae0e2cd4022019b507365a98d1e01f1734d11aaf9bf0e85cf190eb8d6f7eb5f5ad9dedbf24920141043726ad488dfcbc2f677f014acb3074480dfdc01c13f8252f989ed3887e5b72c09268971fc4e0c3eda4e66d9e73931c1fb63bdd347981235ebdc4caa28bcc4571", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3130779, - "script": "76a914ec124728d95ce78f128bf7b29c3121cd1356db6988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "85152e039cdf5e540a8283ae482027796747d9312fae696d5fa2b0fd97f5689a", - "witnessHash": "85152e039cdf5e540a8283ae482027796747d9312fae696d5fa2b0fd97f5689a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 323, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c3f3e3a41493a112c083202dc26d8b6bafe0059387bedd66bebac6ec4d34c2e4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 868061, - "script": "76a9146358c71e7194a7f41565df737556a1384c3503ac88ac", - "coinbase": false, - "hash": "c3f3e3a41493a112c083202dc26d8b6bafe0059387bedd66bebac6ec4d34c2e4", - "index": 0 - }, - "script": "483045022100c642115569b05214d381610314c9d7450c6a5608d0cfd675d31c893e5503663f022003bfae9285d0ca1990167761d762ba389953a1fb3927b59d2e695b771fb6154601210359ec5eab4a5839afd524ec79f29bc75720635de0a9be18f0e01dbaa5c3396473", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7fa0c6f859ddd46c5b10d191a5b121939526c60a17759c87112815b20efe8900", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 7811378, - "script": "76a91440873e11c31cd3e4fb95cca36c2360f7c712ff2188ac", - "coinbase": false, - "hash": "7fa0c6f859ddd46c5b10d191a5b121939526c60a17759c87112815b20efe8900", - "index": 0 - }, - "script": "483045022100ba7546400a1c07fe958f72152c24445e2f776bade7132aa4c45e85d099ff72090220363201140c427d59b2b3a55deb0fa1e1be02fe3498120326488f51c5eb4205f7012102428063244548a37ccc888d148f66af6343775f6f05c2bcc46a8db8a23c857683", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e3c6dd0aea649a72a56cf7c49be08c73085d0af2792e4fd4234a92e6a2d75b40", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 25289099, - "script": "76a9146034bcda63975118f9f2f5f93e8f6a31519287b788ac", - "coinbase": false, - "hash": "e3c6dd0aea649a72a56cf7c49be08c73085d0af2792e4fd4234a92e6a2d75b40", - "index": 0 - }, - "script": "47304402200777d4e4224fb7a3d3ceb63dcb3ebb4974401e55f49b2a89b27dfaa763c10d2902206c31837450eb8bc181d976d9d7ccffe64638dacd71058a313cef561842613672012103eb974d0f3bf503ac33c16b3cc0b7f53f465ef577326e74b95ab94f4d86a205bc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "65284714bf3455116942fea3f24791f9f8e75758486d97d9e3308ff28de2499c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 28990000, - "script": "76a914dec45e657b24c5cb4417bf6b1adbc466677d968d88ac", - "coinbase": false, - "hash": "65284714bf3455116942fea3f24791f9f8e75758486d97d9e3308ff28de2499c", - "index": 0 - }, - "script": "4830450221009d1573fcff439dde84bba2cdc68001f09a7504bc78f2a67b4595fa132affee360220659f780c3788ee0d40eb17f51cc4d21dbb212602000d3ae45f30f6ec6654cfd50121038bce75485d1035cd29e56ae5cedfb2c2bfb44c3037793a622ed231fbddd3f59f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6f456a6ee2c2c7719f09a68f0f05825b73140ada36516242002eaeccfe9b6142", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1079500, - "script": "76a9149bf549bbe4f62b0fa6b299ef152d600543920d0088ac", - "coinbase": false, - "hash": "6f456a6ee2c2c7719f09a68f0f05825b73140ada36516242002eaeccfe9b6142", - "index": 1 - }, - "script": "47304402207e5e7e4c392e0003d5a265493263ffe4ba8a745ec403a12556408f862c31bbfd02202820e07c1375753faf631a1ec014f2fe60a2f9fb5c43c197f7d43a48cf2e57f401210343612c84b58199cf04731e4dbaa1e8b062afbfa449652c7d58ace7bc92e5128f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1018038, - "script": "76a9146034bcda63975118f9f2f5f93e8f6a31519287b788ac" - }, - { - "value": 63000000, - "script": "76a914b645abcb3d27a12352e1efa87e2aaf8699c8d7d288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3c006be96c07917a48cdac11c86d2888bd1c1005f73f9a2c2ca7126e7d5e4dfc", - "witnessHash": "3c006be96c07917a48cdac11c86d2888bd1c1005f73f9a2c2ca7126e7d5e4dfc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 324, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6214996fabe31368e1f839a8518829b268b3ae810306f3e409381f1c0f4af84e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 400000, - "script": "76a91436a799410379a37565064e87156b989b297173b588ac", - "coinbase": false, - "hash": "6214996fabe31368e1f839a8518829b268b3ae810306f3e409381f1c0f4af84e", - "index": 0 - }, - "script": "483045022100f5f1b1dba61b83af9c4c728528745cfc3782a134eda77e231e58b0a3f331fcf502202a5425a50527151e879e37c480586ead23409aaa59c2e32d30a99685d5ecbab80141048bfa915437d51f123656d33b3c99f8507f9ac9422bd0e52f4ffac99463899c786368fe63cd4bf9946cbf05852227dfc90f02693b6fa594a67078c6c130f6faf3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a72d1339d36a589abf306dec83ea24b8f1fd8da784342a298bfcb12a4a864f67", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 100000, - "script": "76a914b41d52a7fc5436f73db8e8b8f2ec4e1f19db7cc888ac", - "coinbase": false, - "hash": "a72d1339d36a589abf306dec83ea24b8f1fd8da784342a298bfcb12a4a864f67", - "index": 0 - }, - "script": "4730440220119f836b003f5a3d613ab4360dab6661ffe54b9dd2f510060679aa338b04000202207da4cd2069a56670edfd784e724e3916760418f8f86121fd7eabe02dcde6a2dc0141045c67c057ecba6f75497abd0841148c6577c76a72d3e3e5f77bdd5eb8accce3e7cb4f0fb3f067126b267d55360e124b47d4119e780d5227dd1869544db5aefbab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d92381d0b527da6f532af74b0fdd596d9dd33446d85218e35ae7b50220186414", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 100000, - "script": "76a91474515db42ae2211b56b573a92206b671cbdeed0988ac", - "coinbase": false, - "hash": "d92381d0b527da6f532af74b0fdd596d9dd33446d85218e35ae7b50220186414", - "index": 0 - }, - "script": "48304502202e760ae6d3e8fedfb361dc4437463558c60d249170681f5fa45f23c631c6c6f402210085b9562ae8672ba13f1902110b3bac154a9a45cabf6dcc656a72a6d5e67a90a00141046b6fe16d3acd7bd8203166c8b4eff37fbb669559b50ba482180ca9893f32ce1de05f17eeb9daefdcf9db861f02ec56cd3b3a49f8b245e026fe9082ecb5c3fce3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "df2650bdfcb4efe5726269148828ac18e2a1990c15f7d01d572252656421e896", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 100000, - "script": "76a9140be4bbd9380c700355ea5b565a4d8724c377cb2888ac", - "coinbase": false, - "hash": "df2650bdfcb4efe5726269148828ac18e2a1990c15f7d01d572252656421e896", - "index": 0 - }, - "script": "483045022100f9f254c4acf52469e6e5dd6cbb40b13cffe4a492bd46a4b2da41a45032a06dcd02202fc94354aa6b433b90221e42fe389204f3cb669885eb253a6f08bdfc80dea84a014104472f4d2674087e7a52ce048f72eb10b4d2780b54cf1480d98f22cd81b3e2b79b941b27e35ad1ad0450cdac455f4852f2b2aadd3ddb9deb9438c189ef97917ac6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "87a653334812248a34d34e7296ebb39adee652fc39edb3ed354d458889b53c12", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 100000, - "script": "76a914b84b265173a01b21b6519b13f1a86eb048aaf3d388ac", - "coinbase": false, - "hash": "87a653334812248a34d34e7296ebb39adee652fc39edb3ed354d458889b53c12", - "index": 0 - }, - "script": "48304502206ebb3f8bc27c4476462160255c2af27ce84f85e8811e4df3174e828842128dfb022100fa7574636584495ae42b329b7936555bf8ba7f4e4ba58085213abaea4a88c7320141047d4c0f32654c1fecc5c1ab21e17ed25dfc844d44d4ea1058add2a349bb52e6b27013dedf0a5b8a6e5a5706471b67725e6b539c07be92c0032b183a4aa3fb076e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "58ca53e93ca2071beeb7cd7d6bc140f866720fe0458e5c4eb31e8b05438179af", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300007, - "value": 100000, - "script": "76a91444b8e0a76bec6c7e9552e2b4403d1fb1c0f9bb5d88ac", - "coinbase": false, - "hash": "58ca53e93ca2071beeb7cd7d6bc140f866720fe0458e5c4eb31e8b05438179af", - "index": 0 - }, - "script": "483045022100af5ba1357065f1fa9a42d67c517d6422b4512d639943b6602abd4ff49e0b17e40220658159a395eec7bbcb9de2656a56ce3884314aa95ca247508de00ea8699b751a01410425d8aa1cbf21896c33af0b7f2980076026a377490862cec906486d061ce0aa242e644f406c5ab14e3099f58cee2a7c7426e01731b65220a58ed490e02797e809", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e2060e69db32b52d106f160ad93af2418160005f2dcad62d44c6f86602eeb68b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300006, - "value": 100000, - "script": "76a914f64a573b1bc6676bc14693e5631ed844e7312c3088ac", - "coinbase": false, - "hash": "e2060e69db32b52d106f160ad93af2418160005f2dcad62d44c6f86602eeb68b", - "index": 0 - }, - "script": "4730440220736a09f2b14b26ca30a68a0aae40160d991c374a758584df505175822441636c02204c2f94e73fc42da1a6c27b83dd2efdb441add790eb1022d75001e9133709f12b014104f7002c538abde32146df44f1912e5e1bafde67a4fa2a687ed00ee4bd156aa96441548a6506d42acc3ed87fa715fd66e7476f71022ccb7deb7615b71e8d8ee8c3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ac9188ce32d00485d917eea2b06e110504974ed4787564065f1c16ca932087b2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300020, - "value": 100000, - "script": "76a914e6af9bc071d56a3a7900c2fcaa7905b4b0243b7c88ac", - "coinbase": false, - "hash": "ac9188ce32d00485d917eea2b06e110504974ed4787564065f1c16ca932087b2", - "index": 0 - }, - "script": "493046022100a8f50303d1cfda3352fd048b9cc97809f02930058c93410237fd30e0cbddf1c302210099836b8ff54290088caeafed666c1c9769b58493ab74848b3341995ad63bfb750141044eb9134563174e4c1bdc6751169ad6f20e526bd7607b3af8ba54e520a23ea2f83fcd862a95fcddad643c095fa10f74aca23e0b52ea5a5972117c1c5fa353f4e9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "591fee2aa983249c11b256be69df5496fd3ea0cd855e28e79566ed0bf89118c5", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137454, - "script": "76a914362352ceeb4593694a1dd6b4c835abe2ccb2bbe388ac", - "coinbase": false, - "hash": "591fee2aa983249c11b256be69df5496fd3ea0cd855e28e79566ed0bf89118c5", - "index": 1 - }, - "script": "473044022055be1dcc83a7a8b2b846df41c1ed98b124131c4881ecff7db3d56402eb818b380220078488f48c4c5d3dc1e5ebd393cdd561984293c0ed86cdbf71fae77e7889ae980141040766d8790b6f411ed66c7c885cc4df5bf8980e3866fc22a59889acd0f22ce494f4f84b45ba0d8c9557fba49760a7259fbc41431d33b813bf8c2364579ac5baf1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1100000, - "script": "76a9140450cad3a3cd648f583e796602be13c6a27adb5e88ac" - }, - { - "value": 97454, - "script": "76a914679840b2cac1ee2a1d63dfad985df1502ca8ca7688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "18322690a2a3c2ea087eb3aaeb5643ce46dee125c6b5a68229d93e316444e881", - "witnessHash": "18322690a2a3c2ea087eb3aaeb5643ce46dee125c6b5a68229d93e316444e881", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 325, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fb20d13745b7b8c310ecac74c2c75fa70062cbdd5681ea5fcbb7cdaf8e599cc9", - "index": 291 - }, - "coin": { - "version": 1, - "height": 299253, - "value": 1040335, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "fb20d13745b7b8c310ecac74c2c75fa70062cbdd5681ea5fcbb7cdaf8e599cc9", - "index": 291 - }, - "script": "473044022020d90119f1f3a991261d2dfe1d3ca728bf817b0a518e3ce33f460f92ec09f1cc0220199f0dac2f909f98fb3d5473b5ae07e2764d1390aee2d2a8c7371fd7c532d39301410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "70f4fecd524ede51bf720c927f381eb96b0d4f1cb87a60f2254137085a28b7bb", - "index": 297 - }, - "coin": { - "version": 1, - "height": 299294, - "value": 934121, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "70f4fecd524ede51bf720c927f381eb96b0d4f1cb87a60f2254137085a28b7bb", - "index": 297 - }, - "script": "483045022057deeaeff073a6be2feb00e6479e75eac8967d7a09c9c39bc28a0d30ea5914500221009ed8f13f420e639393f574ed2635c5876368cd4484d1fd7cf7079a8989f1370901410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5fc9dc90cf50a67db674b46febc999503f261565a6cd74e20caa15556371129a", - "index": 61 - }, - "coin": { - "version": 1, - "height": 299335, - "value": 196087, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "5fc9dc90cf50a67db674b46febc999503f261565a6cd74e20caa15556371129a", - "index": 61 - }, - "script": "483045022100b3cc0ca7430745644c5931d783eb616facdcef26b3e79bb362a7390256135f1e02203005087dcb8cd3581a6bcc75fcfac208429eb578b800bbf3cdc2e23398de849801410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7cc653806a9f27af5d7e492c6fb3085776aca3477447cbeab57c511efba3aae", - "index": 970 - }, - "coin": { - "version": 1, - "height": 299394, - "value": 237626, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "e7cc653806a9f27af5d7e492c6fb3085776aca3477447cbeab57c511efba3aae", - "index": 970 - }, - "script": "493046022100b54c215706ce495081230538782c8c68f4689ecf9ae38da9bc8f2bc235c7a14f022100a2afbbc7423d791d418197d820b751ecdb975723060fc794bf6ed5c31019ba0301410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ab18b68de47fab11c6c2c2fa4953fb2eae3dd7237d6e1e5747acdc332f98fe55", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299486, - "value": 2640864, - "script": "76a914ff1b697b8d1e46de33e71bf88be0ce036db03a1788ac", - "coinbase": false, - "hash": "ab18b68de47fab11c6c2c2fa4953fb2eae3dd7237d6e1e5747acdc332f98fe55", - "index": 1 - }, - "script": "483045022100cc8dd25d1991d0857392822beddb26864ba7848f423213f683f4d97c38e53e910220048e97c2c1e81ed58e3c80e164996f5ceed91aeb4b218a41b189f85c6e5938b0014104e9099dd0e67b2c985c6319dd9fa0cd1aebdae765d8f54a00dc74d0aa1c6442ad1a565d8eef7682e01b63e53b5c711f9b9db0d0338614043c06f4546ee5630f1c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6c0735544555f96608d0ef17a8a6840b0082ba15bcef9be2809fd9eb99796f1e", - "index": 59 - }, - "coin": { - "version": 1, - "height": 299568, - "value": 270686, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "6c0735544555f96608d0ef17a8a6840b0082ba15bcef9be2809fd9eb99796f1e", - "index": 59 - }, - "script": "49304602210096fd618fb0453031a96bb363daece5b08bcad874b444cc055a7c850bb7480323022100e4c9c9542ddd3c76e4125919ccabebfad86f4a5e5ca135b7e14b6128caaee21801410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7391915855f352e34a825160d9025b5a81ab54d71adb9cd04a44bf82f2bae213", - "index": 243 - }, - "coin": { - "version": 1, - "height": 299644, - "value": 314370, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "7391915855f352e34a825160d9025b5a81ab54d71adb9cd04a44bf82f2bae213", - "index": 243 - }, - "script": "483045022100a9cc25c8c1ce102ceb33c8ef75e2288c8d3ef09304f83b5bb9fc63ed9bb1387e0220215fa5e82a20c6c2a605c998ac4d1e069870f3ce70cfe6cfa10c2511ceda4e4601410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ced3e4d04da6b8a1400bda5f848150a862c745784162c7adb730f2d307cc6a1", - "index": 63 - }, - "coin": { - "version": 1, - "height": 299728, - "value": 366424, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "4ced3e4d04da6b8a1400bda5f848150a862c745784162c7adb730f2d307cc6a1", - "index": 63 - }, - "script": "4830450220487639c089452e651a0a4dcb47aa641f4a1c55e39850154fcb593e77089cf970022100cc94c1eb6b3d4803985f96013825f6ee6deb75c0c7caf1fb5de6c17059e7dbf401410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bf9eec8083992f731e17acfc30e4ef372df077e79f7f1d41525ee9a186aeb005", - "index": 60 - }, - "coin": { - "version": 1, - "height": 299811, - "value": 344754, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "bf9eec8083992f731e17acfc30e4ef372df077e79f7f1d41525ee9a186aeb005", - "index": 60 - }, - "script": "4930460221008faa6c776d0dd388e9932d4a473ee6042c6b47448faabe2f65d3688371ca0726022100ecd9b578be2156da11e99b539944681a1ee7d395661c08afc6493cf187a0170101410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7c2bff3103cf50783f689b7b44a5127e9a2069d7b50498cfa8bd5a1bfe263ef2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299814, - "value": 2554274, - "script": "76a914ff1b697b8d1e46de33e71bf88be0ce036db03a1788ac", - "coinbase": false, - "hash": "7c2bff3103cf50783f689b7b44a5127e9a2069d7b50498cfa8bd5a1bfe263ef2", - "index": 1 - }, - "script": "483045022100da8c13aa0b3a5b4c2d0346bbc8aecd15fcc47a03c70acf850b7f168b8890a6f402202ad0338256df73a0bec670b27afc792234ccad9bdb090222630873bf72493dc7014104e9099dd0e67b2c985c6319dd9fa0cd1aebdae765d8f54a00dc74d0aa1c6442ad1a565d8eef7682e01b63e53b5c711f9b9db0d0338614043c06f4546ee5630f1c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "83b27bcc0002f3c09066da06b56e2323681781983daede2bbe4b760b06627765", - "index": 254 - }, - "coin": { - "version": 1, - "height": 299888, - "value": 367051, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "83b27bcc0002f3c09066da06b56e2323681781983daede2bbe4b760b06627765", - "index": 254 - }, - "script": "47304402200dac7623514d99f287ef8ed7437aa21888e4ebcd25cd0c9aa6fc730419867a5902207d99e79b2c2e3f06f1a1facfae11585c94d5b5a785a3aeeb15967a6e5ae08b9501410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c857e3ab46e30be796e241322a4fd1a105935ce359aeca6ce61751ea03588799", - "index": 242 - }, - "coin": { - "version": 1, - "height": 299977, - "value": 390044, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "c857e3ab46e30be796e241322a4fd1a105935ce359aeca6ce61751ea03588799", - "index": 242 - }, - "script": "483045022100b890e8c547f81bc54f112f25a950247cdac8cb84c0bb4e337ae95bcfda90feef0220220f7dafe5a8e39bf66ec081df2243ff12829d2b550fe0badc9ea83b0eb51a5801410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "57d62e51ea08382152699122e27acb029a7e897439127c0dfccd68111e8e653a", - "index": 283 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 698645, - "script": "76a914625c34557e58638ec62ab78f871666beb3eb185e88ac", - "coinbase": false, - "hash": "57d62e51ea08382152699122e27acb029a7e897439127c0dfccd68111e8e653a", - "index": 283 - }, - "script": "47304402202316cba0b14de3699a6e6535a2d183037e749a5df1d3c138308eb8d5adb493f202201e9b755f03fa3b42385cd1d5a0469d3757ad60f81b76e87c4b24a1503ecc3d4e01410424940862533ca94be5a31f7f8baa2f3f729182ae79f04d377ea7f64254e7281d86534cd639d1a7b5e8bf2a8c0e65ccd1d6b09c0e03b559e2c4c568191d1a3e4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5ae75f4e778be63b322bcb902efdfa9efce97b19ccb2ce82a736469f470b3c6f", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 117481, - "script": "76a9140092ee8a84c4d01e8149cdf50d1534da2bbac2c588ac", - "coinbase": false, - "hash": "5ae75f4e778be63b322bcb902efdfa9efce97b19ccb2ce82a736469f470b3c6f", - "index": 2 - }, - "script": "48304502203116b08c153559875bf47e22e2bb07564f417b1f5349ae12707ff8605f5bc68f0221009dc91775f1e99ae0bf3592b481d24d4ff512a089c493b2ba108b23b52b858e51014104bab943e5c235969c85a867ab7d3a12ba6326a36c0f784b201eca57ff2e08c4ceb59e6be2c7dc70a788217f7505925d5620870f38f493bc1d3806636a24d5e315", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10355281, - "script": "76a9149ab99bc7a02741cbd52b034456805e073a4d100988ac" - }, - { - "value": 57481, - "script": "76a914d5bee8e18f6ed3524f582475c65d06c51bb3acc788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "23c6e721f2a244b1c5a6559a625a7f12f9a191e5857df058757e7ffc87562d78", - "witnessHash": "23c6e721f2a244b1c5a6559a625a7f12f9a191e5857df058757e7ffc87562d78", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 326, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8e6854d20591afcdddbd92f7beed660e02902cb7c886144d0940038d60b91c9a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299971, - "value": 9200000, - "script": "76a914aaf9cb8953735456aaa313c31223ed8e94f3301288ac", - "coinbase": false, - "hash": "8e6854d20591afcdddbd92f7beed660e02902cb7c886144d0940038d60b91c9a", - "index": 0 - }, - "script": "473044022017abc5bd0afb3f4e0d8960ce4f08ac45ad9e455f27bf4ba347ac2b091e8a16900220057183a9b9ff0651729f5ffbebed0f90ef40d07209880c1306ed2f89cc117a27014104351c9d99e72197af558cc778ea0c1e18f1b9da1c0850d4dc65cfcfc219c3db0daf064fc04e0b8d732eefcd22737d9409fca5db0f864ee541bcde2ea9178d774c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8aee1b8d9cc1c7abe78bc0117128ed663fcc4d1d4e30c3e773412f0d8bbc204a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300009, - "value": 35000000, - "script": "76a91408dc3fa93c67a2a3fc42906baceabc642598efca88ac", - "coinbase": false, - "hash": "8aee1b8d9cc1c7abe78bc0117128ed663fcc4d1d4e30c3e773412f0d8bbc204a", - "index": 0 - }, - "script": "47304402207f491b95b20f899994931aa85ef599947cc1d486a59ead6968e6842ec0c4d2e2022053a0637ee999d52b3a8f33ff6f88c9f16c709bf251f8e70c84f90fe702874c60014104742250dc14dc4802ad5ed6ee6d38a1f9b271402f789d50064a79c7a9fad2e7c75887eb0164a053e3b9fe316789cc7232fd949aefcb3ffbf7a238efb490905da5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1006178, - "script": "76a9140949587cf96e610d1a6460a1eb754f51e61c0e0f88ac" - }, - { - "value": 43183822, - "script": "76a914e54195422a7e8a421c6846a659e3df2f2928831f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6d4feefbf33c9a156d3723cccb0348a5cc83738ca42c5b181f5cd7243bc16669", - "witnessHash": "6d4feefbf33c9a156d3723cccb0348a5cc83738ca42c5b181f5cd7243bc16669", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 327, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4677fac8a795cf2e7290394a4d0014db98f011618288ce07454f20beaeb762f2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299401, - "value": 38442, - "script": "76a91465a8896864c41c300383193af8ee87a92218d61088ac", - "coinbase": false, - "hash": "4677fac8a795cf2e7290394a4d0014db98f011618288ce07454f20beaeb762f2", - "index": 1 - }, - "script": "483045022100fe13b7021751609e0a9c803997227406a76219a0b8117164638db5d81cf4321d02205ae09d8fd25d2ce39ed94e4e39549271f7d1da8211fa23fbc10cd05c2bad8c38014104e900ccf1b6e9438a7ca119ef8746cb7700ac8b1327bd54960c55d4194004c82d024e2999419d4347d2d93ca4a448f62efb32b6398b71052f2f13a0426181180c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8274f0ea38414211079ccee0d7bc9554fc6464c26d4654ae96a7073008dc3927", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299628, - "value": 4084588, - "script": "76a91465a8896864c41c300383193af8ee87a92218d61088ac", - "coinbase": false, - "hash": "8274f0ea38414211079ccee0d7bc9554fc6464c26d4654ae96a7073008dc3927", - "index": 1 - }, - "script": "47304402200298bf47223e7af6156f337b7811c463f599cc3429deffc011444effc6f393ca02204eb97d32f1e4a3095a0ece74274ec6b9e975515b403b9dd1e211d1e806a81b06014104e900ccf1b6e9438a7ca119ef8746cb7700ac8b1327bd54960c55d4194004c82d024e2999419d4347d2d93ca4a448f62efb32b6398b71052f2f13a0426181180c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3744658, - "script": "76a914d87b292dc896a49f1327dda47cb57c352ab85fa888ac" - }, - { - "value": 368372, - "script": "76a91465a8896864c41c300383193af8ee87a92218d61088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8a8db69dcd53e22943ac919770ebbc9ec9eeeed176089782e6ff1ed3fe5fa430", - "witnessHash": "8a8db69dcd53e22943ac919770ebbc9ec9eeeed176089782e6ff1ed3fe5fa430", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 328, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "aeb98b32310a8e879ef7081fed5b391e08fc1c319ac28e9bfd209deda4478e0a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299059, - "value": 1282668, - "script": "76a9147f220ad447ff38d977fb31339db3efb01730354488ac", - "coinbase": false, - "hash": "aeb98b32310a8e879ef7081fed5b391e08fc1c319ac28e9bfd209deda4478e0a", - "index": 1 - }, - "script": "4830450221009510e92c4e939e1ba8d46da5968afeba1dd70a508e814e7e4a348a594033fd0c0220580bd3ab4e88bd631d44261d2964028fdfe42df91344de90023dcf8fc6a32973014104948c824742555e934694d5b0f36f46384ca73c813250e0a44a9a399278d7ffe50f9f50984e3284417eb5f232a8a131b05b4998279199723cb71deba9b465ebad", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d21a08aadb02f53c7f5a46bcd6efeba7b9f7767492846fea1979a028d7856821", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299943, - "value": 1357094, - "script": "76a9147f220ad447ff38d977fb31339db3efb01730354488ac", - "coinbase": false, - "hash": "d21a08aadb02f53c7f5a46bcd6efeba7b9f7767492846fea1979a028d7856821", - "index": 1 - }, - "script": "4730440220091881d281280021ea27ad7571d2e6f0cf883898f6f56003290a49f76b9e701402202b69552c233f80df10dd9d911f6da1fedb1c2f08df187dfda2599c1e91d3045a014104948c824742555e934694d5b0f36f46384ca73c813250e0a44a9a399278d7ffe50f9f50984e3284417eb5f232a8a131b05b4998279199723cb71deba9b465ebad", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2625000, - "script": "76a914ae49671b2e9bf0d4b386d795bd3439429005152788ac" - }, - { - "value": 4762, - "script": "76a9147f220ad447ff38d977fb31339db3efb01730354488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "584f54c06dfe09a0ffb73e200ad0f572d1a93643ca813289eef909001d4716af", - "witnessHash": "584f54c06dfe09a0ffb73e200ad0f572d1a93643ca813289eef909001d4716af", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 329, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ab86495893de25f12b366cbab865102a7cbfe5d36651460f5e93fd0576f9b07f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299867, - "value": 763491, - "script": "76a914276b8286bec99a5d3eb816a642b707863146e92288ac", - "coinbase": false, - "hash": "ab86495893de25f12b366cbab865102a7cbfe5d36651460f5e93fd0576f9b07f", - "index": 1 - }, - "script": "483045022100dc07b6d01d35b65a56f3ab8a2178c65f3102f66509eccccdd4912781c71957ff02206f0ab0b31cb2ccc334f75405036c1e70853bb23009fe59f688d09616dd791fb5014104f9d7c2fbf2dea622bf3646b9d72e2426ebaf44c1540a910057d8a876513e9fb97e18aef7e126d06059edf3228edd59340668874b7f42f8c55ff4ed1e73154084", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9ec7b4be12347f7011affe470984fc2722da3bd52fa891b63da0d581ae20d423", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299973, - "value": 15100900, - "script": "76a914882f57ee66da7d4cc4b73e17128d6b03c9b167f288ac", - "coinbase": false, - "hash": "9ec7b4be12347f7011affe470984fc2722da3bd52fa891b63da0d581ae20d423", - "index": 0 - }, - "script": "47304402201783cef4cd6c427bb9a666ec011307b0d556f0a7dd7204fa17ad5c4aad4366c302207f5ad7c0b2e309236ba1ffce584a72322f2b227e19f962972cfc7a75c232e66b014104799d750a5b0ba0890a916e0ad03577ebb45fd4777725a8db03b4473b3027813eb567c5ace4f798b0e711c02e734f889a5063193256bfaa05bd8cdf3217308a41", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3500000, - "script": "76a9142519eb53a0997bb49791ab162ed71320a807ba4a88ac" - }, - { - "value": 12354391, - "script": "76a914f178b09265c555390e17e2b600db7f442ad921ce88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ba5cbb56c839a9ad5a32b4b84c88e0fa633bad202e9818c4ae84819f24794d39", - "witnessHash": "ba5cbb56c839a9ad5a32b4b84c88e0fa633bad202e9818c4ae84819f24794d39", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 330, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9d7ec7d355947d189a48eaafc7b6c1644a568bc3057d06abe52e3275721b4834", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299552, - "value": 15214, - "script": "76a914ec416d96ae71148c7f810f68f763facf6e6e93be88ac", - "coinbase": false, - "hash": "9d7ec7d355947d189a48eaafc7b6c1644a568bc3057d06abe52e3275721b4834", - "index": 1 - }, - "script": "4830450220079ae850ee067d4cab4d3b3c4f75ff6bee495aa153494aca4670e82b38ace93b022100cfccec5bdd9c6b9479c8c4adad0e27e54c5172db929746ab085a54399d4d51030141048cd2dac46ecf98e24eb7324d0df7ccf81f2f8e4f846c6b44d4dd689533ac2e964bc639e973d00b94ab53cddde05ac19eb5cd89585a100a5e769f281449121340", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "68a5bf33c4b487d2015ee78e8a9591204c682a144f093b03b7139fdc9339e211", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 26400000, - "script": "76a914ec416d96ae71148c7f810f68f763facf6e6e93be88ac", - "coinbase": false, - "hash": "68a5bf33c4b487d2015ee78e8a9591204c682a144f093b03b7139fdc9339e211", - "index": 0 - }, - "script": "47304402200852ec495ae6d8708ea188824d4af3cdcd1e10ba6b3c33d1dd3662bfe520099a0220440ac03f7cdf51a1920a54e10321a3146da5551e47e3b5ad3fa09c35d4ad00690141048cd2dac46ecf98e24eb7324d0df7ccf81f2f8e4f846c6b44d4dd689533ac2e964bc639e973d00b94ab53cddde05ac19eb5cd89585a100a5e769f281449121340", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 26000000, - "script": "76a9143b9925c88d396ded7fc0bbc61e86741a327a3b6688ac" - }, - { - "value": 405214, - "script": "76a914ec416d96ae71148c7f810f68f763facf6e6e93be88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "989235c2baeec7d6d722bc70d958188542bda7a37c29befe52957f1504323abf", - "witnessHash": "989235c2baeec7d6d722bc70d958188542bda7a37c29befe52957f1504323abf", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 331, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9d03ad907596f589027d0afad3f8cdb8027aa48a2cff7920fafb6903eecd0f18", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac", - "coinbase": false, - "hash": "9d03ad907596f589027d0afad3f8cdb8027aa48a2cff7920fafb6903eecd0f18", - "index": 1 - }, - "script": "47304402202bb3074c6ce092c1ba97a9f0f7a8519e8f50bcd2ae5fb7d5633a67f2fec1d43e022065e437ed20a943a00ce42e5f31dc7de5a44bfe567beac335349bd3ecb90bf3e3014104d81a0388c3592ae3aaa9d7387a46dd582660328b4da4227dc8dc4408bbec2503988b46cd87b714356953e4e024f1085801e85aaf0c753e6f1e512d0aab6852e4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "32944e1ecdd15da983e067b55b77e2ff26580c187cf45cd9fd6b4e9924061fab", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 15324085, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac", - "coinbase": false, - "hash": "32944e1ecdd15da983e067b55b77e2ff26580c187cf45cd9fd6b4e9924061fab", - "index": 1 - }, - "script": "4830450220536ccb265e9b2ad582a481d1a6d7148ae131327acf0bc8c165238707d8d75034022100fcc9efac24ffc2c8a45211d695f39b5a095ff0a6cda1165f6414b645098839b4014104d81a0388c3592ae3aaa9d7387a46dd582660328b4da4227dc8dc4408bbec2503988b46cd87b714356953e4e024f1085801e85aaf0c753e6f1e512d0aab6852e4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1900000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac" - }, - { - "value": 13424085, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8003055945c0aca41256dee4d4d1a3dfc81c3045de7ca5501bd7194b5ee819a0", - "witnessHash": "8003055945c0aca41256dee4d4d1a3dfc81c3045de7ca5501bd7194b5ee819a0", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 332, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "989235c2baeec7d6d722bc70d958188542bda7a37c29befe52957f1504323abf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1900000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "989235c2baeec7d6d722bc70d958188542bda7a37c29befe52957f1504323abf", - "index": 0 - }, - "script": "483045022100fb247d6be38ba475559629d0296d5f14539915a4e95cc9bbc68d9e49ee2fd220022071df53a34433fe5879713f6a0709b4d5ad3bbcc725c1de11502c50ed39d97920012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac" - }, - { - "value": 1880000, - "script": "76a914788de3e892875e1652dfdf9bf9677b84086e415388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e7d66fdfbba852d9e466874bd65dc1fc4d03b089f4ac840453d4a33717f7b187", - "witnessHash": "e7d66fdfbba852d9e466874bd65dc1fc4d03b089f4ac840453d4a33717f7b187", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 333, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8003055945c0aca41256dee4d4d1a3dfc81c3045de7ca5501bd7194b5ee819a0", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10000, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac", - "coinbase": false, - "hash": "8003055945c0aca41256dee4d4d1a3dfc81c3045de7ca5501bd7194b5ee819a0", - "index": 0 - }, - "script": "473044022004a5ffcc0aceb743ab0dc64c6ce55b91edeac476f091ecdc24c6f8e4f71a15e502205d06be9cc6022d4a9715519379b8877e839ec8e626237b6d054e5a5ef32aad91014104d81a0388c3592ae3aaa9d7387a46dd582660328b4da4227dc8dc4408bbec2503988b46cd87b714356953e4e024f1085801e85aaf0c753e6f1e512d0aab6852e4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "989235c2baeec7d6d722bc70d958188542bda7a37c29befe52957f1504323abf", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 13424085, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac", - "coinbase": false, - "hash": "989235c2baeec7d6d722bc70d958188542bda7a37c29befe52957f1504323abf", - "index": 1 - }, - "script": "4730440220350e12659e90e2f1cb565a5b09d21ac70467896395a19e60aec98fc74a424c9402201acb6df254cf86c9e7924397995766f1f95e0ae4780951c0b7cc3ca457290ddf014104d81a0388c3592ae3aaa9d7387a46dd582660328b4da4227dc8dc4408bbec2503988b46cd87b714356953e4e024f1085801e85aaf0c753e6f1e512d0aab6852e4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2800000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 10624085, - "script": "76a914e7088ee4a157a6581943cb12bcb0e31f05d143d788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8ea590a1988f8d5b5ed225f7c560008b5c56b13cee38d555535f4b7d35199a0e", - "witnessHash": "8ea590a1988f8d5b5ed225f7c560008b5c56b13cee38d555535f4b7d35199a0e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 334, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5ac88d05e3a067087eeefe5ddb8e6d0f040ece61add8e3c93477ed2370eb8cbe", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac", - "coinbase": false, - "hash": "5ac88d05e3a067087eeefe5ddb8e6d0f040ece61add8e3c93477ed2370eb8cbe", - "index": 1 - }, - "script": "483045022100d6b85a3aaaa105648645f340d21db2eeb248582d94332c6876c5bb5ddb74529402201b751f9486ea023875cf6878a5541d85bf1527811a7ca2a6fc5c6ac92159b67f01410441dc748e05cbefabe0cd59ba2d5b9c6b3729c4b87e0a3eea23ea77fd8e0fb883614ce2f11ac217e18acfdbe99f737b6695e650de4b15158fa09bc64ad9292279", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f2a53ce3272a32f1fba101d82594268ffb4e6a544db62181e40d173a416ff57b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 11994761, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac", - "coinbase": false, - "hash": "f2a53ce3272a32f1fba101d82594268ffb4e6a544db62181e40d173a416ff57b", - "index": 1 - }, - "script": "47304402207615f7d004dffec9ec8d97f193e48a57f63b44edbaaab1674a624751e31bf2dc02200e6ecc269e9e0611a1fc9daf782b79c4b22df9f6a1966b676a1330b73ada1d1901410441dc748e05cbefabe0cd59ba2d5b9c6b3729c4b87e0a3eea23ea77fd8e0fb883614ce2f11ac217e18acfdbe99f737b6695e650de4b15158fa09bc64ad9292279", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1800000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 10194761, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "00efdb5b8e7f75df11663a0430768ffb544445ecfac958ffb795c80391a488cc", - "witnessHash": "00efdb5b8e7f75df11663a0430768ffb544445ecfac958ffb795c80391a488cc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 335, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8ea590a1988f8d5b5ed225f7c560008b5c56b13cee38d555535f4b7d35199a0e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1800000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac", - "coinbase": false, - "hash": "8ea590a1988f8d5b5ed225f7c560008b5c56b13cee38d555535f4b7d35199a0e", - "index": 0 - }, - "script": "4730440220050ef153147a57f0254c359718e8eebafa918e7deae91ac5d7de727e3052c5990220473fb5bfba88481ef947b1192e602220b9628db18732f16b8d1f556863bf1af80121037bedeab7fcb8f05bc5fca2bb43525bd7af9f125035149ab4f48843db0ba37c8f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac" - }, - { - "value": 1780000, - "script": "76a91485c926cc9a4519a5789412dc8e5bbca5f0d1b86988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "435dfdf9e23a06507a4d194c17349c25b1391c877015e15a542cd9feffc8e29b", - "witnessHash": "435dfdf9e23a06507a4d194c17349c25b1391c877015e15a542cd9feffc8e29b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 336, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fd9b95ac1165837085be53dfa336496e631e7e669c980727fdb0079b8895d267", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 10000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "fd9b95ac1165837085be53dfa336496e631e7e669c980727fdb0079b8895d267", - "index": 1 - }, - "script": "483045022008f106812253d92eafc2600556737b76a10a41cfcf8683497a0877d41086b0c5022100c755aedf6cf0aee31a89cef557472214837d4b9291e39d2fae8c8feb826f5ee50141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "062011727c388f1bc4bbcf6929972a2880a796ca1e04b956768a0b54e4927a98", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 11419415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "062011727c388f1bc4bbcf6929972a2880a796ca1e04b956768a0b54e4927a98", - "index": 1 - }, - "script": "47304402202cfe9f1bc1673ddeffbcf3ef91388c357b6dc1c27c50e0d7bc4b707b4c1581970220182ff9a5d99298da2b57f1f039192c526c938f5e9a5233f5c3ea8af9bd9a51470141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1200000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 10219415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c9f2540ff319f2d9a1db6f4c4e1c84422d745ca70e63e1b9b91d506cfc37e029", - "witnessHash": "c9f2540ff319f2d9a1db6f4c4e1c84422d745ca70e63e1b9b91d506cfc37e029", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 337, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "435dfdf9e23a06507a4d194c17349c25b1391c877015e15a542cd9feffc8e29b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1200000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "435dfdf9e23a06507a4d194c17349c25b1391c877015e15a542cd9feffc8e29b", - "index": 0 - }, - "script": "483045022100a2206c98b436b3bc92625ea234177d0e8e34dac7344379be410c1bee2cbb3c8502201b918373bb602860cedd766483aaedc37a465c1e9d4158a4feeb5b97b3e9e0970121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1190000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e80e1449bb89bc0fe336a396dd66d714de72f225b0885bae7f15b09073d88939", - "witnessHash": "e80e1449bb89bc0fe336a396dd66d714de72f225b0885bae7f15b09073d88939", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 338, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f0f86a5d97c9350177ab23b45113158ad9bafb534314d2de09c4d0b9273e59df", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1390000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac", - "coinbase": false, - "hash": "f0f86a5d97c9350177ab23b45113158ad9bafb534314d2de09c4d0b9273e59df", - "index": 0 - }, - "script": "47304402200732b7faffab7fd670c8f5c5d5e4a989dec08ad6b11eac8d975ef113ad7526ef022071791ea8c00bc02f1dc20c6f22f2cb3a5f792b28fa34d57bb814db6d050fbebe01410457fbf746bf1d48c6350a52e4c264a7e505056c2aadef3fa6d03c3e2abeaf704273500cf186513da95cbc2c6cbb6e55ab5942da7d5ac281319076bb8c1b0d27e5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "18b9ad64d86426f29937683ddc09aaba442cb188b636e53d778862520eb63cd6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1365000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac", - "coinbase": false, - "hash": "18b9ad64d86426f29937683ddc09aaba442cb188b636e53d778862520eb63cd6", - "index": 1 - }, - "script": "483045022066838e113d92e3d0302ef38e657f8f49c7b2cb9739fc00b62046368ca5aa6a25022100ffcb0ec236effe2f1ecc3605c18f4c2bf312184abb4ae3c4bfcd37d9478964c001410457fbf746bf1d48c6350a52e4c264a7e505056c2aadef3fa6d03c3e2abeaf704273500cf186513da95cbc2c6cbb6e55ab5942da7d5ac281319076bb8c1b0d27e5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1600000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac" - }, - { - "value": 1145000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "16e438d29d4a19e0df2f656564950c785884a1806b2ccc037ebea0b2ec4d792e", - "witnessHash": "16e438d29d4a19e0df2f656564950c785884a1806b2ccc037ebea0b2ec4d792e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 339, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e80e1449bb89bc0fe336a396dd66d714de72f225b0885bae7f15b09073d88939", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1600000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "e80e1449bb89bc0fe336a396dd66d714de72f225b0885bae7f15b09073d88939", - "index": 0 - }, - "script": "483045022100b60d9cac407f0c8da97e8da33c0e0de81db903cabb15217c76f862633925722802204e862d4dfc9e718467fdcdd088df976cf8283016b80e52f3b19237e4b30b4bbd012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac" - }, - { - "value": 1580000, - "script": "76a9146dbc2a75b5bbee0abf61ef22ea1a0cf88c16853688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3bb4ae8053139f15015583720f578d0c9e75c294e797413cc61229e34fcb6102", - "witnessHash": "3bb4ae8053139f15015583720f578d0c9e75c294e797413cc61229e34fcb6102", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 340, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "555585470ee4e89de9afc109292ec1c5e764e79b08cac4138b4b63b7c79f4cdc", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299947, - "value": 59000, - "script": "76a914d5f71f487783c928cbfb46af44c509fc7df7e5b888ac", - "coinbase": false, - "hash": "555585470ee4e89de9afc109292ec1c5e764e79b08cac4138b4b63b7c79f4cdc", - "index": 1 - }, - "script": "483045022100b3226addd9a613e43cd13388d0299b53737ab8fa4b3ccc876a2e7798e413b8ac02205dd5f7433fdb32b70840e1f3c6f3f9617e9fcdbd99135e8f286c92078332fc7f01410478598fbe66f132b595d9ed0f56a5a118a9fd35d3799fbb69541f0cb8b9ffc125477ed5db9458409ae6a27756bc721aa250ba9a013224780a7c53bca058156bf4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dfa3986babe54b50d013bca88c939e4554d70a774af729acb9e733f3cde1a966", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1282000, - "script": "76a914d5f71f487783c928cbfb46af44c509fc7df7e5b888ac", - "coinbase": false, - "hash": "dfa3986babe54b50d013bca88c939e4554d70a774af729acb9e733f3cde1a966", - "index": 1 - }, - "script": "47304402202ea8987cd5d7c039297e494e8ef4c44a6102422e8ac9a9ae39336434eab5a7ef02203bb144ee668d79f2117f1c22a1ecb0e11182baa71aebde9607787bb86a1945ec01410478598fbe66f132b595d9ed0f56a5a118a9fd35d3799fbb69541f0cb8b9ffc125477ed5db9458409ae6a27756bc721aa250ba9a013224780a7c53bca058156bf4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1101000, - "script": "76a9148d87e436738ebb0b5f037a75e548052652a200c388ac" - }, - { - "value": 230000, - "script": "76a914d5f71f487783c928cbfb46af44c509fc7df7e5b888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "32eab198a046b5b962c72434716e5ab2c5afd2822ac0e40279126a760912718b", - "witnessHash": "32eab198a046b5b962c72434716e5ab2c5afd2822ac0e40279126a760912718b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 341, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "984533f60f4560e140aeba1b6659a452513bb2ddcb158736440db33273ff1a72", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 44847133, - "script": "76a91429aaca32588cd43202ed342a763096772fefd30a88ac", - "coinbase": false, - "hash": "984533f60f4560e140aeba1b6659a452513bb2ddcb158736440db33273ff1a72", - "index": 1 - }, - "script": "49304602210093c030641147fa34675ad25e8a3788f0efb9c5b08a59eb726c0b8759467929ff022100dc0827951650731cad1a9816656c80445ed88952eebd0e76c599074cdaf9f6490141040f467849138c6a3e1be63412a8094d61e7591e4b37fc93b60a0ae1d358331ac31bddf8129d2d6be5388391a1252904ebcdf1802392e08b9e091a84a3f28495b9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "578b60e4bb6afeef4bc5b2275a1f67040112c23e9fb4c18acc59e0babfc9e954", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299990, - "value": 37308905, - "script": "76a9146d7d043253c42ea699000834dceb696694ecf59f88ac", - "coinbase": false, - "hash": "578b60e4bb6afeef4bc5b2275a1f67040112c23e9fb4c18acc59e0babfc9e954", - "index": 0 - }, - "script": "473044022025d7bb851dc8b5a19644fa9965745c83fb2eb6e5ea0b1b88eb62bce3b4404b290220223d3ad0453931ab08bc215fa5770b7d43de170627d09a1b72f72df2d839dbe80141043a8bba361c9400d4824b40b70c9cee516e3e0f0ab733b84e9911db887976af1f9880939ee56723fad891aa8974a3fb06fce2786a2389edb4183767654dfc2cdb", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000418, - "script": "76a914f70e7ddcfdadd44cf1d587b1bb5a2c7a17266f9488ac" - }, - { - "value": 81145620, - "script": "76a9142f42ae0851858fe57ce39af112e0d0f3a515f29a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "825c4ccbdd0dc9085d210f643411fa67a166e0a924a6f6d21c01ee39a747155c", - "witnessHash": "825c4ccbdd0dc9085d210f643411fa67a166e0a924a6f6d21c01ee39a747155c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 342, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4ed8cce5ba494ea83e34c68865a11602aa66fe6a30a0fa1917486d725bca9545", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299685, - "value": 223976, - "script": "76a914dfd2acab035e374597c763dbe28ffa67e9f68cb088ac", - "coinbase": false, - "hash": "4ed8cce5ba494ea83e34c68865a11602aa66fe6a30a0fa1917486d725bca9545", - "index": 0 - }, - "script": "473044022031d72ac52521c65983b8d0363c93b2e775ef199211cc6996658070a810dd09d1022023b1aeee08286357b58f00b49e722266e045e06b6233308527aeba68bff57b94014104eeeca10c76731eea33e3b66a0fdc175e1c07ee5030c48fb433f0db215fdc40d768e7e9ccf8b15ccfd9d9ae632601e0aaf6cb1874cb4f9b79973d2e0bd4846280", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "61971c4f010dff3bc0c52308f5aeeff0a86bc5705c8351144ff7cc01b24fa20f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 277021, - "value": 46624, - "script": "76a914dfd2acab035e374597c763dbe28ffa67e9f68cb088ac", - "coinbase": false, - "hash": "61971c4f010dff3bc0c52308f5aeeff0a86bc5705c8351144ff7cc01b24fa20f", - "index": 1 - }, - "script": "493046022100fe220c6cfbb30619d08a589160f3510c610dc625eae0843500500bb28ce8358802210083c2c6a1c1525cafd8089c4ef997039f505f4bdf6d93f9fd99b49ccbfc7f78e8014104eeeca10c76731eea33e3b66a0fdc175e1c07ee5030c48fb433f0db215fdc40d768e7e9ccf8b15ccfd9d9ae632601e0aaf6cb1874cb4f9b79973d2e0bd4846280", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 160600, - "script": "76a914dfd2acab035e374597c763dbe28ffa67e9f68cb088ac" - }, - { - "value": 100000, - "script": "76a9141c6456c8eb57fcd32690c3697fed23ebfc1c6c6988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e710ac6ab29d72f7a1b39668209ffa3d0d7b8c762438e36b45c55584edda5b21", - "witnessHash": "e710ac6ab29d72f7a1b39668209ffa3d0d7b8c762438e36b45c55584edda5b21", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 343, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "70642294ddaee6ce78677d8325f88a56e3cf4a7ed0b8f2b9ee6e1139b8c0c6eb", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1925000, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac", - "coinbase": false, - "hash": "70642294ddaee6ce78677d8325f88a56e3cf4a7ed0b8f2b9ee6e1139b8c0c6eb", - "index": 1 - }, - "script": "4830450220103732d43a7d9d44fba63f358c2ae89986bd43ad677b260c40fda1975b37fad4022100960dce025a7d65482f2e4ee6e9b42c10115e367c7aba4c0550dd5b53d00215b3014104bfa71464809d4495b30e075ae06ed258066979d4e4073fa82b3e92a51c7a10d9f31872401ed1fb5117c5299d55de005c56d32b4366b4f8c06f08f0219701dddc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "21001edc42acca2538e636de370f9da88005ff059216697e0ef8dfe01993fec3", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 9479359, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac", - "coinbase": false, - "hash": "21001edc42acca2538e636de370f9da88005ff059216697e0ef8dfe01993fec3", - "index": 1 - }, - "script": "483045022024be844ddf2de6d7fa736fa7bfcbe2b9035237a49ca7f94f6f5ff0ca5beec2d0022100b704104ec19039744ea49f0488493239279279ba8f6585ee13c5b020a2a066ec014104bfa71464809d4495b30e075ae06ed258066979d4e4073fa82b3e92a51c7a10d9f31872401ed1fb5117c5299d55de005c56d32b4366b4f8c06f08f0219701dddc", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2200000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac" - }, - { - "value": 9194359, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0cc0dd6f9fd72222dffd2f46a89b7a87dcbc4d54313e6e7d6f7bf45d41302602", - "witnessHash": "0cc0dd6f9fd72222dffd2f46a89b7a87dcbc4d54313e6e7d6f7bf45d41302602", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 344, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8ee442b5e11e9579aef98b4539e48b74d2b613680d74f6ce2d4bb4d14e0c134b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299901, - "value": 106125, - "script": "76a91425d28f254c906d6997d767e697037ce4e6884daa88ac", - "coinbase": false, - "hash": "8ee442b5e11e9579aef98b4539e48b74d2b613680d74f6ce2d4bb4d14e0c134b", - "index": 1 - }, - "script": "47304402204f138d980ec97c6b7ad8f9b67ac7b5be485eddc84f4349512137ffd08b91b22902207c6b3cdaf324cd5ea49a59c3bec02921102d26abbd933a5d837e4c5b6ac05d7e014104238064b6d29720d9271a868a98c2e78c0e0a12698570abd51e3b27b5dcac61e34f8514b496bccb004876d79fcbff2f470d8e6a69ea0fb5e8cbfee06567e5cad6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "350ef3ff10c3ef3e1956a99bb3c6022f2cf9a6c22b9ef938e5f3f4475741a1e2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2034942, - "script": "76a91425d28f254c906d6997d767e697037ce4e6884daa88ac", - "coinbase": false, - "hash": "350ef3ff10c3ef3e1956a99bb3c6022f2cf9a6c22b9ef938e5f3f4475741a1e2", - "index": 1 - }, - "script": "493046022100b1052e8c398d502206d806c8a52ac87ff01a5873d64facdb5f297869b3d4bfcf022100f63408fe27dc3f45388462d475f2aa71a359bb4d58cbf1b56fc665e925490fee014104238064b6d29720d9271a868a98c2e78c0e0a12698570abd51e3b27b5dcac61e34f8514b496bccb004876d79fcbff2f470d8e6a69ea0fb5e8cbfee06567e5cad6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2024700, - "script": "76a9142d5d0c7d4932b6cbf1e7d5849c60e9dc14d4c23488ac" - }, - { - "value": 106367, - "script": "76a91425d28f254c906d6997d767e697037ce4e6884daa88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "78e29ab14d9175dd90f61807c3635762a31e273b9c82faa5da09f057d2ae0697", - "witnessHash": "78e29ab14d9175dd90f61807c3635762a31e273b9c82faa5da09f057d2ae0697", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 345, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bc9b12fb59bd69157a5fc7f09a0e740980a9660fef77abadcda30c7ad5365dfe", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1890000, - "script": "76a914663a6875c51af9695719ebb20870dc727a71a3e088ac", - "coinbase": false, - "hash": "bc9b12fb59bd69157a5fc7f09a0e740980a9660fef77abadcda30c7ad5365dfe", - "index": 1 - }, - "script": "48304502202130cadddb7a1b16633235eb4ea06fa668d28e4f3bc1ac96f2618977a2273b9a022100f3cf7a7114455b6eddb0aabdb5c1ff54822679379fb97e3128a7abfd806b679c014104ee46bd5ddf14716980a35b1e55f14f22e44ba6c0f30391f0ab3659ba2469b9caed98785d724434d3a62cfd744419556225a2d493e38c2397044b178c88561b2e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "013fa3e6c652b889a0a7dc41cc736a0d8e068f0d688caf653658076101c7f70c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2290000, - "script": "76a914663a6875c51af9695719ebb20870dc727a71a3e088ac", - "coinbase": false, - "hash": "013fa3e6c652b889a0a7dc41cc736a0d8e068f0d688caf653658076101c7f70c", - "index": 0 - }, - "script": "483045022100b65f51ed9c001e714ad58cff136a3e5a7136ed9d318bf0135f7f3310ad23392202204f60174a6e3e402f16f874ce03865dc18def7f758e830e2f1a70f8795e8b4846014104ee46bd5ddf14716980a35b1e55f14f22e44ba6c0f30391f0ab3659ba2469b9caed98785d724434d3a62cfd744419556225a2d493e38c2397044b178c88561b2e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 3170000, - "script": "76a914663a6875c51af9695719ebb20870dc727a71a3e088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "65dd34850904472517e837679b4be6f340473a0820a0a2eb6f594c564abdd3a3", - "witnessHash": "65dd34850904472517e837679b4be6f340473a0820a0a2eb6f594c564abdd3a3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 346, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "78e29ab14d9175dd90f61807c3635762a31e273b9c82faa5da09f057d2ae0697", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1000000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac", - "coinbase": false, - "hash": "78e29ab14d9175dd90f61807c3635762a31e273b9c82faa5da09f057d2ae0697", - "index": 0 - }, - "script": "48304502210093bc381b215938f3866cf4698495e56c4b44e072ebee30a4c23d25f481fc13630220047baa362eb581866c12f8a1f28f71d4b5d0b98b3b39cb9bf54d346c3bc5cdcc0121037bedeab7fcb8f05bc5fca2bb43525bd7af9f125035149ab4f48843db0ba37c8f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "447dde86787541b4a3e28030f86b0a3c838d53954a258804316fe02da93ddf1d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2880000, - "script": "76a91459ab87f2518ef5916684a0c13b30d234e20ca35d88ac", - "coinbase": false, - "hash": "447dde86787541b4a3e28030f86b0a3c838d53954a258804316fe02da93ddf1d", - "index": 0 - }, - "script": "473044022008f90a741feed969f1241f0005a3efe9761ccc3ca92d3cf24737eca848fc7962022000c30cd672506ab997cb0a9263031cabcfe1d94528ab675bea981018f9817648012102192c62062f08ebbf621a1dd691e70ea2404759abc1d0192a33b35a39bbeca87a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1750000, - "script": "76a914663a6875c51af9695719ebb20870dc727a71a3e088ac" - }, - { - "value": 2120000, - "script": "76a914788de3e892875e1652dfdf9bf9677b84086e415388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "87104d1434372519911baeba177c7c2b09ae03e15e87dbf564cd45224d87ed18", - "witnessHash": "87104d1434372519911baeba177c7c2b09ae03e15e87dbf564cd45224d87ed18", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 347, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "15d11f96abfd62aa71ec219ddaa085d33a32cf9b30e68a0ed20c504127ec51ae", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 30497, - "script": "76a9141d03bd9811980f07dc4c0561abf1dcfc18880d6088ac", - "coinbase": false, - "hash": "15d11f96abfd62aa71ec219ddaa085d33a32cf9b30e68a0ed20c504127ec51ae", - "index": 1 - }, - "script": "483045022040f5f4e7870100675f6caf1c4fd806dae299d3f73b4890468eae7c282b61b3440221009bb21e42894bdce7d6f520a9af793bea6d0fba39f300ea31935ae2b81695352a01410492c48d00c45f8ee6bd6f068c9fe677d1f8a95b672ad303840052e3d759303666789b47f19af568d36327cb861f1964d2bb2de6e7a486857b6a03f773e4590311", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0b82b25627cecc831c8a48e19437fefcc81b18ebe8252e105f96c4f1b03d720c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5821159, - "script": "76a9141d03bd9811980f07dc4c0561abf1dcfc18880d6088ac", - "coinbase": false, - "hash": "0b82b25627cecc831c8a48e19437fefcc81b18ebe8252e105f96c4f1b03d720c", - "index": 1 - }, - "script": "483045022100e6eb0db2a0fe13f2768f4118ea492d3bef1922d1543d3c3183fc3fd03054ad790220486a5d2eee6117811dfb0cd5a27b5f482c2540499ae00eb6d3b9c8890fbf037b01410492c48d00c45f8ee6bd6f068c9fe677d1f8a95b672ad303840052e3d759303666789b47f19af568d36327cb861f1964d2bb2de6e7a486857b6a03f773e4590311", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5727124, - "script": "76a91430ad7012f49eac76f9b459908035df4f1354368988ac" - }, - { - "value": 114532, - "script": "76a9141d03bd9811980f07dc4c0561abf1dcfc18880d6088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fd4c9dd188826a910e711c29fc828874d43259c750bf4843755919ccd671869f", - "witnessHash": "fd4c9dd188826a910e711c29fc828874d43259c750bf4843755919ccd671869f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 348, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "cd44dc832d1933eb8c058868b56c179aaccc983ce0ab64694adcd53f5f2401ad", - "index": 1 - }, - "coin": { - "version": 1, - "height": 293687, - "value": 500978265, - "script": "76a914b055fa8527e1651d6cfa3b154331c84ca5e97a1488ac", - "coinbase": false, - "hash": "cd44dc832d1933eb8c058868b56c179aaccc983ce0ab64694adcd53f5f2401ad", - "index": 1 - }, - "script": "483045022052a44e4cadea6faafb260f955b30e155eb8a41d7cfa3628f82a3f38ceed81b6c0221008cacbcd84485bd6be25b5471f5da50f7abe20182a3af43f9bf90e6d1c8647d620141049b0fe551be02a4f98526674fce207219ca1ed6d25553c6c9e12f366d51827fd308dd8944b640300b516ce2ec49c9e292cfcda10504c4b75a2f193b7331438e3d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8636598f12c9058104ab43290a4666b29cca930c4de1536362c5dc7e6e34ad73", - "index": 1 - }, - "coin": { - "version": 1, - "height": 295007, - "value": 450377855, - "script": "76a914b055fa8527e1651d6cfa3b154331c84ca5e97a1488ac", - "coinbase": false, - "hash": "8636598f12c9058104ab43290a4666b29cca930c4de1536362c5dc7e6e34ad73", - "index": 1 - }, - "script": "4930460221009c424fd716b6a413305098fccc5dc75eed9989f046f31bfcfcc89723e7ae0243022100e9f573e644225d44fe29d2b53b2b7405b46737d08980c94eade7a14f6947c65b0141049b0fe551be02a4f98526674fce207219ca1ed6d25553c6c9e12f366d51827fd308dd8944b640300b516ce2ec49c9e292cfcda10504c4b75a2f193b7331438e3d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 700000000, - "script": "76a91425aab4820d9a8105ae883c2c572017d40010058b88ac" - }, - { - "value": 251346120, - "script": "76a914b055fa8527e1651d6cfa3b154331c84ca5e97a1488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "feef7fba09508788f791118e03108cddd98c576e42d31f939a15f46e2eda0a4e", - "witnessHash": "feef7fba09508788f791118e03108cddd98c576e42d31f939a15f46e2eda0a4e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 349, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c798041952c0d3df581e26cb1510b829739f27acbbb1413f8de67baf250ab9d7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299458, - "value": 2372630, - "script": "76a914d149eb15033a2de80a26810c5a727ef99da4aa8d88ac", - "coinbase": false, - "hash": "c798041952c0d3df581e26cb1510b829739f27acbbb1413f8de67baf250ab9d7", - "index": 1 - }, - "script": "483045022011b996bad1246f7543b234159a06d3211dbbaf418d8edf35e5048995d59470460221008700d164f99cfc877afe425d6c296fcdc765a34c0b53e8d564f7dd04be5d56ce0141048d17b4764944bd55a653ffdee13791d5cf98abafe2b962b1cab88cdfb070478d765701725f6f59812955bdf3f1fae1c6c050df12110b0ac38d6e48025b0dfbbb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3d02127f0ca932e6211426d3409aa83f8a37a444dd06dab6c0c1e019430df612", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299885, - "value": 3913421, - "script": "76a914d149eb15033a2de80a26810c5a727ef99da4aa8d88ac", - "coinbase": false, - "hash": "3d02127f0ca932e6211426d3409aa83f8a37a444dd06dab6c0c1e019430df612", - "index": 1 - }, - "script": "493046022100fe0d39e53817f2feb788518ff5a6dae2cc9283a46d30d514b8ecc3d72e5548540221009aa7d8fda8a210011ed3df3d3d1fe13b4c9069b2e1da6be052f3a66a335abf4b0141048d17b4764944bd55a653ffdee13791d5cf98abafe2b962b1cab88cdfb070478d765701725f6f59812955bdf3f1fae1c6c050df12110b0ac38d6e48025b0dfbbb", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4405480, - "script": "76a914fb487a0229c7fb48c07a8ade1b726f7e3f6af1fd88ac" - }, - { - "value": 1870571, - "script": "76a914d149eb15033a2de80a26810c5a727ef99da4aa8d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7c4423c6df15e115cafedc6cf63b45f8e8d56d4cf555645d4c21549fe0f9ca0a", - "witnessHash": "7c4423c6df15e115cafedc6cf63b45f8e8d56d4cf555645d4c21549fe0f9ca0a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 350, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a1a2d04e521f8258426f6cd6e88ccbcf651897c37d69f3f165b8c4ad27bf0abb", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2310000, - "script": "76a914142420c21e7adb50575ed5bd393291cd980214ee88ac", - "coinbase": false, - "hash": "a1a2d04e521f8258426f6cd6e88ccbcf651897c37d69f3f165b8c4ad27bf0abb", - "index": 1 - }, - "script": "4830450221008805af6c1be5877d4fb3709e3959de3aaa3a12910bf5343ab281d9c78c78281b02204f02c119df6e18680a6b1a614e992bb14de24cbce9f31b662aecbecb55c055f901410425f1454decf72f35ee8385df1cd1b28e50de9ad0e34722ef04e3d0983d92792d538f2a9a44ed825318a80edaa5be3ac43428677628f4311be178b773835ce644", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "68c7745b301193ec369b509b61b896da727ec28b93fb62e2777f153f27f4c867", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 15040892, - "script": "76a914142420c21e7adb50575ed5bd393291cd980214ee88ac", - "coinbase": false, - "hash": "68c7745b301193ec369b509b61b896da727ec28b93fb62e2777f153f27f4c867", - "index": 1 - }, - "script": "4930460221009c5071f3cf0f0d252e642ec9cd409fbeff37c0a14ffeaa249a0c691be871e88a02210096ce70167849ea283015d9d654fcdad12099fb43d26b6262e48880d8d9b1b75601410425f1454decf72f35ee8385df1cd1b28e50de9ad0e34722ef04e3d0983d92792d538f2a9a44ed825318a80edaa5be3ac43428677628f4311be178b773835ce644", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2700000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac" - }, - { - "value": 14640892, - "script": "76a914142420c21e7adb50575ed5bd393291cd980214ee88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "df9848e42c5b882950224a4c6a31ecd09deee4065bfc725242fe53ed8bd1554f", - "witnessHash": "df9848e42c5b882950224a4c6a31ecd09deee4065bfc725242fe53ed8bd1554f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 351, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "7c4423c6df15e115cafedc6cf63b45f8e8d56d4cf555645d4c21549fe0f9ca0a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2700000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "7c4423c6df15e115cafedc6cf63b45f8e8d56d4cf555645d4c21549fe0f9ca0a", - "index": 0 - }, - "script": "47304402206e3c7476b701e2e0f78e46ff4a95373a57a4817d39b0a9f1826845b11537c0f502203ff0a0cfb47256f8c549f7a0aba3fd417d6f12312d2a468aa4d60087ff101ce1012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "382ba4026d766eadf5afada18e93e622319b63f184d74b823bd2e6358947cf1a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2580000, - "script": "76a914fb2cc2d580e8db8440810e9f4ba58ea8f86b59a188ac", - "coinbase": false, - "hash": "382ba4026d766eadf5afada18e93e622319b63f184d74b823bd2e6358947cf1a", - "index": 0 - }, - "script": "473044022076a3bb5645bde405e36edc5b5a09941fd48a26039a2f771c01d03dc99a4508ad022002ac9f682d5bea5e63c1e24ef87f27edbdf42a8e2ba55487227cb15342e6adea012102bcca29223dd34858f5ca1e2c6513258455d6763e42a113c2ac46216fa9224dd1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 545000, - "script": "76a9140cc7a4cb0d42a97ad29cfc0a49f955d78bd0362388ac" - }, - { - "value": 4725000, - "script": "76a914142420c21e7adb50575ed5bd393291cd980214ee88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "95c0b1bd9a0e759dec2c00acc231715928c90720156e2af91ddb1d2ed0bfc68f", - "witnessHash": "95c0b1bd9a0e759dec2c00acc231715928c90720156e2af91ddb1d2ed0bfc68f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 352, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f5c38397a8fbe3ef1baa463c09dc323ce59edeb55a44a960666afe8d545d359d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac", - "coinbase": false, - "hash": "f5c38397a8fbe3ef1baa463c09dc323ce59edeb55a44a960666afe8d545d359d", - "index": 0 - }, - "script": "4830450220719589e2e7a4a37ff799be818ddd07b71560931f49d28da857e9aa46af57bd12022100ba2779f51dcd0f80f37238c4747255b77cc33612d47c8150ded39bb4b3d34d7e0141048372c61c205da3b5d1535fb2cfc18830af5f2ed8d06356657d514b47ee7b08bbe9265438708cef0c13738c52ae607c9e2cb6076697b7cea63b9e69dd1e98dd97", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8003ee0a631f4abe5cdb8fd672d7bcedabe991d73307fba4ef33bdd3a8eb4d44", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 7113757, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac", - "coinbase": false, - "hash": "8003ee0a631f4abe5cdb8fd672d7bcedabe991d73307fba4ef33bdd3a8eb4d44", - "index": 1 - }, - "script": "4930460221009c904d19e20e60433267539ed15922b80c66957765e4750068cf0b86d759d265022100bc501af1abe6d7dcb432689f62332e5296d99767196498a2f61515ce1f781fc70141048372c61c205da3b5d1535fb2cfc18830af5f2ed8d06356657d514b47ee7b08bbe9265438708cef0c13738c52ae607c9e2cb6076697b7cea63b9e69dd1e98dd97", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2400000, - "script": "76a914626ebedca70103f5c1e06ed5904f0bc478a263df88ac" - }, - { - "value": 4713757, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "55c373d567149b856ef6210399f80f8b898bc928ba22f671971ae893685c3f23", - "witnessHash": "55c373d567149b856ef6210399f80f8b898bc928ba22f671971ae893685c3f23", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 353, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "36542389072b94bcd06872cdab7753ebeb1410a11d219c142aa7d680f6f80f97", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 10000, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac", - "coinbase": false, - "hash": "36542389072b94bcd06872cdab7753ebeb1410a11d219c142aa7d680f6f80f97", - "index": 0 - }, - "script": "493046022100a97416ac1ee0952279c5dafce0bc4fa71ffddb7c1bfbe69016e4b05b4bab780d022100d9939de05ed991aef03aa7932c77dd452c090dc4a994068ca5659bcf85cde6660141042652b0002273ced6b6093720e54ce282f75d8680fd871185ecd5156a2b1cf3139c708e16595fccb6f4bf99d4f76a05a7ebc656f95b8485a3172ebe127c6ce0b1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ab271ef7b06a9d29283d88a39c90f798f72e99d0d123ebab60fd4435803e568c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 11302996, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac", - "coinbase": false, - "hash": "ab271ef7b06a9d29283d88a39c90f798f72e99d0d123ebab60fd4435803e568c", - "index": 1 - }, - "script": "483045022044f90fdce9504d35c5c17fc24f5a6fd2b5b97210ea2ce457ef1933b28be7325b022100ac1b212ee80b965a03a8d5a2acfc0621c682a014c9272bd6b1d78d6bf82006490141042652b0002273ced6b6093720e54ce282f75d8680fd871185ecd5156a2b1cf3139c708e16595fccb6f4bf99d4f76a05a7ebc656f95b8485a3172ebe127c6ce0b1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2500000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 8802996, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a13c23660c9a94ea98309d70824b64e915ec99346907057e0f9c31cf876c9852", - "witnessHash": "a13c23660c9a94ea98309d70824b64e915ec99346907057e0f9c31cf876c9852", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 354, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "55c373d567149b856ef6210399f80f8b898bc928ba22f671971ae893685c3f23", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2500000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac", - "coinbase": false, - "hash": "55c373d567149b856ef6210399f80f8b898bc928ba22f671971ae893685c3f23", - "index": 0 - }, - "script": "483045022100fad0cdc88299dee35ab6884fd162749b04edf8a990b7dbaeb759ed890cc14fb302203d79aba2bcb84cd89e44ee8788a6ca2e7fd5ac40abd6ad5c3256401672d115c40121037bedeab7fcb8f05bc5fca2bb43525bd7af9f125035149ab4f48843db0ba37c8f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac" - }, - { - "value": 2480000, - "script": "76a91417add6531a3e51bb5e5510f18b8933575d0e038788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "93be8b240da7c42645df9d13ecbb35affafc7c1c09e6d2db8a933fbee9df6161", - "witnessHash": "93be8b240da7c42645df9d13ecbb35affafc7c1c09e6d2db8a933fbee9df6161", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 355, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a13c23660c9a94ea98309d70824b64e915ec99346907057e0f9c31cf876c9852", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10000, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac", - "coinbase": false, - "hash": "a13c23660c9a94ea98309d70824b64e915ec99346907057e0f9c31cf876c9852", - "index": 0 - }, - "script": "48304502202279b59df61b8890e914ea97c98cd46c95cfffa45866c45dab4ebc49357001cd0221009521124c0919cdcb4e37114d619ad720d3f75f9e589b546d782d43b1e69b73cb0141042652b0002273ced6b6093720e54ce282f75d8680fd871185ecd5156a2b1cf3139c708e16595fccb6f4bf99d4f76a05a7ebc656f95b8485a3172ebe127c6ce0b1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "55c373d567149b856ef6210399f80f8b898bc928ba22f671971ae893685c3f23", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8802996, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac", - "coinbase": false, - "hash": "55c373d567149b856ef6210399f80f8b898bc928ba22f671971ae893685c3f23", - "index": 1 - }, - "script": "48304502203aaa8ac4967921ce8aa9931a6e76322a650e74460a9bdb608b62bccfd34c3dc6022100e1b47c60d74a76ed61ac301d9b537c7670815f6fdd13fe654bdfb92c7c5b16dd0141042652b0002273ced6b6093720e54ce282f75d8680fd871185ecd5156a2b1cf3139c708e16595fccb6f4bf99d4f76a05a7ebc656f95b8485a3172ebe127c6ce0b1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2600000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 6202996, - "script": "76a9148a35624b46bb58cfd2ef7e6cd16ba577e00b510588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "833134f7294b463140285526461b962c366316c594dbdad156eb1e8506f90b48", - "witnessHash": "833134f7294b463140285526461b962c366316c594dbdad156eb1e8506f90b48", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 356, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fb9491cf4bcaa5418f932a61c09e6f458792ccec8c3abc5a461f877ccbb8f151", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2275000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac", - "coinbase": false, - "hash": "fb9491cf4bcaa5418f932a61c09e6f458792ccec8c3abc5a461f877ccbb8f151", - "index": 0 - }, - "script": "48304502210088ba54976fe0d1ca3a7f01920ce045ee68d9420296ade097c74d7d74c54b246f0220539a86a13f5bf76ab6cbcd7c11f1590746b939f57c566836bd53361adaf177e301410408e0b2378aa23e30a4de4774fdf540f6a72449c99d29ace5a07ef04537dbf29504b7c4c4d5f82a0f949a7f039e386d68a3f1d04da7c86988311ae7ac824c9cb7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2d8cf172eb3381ccc74a5e123ad9e8ab8b862cb93f07297e4f92fe9909b5142d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 3324641, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac", - "coinbase": false, - "hash": "2d8cf172eb3381ccc74a5e123ad9e8ab8b862cb93f07297e4f92fe9909b5142d", - "index": 1 - }, - "script": "493046022100bb558599fb3bd907a9dc751a1ac762b52922b4a141bf8514922ecee874f7b043022100bb759c70f3c42e1dc6d65b44b4b076ff669cd969ee1b0fbf6d862053fdc150c501410408e0b2378aa23e30a4de4774fdf540f6a72449c99d29ace5a07ef04537dbf29504b7c4c4d5f82a0f949a7f039e386d68a3f1d04da7c86988311ae7ac824c9cb7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1700000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac" - }, - { - "value": 3889641, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1d2cb3f7f458b1f18ad55f9c7a0729bdf215a9f85145156cf587a0ed1438cc2e", - "witnessHash": "1d2cb3f7f458b1f18ad55f9c7a0729bdf215a9f85145156cf587a0ed1438cc2e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 357, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "51e7604fd144fc3bb244e4909c939d9cafe83826a5517b3c5e549192dfe1a369", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1750000, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac", - "coinbase": false, - "hash": "51e7604fd144fc3bb244e4909c939d9cafe83826a5517b3c5e549192dfe1a369", - "index": 1 - }, - "script": "493046022100a4c52630633f4b6560212e73285ffe9805d9766eff9591639107da60ed0ea66002210092e4340df3e421bf696b94571bcbf1d74e0e3055d0c0eaf16eed7d35d09a7f1201410441dc748e05cbefabe0cd59ba2d5b9c6b3729c4b87e0a3eea23ea77fd8e0fb883614ce2f11ac217e18acfdbe99f737b6695e650de4b15158fa09bc64ad9292279", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "351a6dfa48a1b644bbdc040bdaf561a10ae7d9503f135129bf11a018f57c5869", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2840000, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac", - "coinbase": false, - "hash": "351a6dfa48a1b644bbdc040bdaf561a10ae7d9503f135129bf11a018f57c5869", - "index": 1 - }, - "script": "483045022100e883da79bb2ebdbc0b0ec3d7fe9f5384fdb63e3396edfef20dcfbd6630e29aa90220575362b14651a97c1758677f55d8b50641c39c1cea24bf66e034868b64a6b39d01410441dc748e05cbefabe0cd59ba2d5b9c6b3729c4b87e0a3eea23ea77fd8e0fb883614ce2f11ac217e18acfdbe99f737b6695e650de4b15158fa09bc64ad9292279", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2000000, - "script": "76a914626ebedca70103f5c1e06ed5904f0bc478a263df88ac" - }, - { - "value": 2580000, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "adf5e5bf0eeedf5551e16d95c3f4785acad5792557fdaa0fd225adec44ad8122", - "witnessHash": "adf5e5bf0eeedf5551e16d95c3f4785acad5792557fdaa0fd225adec44ad8122", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 358, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1d2cb3f7f458b1f18ad55f9c7a0729bdf215a9f85145156cf587a0ed1438cc2e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2000000, - "script": "76a914626ebedca70103f5c1e06ed5904f0bc478a263df88ac", - "coinbase": false, - "hash": "1d2cb3f7f458b1f18ad55f9c7a0729bdf215a9f85145156cf587a0ed1438cc2e", - "index": 0 - }, - "script": "47304402202d575780d2bbb9e8c454c4ed3ec18dfb05553e2bc8ab331564374babd45e3e93022027cfc5ee48130e81458947daf8678ed4602a28b6580ec5f715ac78cc2776a40d012103cba05903e33c1522407602b64d91ad92d7bc33df9cd74d5a97288d5379296128", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a914d899ad9130ec791c28461149e334623e0836183988ac" - }, - { - "value": 1980000, - "script": "76a91438bb181091ee71cc4a0259dc2fb43dc01622d71888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b42069b3eda4453f2ff2fb7b5332705475a3a79c951a17359bc3f4448e7fa820", - "witnessHash": "b42069b3eda4453f2ff2fb7b5332705475a3a79c951a17359bc3f4448e7fa820", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 359, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c9f2540ff319f2d9a1db6f4c4e1c84422d745ca70e63e1b9b91d506cfc37e029", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1190000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "c9f2540ff319f2d9a1db6f4c4e1c84422d745ca70e63e1b9b91d506cfc37e029", - "index": 0 - }, - "script": "493046022100f2b67565d58a3c25b7136f96f45ba3259b51d6863dbad988655cbb7bc5f36af0022100d604d40005ec50bef96fedb89f5d1accec1f3dadcb2bdbd4b1c32200b3b67caf0141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "435dfdf9e23a06507a4d194c17349c25b1391c877015e15a542cd9feffc8e29b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10219415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "435dfdf9e23a06507a4d194c17349c25b1391c877015e15a542cd9feffc8e29b", - "index": 1 - }, - "script": "493046022100bdcf48fa6e454ade21a9bffe5d821ef8a781b21f65e381f06b562a706964f51202210083b740848381873dc252dfb8a8f6b26cd8bdc93438e60e218301afa93eeaa1900141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1900000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 9499415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "915a0f1efa6b8054ef09c803fb2434be6892c7619f547c3d85b1e1b88cbebf07", - "witnessHash": "915a0f1efa6b8054ef09c803fb2434be6892c7619f547c3d85b1e1b88cbebf07", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 360, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b42069b3eda4453f2ff2fb7b5332705475a3a79c951a17359bc3f4448e7fa820", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1900000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "b42069b3eda4453f2ff2fb7b5332705475a3a79c951a17359bc3f4448e7fa820", - "index": 0 - }, - "script": "4730440220660c51564d439957218ce05d9e8d66e0ead606058fb06e792abb49a402c984e2022076dcbe35116f0377319d28de0fd7008ced2a56a9e2e12f4ed19b0df5a48a9c090121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1890000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "97d80dea23b1bccd743730d1fbe1190eba92ddd1cd5658bb93fa6a64834963e1", - "witnessHash": "97d80dea23b1bccd743730d1fbe1190eba92ddd1cd5658bb93fa6a64834963e1", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 361, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "915a0f1efa6b8054ef09c803fb2434be6892c7619f547c3d85b1e1b88cbebf07", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1890000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "915a0f1efa6b8054ef09c803fb2434be6892c7619f547c3d85b1e1b88cbebf07", - "index": 0 - }, - "script": "473044022071aee46c910ce368d9a7e3a91309779caa73a502d994eca4738863c57eaee32a022068ebb1d9a871d294b624bbab39b671e1f47549d0e567c290369603fc450aa9890141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b42069b3eda4453f2ff2fb7b5332705475a3a79c951a17359bc3f4448e7fa820", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9499415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "b42069b3eda4453f2ff2fb7b5332705475a3a79c951a17359bc3f4448e7fa820", - "index": 1 - }, - "script": "48304502203df2c0d1b3d8adad2ab98e9a03fa4dfb99f85a470e50c43048c7c52a87d96838022100c318f05ee0c6c9ca6d9d8d5d98f71e399e78682d4f1c79ef1a5187511b1d24690141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1400000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac" - }, - { - "value": 9979415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "508d709f7fdb8790c8e10af5da34be0e780aa00f060686db93d43060c0819ae4", - "witnessHash": "508d709f7fdb8790c8e10af5da34be0e780aa00f060686db93d43060c0819ae4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 362, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "97d80dea23b1bccd743730d1fbe1190eba92ddd1cd5658bb93fa6a64834963e1", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1400000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac", - "coinbase": false, - "hash": "97d80dea23b1bccd743730d1fbe1190eba92ddd1cd5658bb93fa6a64834963e1", - "index": 0 - }, - "script": "483045022100a9683a9b43a1e74c6e25699e11fdc304d5e0099dc0e412707fae6dff611d2603022051f6260601f8e56effbbd5625c2417799637c7308d372e2431d216c2e3f3b989012103afd34045d7080e5f3d8fc0efab187951caed4b06571c7cc617d01d9abe8b36b5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1380000, - "script": "76a914cdd6cbd410b70ecbca00b02d0f962b710a7fdec488ac" - }, - { - "value": 10000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2517ad0a4bfd32413c80f3a43ee8c08d173385716ebb28e4a5a50fa43703ad84", - "witnessHash": "2517ad0a4bfd32413c80f3a43ee8c08d173385716ebb28e4a5a50fa43703ad84", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 363, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "97d80dea23b1bccd743730d1fbe1190eba92ddd1cd5658bb93fa6a64834963e1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9979415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac", - "coinbase": false, - "hash": "97d80dea23b1bccd743730d1fbe1190eba92ddd1cd5658bb93fa6a64834963e1", - "index": 1 - }, - "script": "49304602210086ee3c24f9712047496dab411cba1b3e3ce107e76c37a0993ee18fa79eb423c3022100c44238be79950b2338a3cd148a8ffba118617c6357944eade28c02dc61d4f55f0141046c429a46e64e9c2a83bd5eb1f4a03b6aa5264583de09ee413c8f881fc35654ae1d0c4593b7b7f915db01b3801d75a7b4d9ebf27ef6c95ca0b42d1c43e15cd6cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1100000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac" - }, - { - "value": 8869415, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "506e2b29df148a9973359da069af459649ca9a943a6a27e082ff11b8a77e9d94", - "witnessHash": "506e2b29df148a9973359da069af459649ca9a943a6a27e082ff11b8a77e9d94", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 364, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2517ad0a4bfd32413c80f3a43ee8c08d173385716ebb28e4a5a50fa43703ad84", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1100000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac", - "coinbase": false, - "hash": "2517ad0a4bfd32413c80f3a43ee8c08d173385716ebb28e4a5a50fa43703ad84", - "index": 0 - }, - "script": "483045022100ef429380380d6ce9e895842399b524997f3ad17eb0165429b94ac66f2438e08002201e732ac3474d9f34f8d2d0050bacf102dfee2f3e2752ff20038ae77a2c336d4f012103c78b7a24d207c3cdf4411fa2f7c36e2816471c17fa0a6bd46d4296d11fa060c9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "42f328d2697615acff34271c78b4975ff2622f489c3ec1d307871b5fa6c57329", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1480000, - "script": "76a91485c926cc9a4519a5789412dc8e5bbca5f0d1b86988ac", - "coinbase": false, - "hash": "42f328d2697615acff34271c78b4975ff2622f489c3ec1d307871b5fa6c57329", - "index": 0 - }, - "script": "47304402204a2b6d841d2c69985acb5b799e65cd3f1ec171c0409ce3c13a5a4e6b14cf615f02204bbfa143ae08d42e420161aebfc70d7c1899a766bf8bfddc93747396ab0f391c012103aa10fa80220846c1f20094fca57c8a007f66446ba0cad96c85992b3855ba1943", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1030000, - "script": "76a914732466063d4c511272443863045059c74105c6e188ac" - }, - { - "value": 1540000, - "script": "76a9142506b48887f593fa5a9b7afc1a822077526ef99b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a1a01b1ff38b7c51dad7098bfa2169ad34d0447ad762a279b356ee014b230e3a", - "witnessHash": "a1a01b1ff38b7c51dad7098bfa2169ad34d0447ad762a279b356ee014b230e3a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 365, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e862e0a210512df55fd162b9684fde7480c419a821618a952f03e5d9a3003130", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299715, - "value": 37314, - "script": "76a914c630e9bff9c5975f7301902e4e1651adf46c5dba88ac", - "coinbase": false, - "hash": "e862e0a210512df55fd162b9684fde7480c419a821618a952f03e5d9a3003130", - "index": 0 - }, - "script": "4730440220269409199c9c0c1b88b44538a14062d71371ef1b785841c335259b2f384ae83502203ffaff2f7712d6890e298ea8f8ad0e49f122726d464e91cf7501477d4c3910e001410494a8d0b11ffa943bc6174e5b093f1c687da25028b5592709488c9b1230a061d40be4e35204b3e44ed2ba5fad30c8ed8318867c3eb21b6ed51857bbb796296321", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d14f79143cee2b6933f16479a1c587d397c78ebd2b0fcee22c48e38444ada004", - "index": 42 - }, - "coin": { - "version": 1, - "height": 299820, - "value": 141676, - "script": "76a914761c6d6b984bc30510d167dee3d5196adf8a7ec488ac", - "coinbase": false, - "hash": "d14f79143cee2b6933f16479a1c587d397c78ebd2b0fcee22c48e38444ada004", - "index": 42 - }, - "script": "483045022100f74ab83b3f6775340a313477384c3fdfbf97e013300a774e40de649ceeeef0b30220589b69e757c02a84632ccf815536a4424b7dd8d415dd4b5f9e1a0e5849a6918c014104ba1f19dae5a2a36eafe79672ec744e4cc9ee24e01dd9d6996c700d36a7811803b34d827b74c9e0822c2181e130c046e2e94a4f932d280a7724910755567c2da9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "df58e5a3e57346e854d3b82a35f4e974c8ac02b85289dc996833829d573d1942", - "index": 52 - }, - "coin": { - "version": 1, - "height": 299987, - "value": 733132, - "script": "76a914761c6d6b984bc30510d167dee3d5196adf8a7ec488ac", - "coinbase": false, - "hash": "df58e5a3e57346e854d3b82a35f4e974c8ac02b85289dc996833829d573d1942", - "index": 52 - }, - "script": "483045022100955d6c30c709d37ee309d38492f1c86a0386d8003cb25a215617c321205c75540220146b1fa5a35a6f14b9c97c2e74abfa5a0a87fdb05d624b79da0c4f6f9dc17de4014104ba1f19dae5a2a36eafe79672ec744e4cc9ee24e01dd9d6996c700d36a7811803b34d827b74c9e0822c2181e130c046e2e94a4f932d280a7724910755567c2da9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 900000, - "script": "76a914bb81a1c6b7c1a1d09cd25b9abc2954b0aeba4f6388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c6056bcf8432602e0d612bd720bdf106932c833f7113b20f7a0cbbaf3c5539c4", - "witnessHash": "c6056bcf8432602e0d612bd720bdf106932c833f7113b20f7a0cbbaf3c5539c4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 366, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2c1250c35428df72c8080e0bb330eb8603aac115e2693e21623034d93799ade3", - "index": 229 - }, - "coin": { - "version": 1, - "height": 258254, - "value": 170, - "script": "76a9146f3b1484bd137cf7f26dfa73760bf47a0670789288ac", - "coinbase": false, - "hash": "2c1250c35428df72c8080e0bb330eb8603aac115e2693e21623034d93799ade3", - "index": 229 - }, - "script": "4830450221009ed0c7747a2a830be32576ce9a1b078f1c8affe542774d576f3bfb424bdc97d5022041aec55137928df634e395d61062d30392e3b6604095fa4c5f8c84349613393f0121039df64370bf6c8f5097cec0f44578d18168f85927a82de23640b29eb987c54f0c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2311a48e5e3a3bc17a1b7ba9b560cbf257581ceed16d6bc5fd33c4487337e152", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300008, - "value": 263184, - "script": "76a914e85038b40c15662048532857b20b3f3c16a0c06f88ac", - "coinbase": false, - "hash": "2311a48e5e3a3bc17a1b7ba9b560cbf257581ceed16d6bc5fd33c4487337e152", - "index": 1 - }, - "script": "483045022017aeb9b4e3f30b924259a2b4305fb4f4e8673581f3f6f74f5627397d9afb131f02210089578d0a2ccf97022c046f0a0e2be84c18aa518cddd2cfea5801ece00896afe1012102249ac6302a83f9306cf528f606b24a0c2481ba728bdeec59b06c80119256b706", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "edbaf2541436f56a06b3243299eabe7d82a3316be489e8e9d755deeb85ca943a", - "index": 272 - }, - "coin": { - "version": 1, - "height": 252741, - "value": 378, - "script": "76a9146f3b1484bd137cf7f26dfa73760bf47a0670789288ac", - "coinbase": false, - "hash": "edbaf2541436f56a06b3243299eabe7d82a3316be489e8e9d755deeb85ca943a", - "index": 272 - }, - "script": "48304502203b07afe05c231398058c1bd6a4f0501113ea922b475aba441444195d1ee84661022100f3c376593a207801b1d5a2b2a68deb07dfaca4a481fac37fc782b20ab458467a0121039df64370bf6c8f5097cec0f44578d18168f85927a82de23640b29eb987c54f0c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 253722, - "script": "76a914581d833bd9573b7b4690dc8df2e7052d79ac539b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "474f52643cfc36f0ca4556163e553d7763900db3e69fc7bc06d7390fa136023e", - "witnessHash": "474f52643cfc36f0ca4556163e553d7763900db3e69fc7bc06d7390fa136023e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 367, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c6056bcf8432602e0d612bd720bdf106932c833f7113b20f7a0cbbaf3c5539c4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 253722, - "script": "76a914581d833bd9573b7b4690dc8df2e7052d79ac539b88ac", - "coinbase": false, - "hash": "c6056bcf8432602e0d612bd720bdf106932c833f7113b20f7a0cbbaf3c5539c4", - "index": 0 - }, - "script": "47304402207fc4ba0c6d4c7b5d5220ee24b745b406e5dd84e076e3ca6bdb39bc0c0185bb5602201c77da1d359d5a5c6414f1ec561479317b98f18ded77e93b65207fa8bd35bd160121027ed37d607ad691646dbc091d26866b8951fb50b300d33e9093c4d2bb7aad5d5b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10860, - "script": "5121027ed37d607ad691646dbc091d26866b8951fb50b300d33e9093c4d2bb7aad5d5b21204348414e4345434f000000280000000017d78400403e000000000000400a666652ae" - }, - { - "value": 10860, - "script": "5121027ed37d607ad691646dbc091d26866b8951fb50b300d33e9093c4d2bb7aad5d5b2104666666670000000000000000000000000000000000000000000000000000000052ae" - }, - { - "value": 222002, - "script": "76a914581d833bd9573b7b4690dc8df2e7052d79ac539b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "52b34b980222753b0f3f9d450a74bb3b6c0f789669f5439796ec6ac1b085559e", - "witnessHash": "52b34b980222753b0f3f9d450a74bb3b6c0f789669f5439796ec6ac1b085559e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 368, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9d533fd8ba6e30d7520073b87d1ec67c709c2f6fbd8c32a06083333523d7338f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 10000000, - "script": "76a91492a2b75744364dd2e782c4f599d6e0950b5cef5188ac", - "coinbase": false, - "hash": "9d533fd8ba6e30d7520073b87d1ec67c709c2f6fbd8c32a06083333523d7338f", - "index": 0 - }, - "script": "483045022100ce758b7efaa901b114bdadb49a91538448488295c6f2bcb00ee772f22fed61450220425e77c53ef637e8793e5e7e4baf1c75fcf7dfc83e3c7ecea00b8227ab1ba3c001410466b79fabe8c1a6df0e30a1e1939fe7757016f6c4da69853b037a8884016fd2d2dcd6674ac7d86e2647a2f69564507cf9b6a91a3315272121b4908fe16685925a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b18cf59baf64e3c6b7ad254cb578a4a871afb1b42caf0f4a18791f83ba5ab0b4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1123101, - "script": "76a9148c847393d39901ba1d2ba4f08838c5e209936aa688ac", - "coinbase": false, - "hash": "b18cf59baf64e3c6b7ad254cb578a4a871afb1b42caf0f4a18791f83ba5ab0b4", - "index": 1 - }, - "script": "47304402203019399457446b5022d28dd2dbc1e0cb4735163e4d81b5dae6a175f07a35b7aa02203276d9c6efe6ddf8f2b73066243c2e1b08e018f6d62bda9171e4614c6a8981b901410495f6c966431a0d6a358818b2cb392fb741e9216db392597fe2db383c5550e15c3053e735c663f1085ddcd1138dcf6c6019fab37c5b6f406deac8cf6a4cc26ccc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "132b274f2f68848bf437acf95a0d64a6324f191f2c4939907cc93c94d33268e6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1002802, - "script": "76a91482818bc15d2c2f106ea2b8894db5fa32f4c0655e88ac", - "coinbase": false, - "hash": "132b274f2f68848bf437acf95a0d64a6324f191f2c4939907cc93c94d33268e6", - "index": 0 - }, - "script": "483045022100c1688c50f31520e88bfb00bbca5e84de2605765e1c3cfabdffa37509b47f788602203021af416e84badbbea7680b07017793196bedf229f1ea7c21838e60d6dd8729014104fa1a82a6bfd28da16a23b8c88fcc1ca0f69354d9474c98cbe69c106fe76e902128b79884d607fe365b59a4eb6afb05b3e93cc30f8d850db9d9c9c710cd89f038", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8a35b37cdf64de4b66774d0553b9d6a8bb86332f48f585797dcdb88ff4eb8a71", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1029885, - "script": "76a914623cfac997d4ce2ec597e40a6229f4497fa1f28a88ac", - "coinbase": false, - "hash": "8a35b37cdf64de4b66774d0553b9d6a8bb86332f48f585797dcdb88ff4eb8a71", - "index": 0 - }, - "script": "483045022100bd20201d18973f17c5e6ab626a121f70af1440bc287e0d529d93e2653cf866e1022048d246a752dc5bfb9c4235487e9facb6c0e2cb98204170daf514e1887d4a08de0141042747b8d6dd0d2151d8fd2a83b4600b8fba250ec5e6b2d55c6166ebe25ef8a384b8d8ea1701c3016da9b808a9eb082c5b5391c57ba39ce8a227a8c4d3ce065808", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bd1c3bc9246dc56f158e8eb3195fb61eb3557ecec868f118eb54cb32ffa9243e", - "index": 59 - }, - "coin": { - "version": 1, - "height": 300007, - "value": 5755, - "script": "76a914907f1977e8c97f54d463d50e8f70fd97e902087f88ac", - "coinbase": false, - "hash": "bd1c3bc9246dc56f158e8eb3195fb61eb3557ecec868f118eb54cb32ffa9243e", - "index": 59 - }, - "script": "48304502210096c0af1b1661a59083f56da55750b78ea434a1ffcbcbb81b3fd1615cba66b7e1022032ef123dc9567c2b7cd459b72cf54cd281b0245348bbe2b46857363b66b1703a01410423641667359ec400d6ef0254d956ae93bec11b8913c519eb0688dd8e464cbcf164d168d7aa35771523755bd34002633cd734e101f4a1e644e9dc19c12a6a9bbd", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 12140458, - "script": "76a9142b5930c9f810c7208204856da589ea8275bfcdb188ac" - }, - { - "value": 1001085, - "script": "76a9144055a1f719b045092d82ab6a6de027e8a07c9ac588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "bed06339018885aa3f537b031bac8cb1347542f1f4de7739b43eee8d4a2b1d5b", - "witnessHash": "bed06339018885aa3f537b031bac8cb1347542f1f4de7739b43eee8d4a2b1d5b", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 369, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6691eac10d4bcf216c3e31bdbb8a66c378dfa499ece848d5da7caf3707bad315", - "index": 22 - }, - "coin": { - "version": 1, - "height": 300003, - "value": 1979722, - "script": "76a914d5b005d75e3354fa2a4f2e4db880f2421539d9a088ac", - "coinbase": false, - "hash": "6691eac10d4bcf216c3e31bdbb8a66c378dfa499ece848d5da7caf3707bad315", - "index": 22 - }, - "script": "47304402207bd71bd6bf54a78ba383a9d5222fbb2721cc5ea24baa4025603829b00795ef6e02207359befb0487dcdf722f431ff0afc4759e9fdb2a5edb1a84b359d4414918eff40141048c0ea0691a8ba16f58cf8d9265630bbe8078c5a925b7562978c1e0614453b96168ec1d491b86fcfd5239bd1552b45e5fdbb4c009562110fb81356db844bcf981", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 114 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 4634449, - "script": "76a914230f1d29ff930bbf918c57a0f611eb9297cc747f88ac", - "coinbase": false, - "hash": "12388c682654fda29aac2866f438d9c649cad371723296bb418343be46ea33e8", - "index": 114 - }, - "script": "49304602210099932709f248764677f594f65d4d824c890fafbd683502b82f9b09264f7123b802210085b0c3299a2b3a216f88a6b72a588ef713cfcc7460b9a4abdc4a3452bb67e9b4014104c770109a145d135d3bf5d61eaadf00772ba9b928bee4ac2e87299e799c8936b3cc60af9455a488898a97ef0e7b11b26e1c900bfb4e30319e94f9a1c27e848487", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "96f26c43e4056d4cccd2dbb029eda40928a4a6cfd1d9dd8e178d99e70f1746ff", - "index": 21 - }, - "coin": { - "version": 1, - "height": 300013, - "value": 1891622, - "script": "76a914d5b005d75e3354fa2a4f2e4db880f2421539d9a088ac", - "coinbase": false, - "hash": "96f26c43e4056d4cccd2dbb029eda40928a4a6cfd1d9dd8e178d99e70f1746ff", - "index": 21 - }, - "script": "473044022047773c61f06f57841a83b31d622c22af293900a1b3e461526a1fda046c4213d4022035fc21263029802fb64ccf64e30f002d041549ace96eb3b69cdd904ea5a9f91d0141048c0ea0691a8ba16f58cf8d9265630bbe8078c5a925b7562978c1e0614453b96168ec1d491b86fcfd5239bd1552b45e5fdbb4c009562110fb81356db844bcf981", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 114 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2252308, - "script": "76a914230f1d29ff930bbf918c57a0f611eb9297cc747f88ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 114 - }, - "script": "48304502206f90c308d0289ea3a1cc6111f6062b18068f3efeb8bbefac0d65db54929d210f0221008398a840958884a8fceff22557ddd4fc1c977225f8e1267e67e3d92d1b20ce9b014104c770109a145d135d3bf5d61eaadf00772ba9b928bee4ac2e87299e799c8936b3cc60af9455a488898a97ef0e7b11b26e1c900bfb4e30319e94f9a1c27e848487", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "455ade2d6af6b839b05f7c530ccea36a61e7663ac8897bcf8c0491baa892c00e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 137491, - "script": "76a91462f3adc7cab942959bf06a59ba57140216554c7e88ac", - "coinbase": false, - "hash": "455ade2d6af6b839b05f7c530ccea36a61e7663ac8897bcf8c0491baa892c00e", - "index": 1 - }, - "script": "493046022100ef1a633fd1af89836782b781132aa023bae9f08dee39b19066454a18ec431d5d0221008843d5b1f92a939ab639fb2d7ee4e509febaf5fce501c77839bd3b2d62c87d58014104463af689d3956ee92e6a9434333a66ce07e08a78309c64192655eb89d32d0ccff663c515fe93d87fb184d27e55571bc82d4398391da09f27922f27af640c3ba0", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10758101, - "script": "76a9149bda732b7e2ce581819d174ef0c19a08592f7e7688ac" - }, - { - "value": 117491, - "script": "76a914bc027c47bb96cc336cd427bd7fac8d05c0afdb1888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7d928a6e44248dfd585b3b84f45bb78be26f406417f0dc84d1aff51d342e1bd9", - "witnessHash": "7d928a6e44248dfd585b3b84f45bb78be26f406417f0dc84d1aff51d342e1bd9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 370, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0f82638db28280dc15c990cedff4b5f9e412f12e88676ae8c59602457acef24c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299987, - "value": 100000000, - "script": "76a9147c5aab18f23b029ab073616e538d02f9275447f988ac", - "coinbase": false, - "hash": "0f82638db28280dc15c990cedff4b5f9e412f12e88676ae8c59602457acef24c", - "index": 0 - }, - "script": "48304502202a4cf486bfc41cb67407f6d0ea904d8ef5dc3850d6f6df7df1062a30254fa266022100bf9d2b8b8aeb4065c6eaba274109ac987fb1cf38842f173840cf4a77052f6fbc0141047b096191b674912de9cef933110438ab4bd2269f7072381727791527637e702913b03a8c4c09e7abd5e6f73b82b21583a6cd32b47e6ebe57dcaa19f18bdf4ecb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1185acedd4d917f531b8f9a70f9e842abe9458e607d678364eaaadaa8083b0d6", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299987, - "value": 32400000, - "script": "76a914912264004472505b4048e3e15cf66c9ae06fa1e188ac", - "coinbase": false, - "hash": "1185acedd4d917f531b8f9a70f9e842abe9458e607d678364eaaadaa8083b0d6", - "index": 1 - }, - "script": "49304602210092032c5714d166343f04762fcbb23d24a888990abd5d1f53787e03e9dc2189e7022100f99ee57c91e27b685e76d5d0976aa5449951fcd10be44e376658629acd6f4efe014104481e4333d35c6a307d8f4e358c5f050711127b3ed3bb67507826b1a357dfb7ccf1aa0e5e5d6a17194fc50a9a0496e685ec3b2e80793042eb47e952e3e7e667bb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "988d5b591b6daa5289c43ba97e473aab6bc11af8ba2c541cb9b7015ba7158ea5", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299993, - "value": 59500000, - "script": "76a91430be0710877b2fb3b63aac2d37db444d8835a43a88ac", - "coinbase": false, - "hash": "988d5b591b6daa5289c43ba97e473aab6bc11af8ba2c541cb9b7015ba7158ea5", - "index": 1 - }, - "script": "493046022100ac00ac49be8484de1e92fe17679b52eb685c7675c426dc95bc0abb2cdffd0255022100e4ede7fee71aa88f36912bcf59307316e7d2d97e304ec66c05a3a165a6167144014104ab9998acdd24ebd514b5daf63b2bf0ec5a481e0ae4023272c91c0abb8ff9252663eeaafa8679827ca45f7d6ff34a4d09449f2e22129979788a776d2b86224227", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "26595cbc4edeb2cd15c3c68288df24c9d195048edc296ceccf27833f2793ffbe", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 64504363, - "script": "76a914dec7334d4d54267b114edeb7938f18af61c238ba88ac", - "coinbase": false, - "hash": "26595cbc4edeb2cd15c3c68288df24c9d195048edc296ceccf27833f2793ffbe", - "index": 0 - }, - "script": "4830450220320ad68a4e09298927a3024b7168f39fbf2408d79b548483a9b05cf72bcd9e7d022100b7acaf97df3e1b336290742cfc0ba89ca5fc5e49a3a36a046079b42b8e8684e101410452c5145a2c923ee773d9bb553c190dde6e8ace51bfdab30b11bf4349646473f5412698a8ee1ebdcb474f6c0bd56098ccceb7bf83746c97c9968fa8ffe51747a1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e0b48b9da346b569febf6e55e0c35bd8a072ecb51491d10334828bf8ca92455a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299471, - "value": 1016071, - "script": "76a914997fa3cb9803f3e9be709bd24a371da3ed65eed688ac", - "coinbase": false, - "hash": "e0b48b9da346b569febf6e55e0c35bd8a072ecb51491d10334828bf8ca92455a", - "index": 0 - }, - "script": "493046022100d9bd0fbfa27424a4e8c7e572dd4bfa8bbc1db71093c59371a7270078862dc4dd022100b4240ea0078087b3034f447f73ce824aa0b267c627d9328cb7cec1ba87c7e6c6014104f774514b742f54c6aac8ca585ef76af5c0f80e507bc3cc862597485dd692e8f44d02e3825174d51b45ab747c729b8a9869a471158bc8a3d928208b0827ee27b5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000000, - "script": "76a914ae18f57a185dda965710fdb46740f3af9bdf033688ac" - }, - { - "value": 256400434, - "script": "76a914bbfeaff760e3eb9a932fb3e6542c79264e6d3f4688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f3484a690e27980a9c548c6effe7654e24a442a758a6a44072666abbce066534", - "witnessHash": "f3484a690e27980a9c548c6effe7654e24a442a758a6a44072666abbce066534", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 371, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d3d9a5a90ce398d2886adff8a2e04eeeab0908f0542827a8f387ece5c8ab5239", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 652500, - "script": "76a914a48c35e18e369168a18029a75ceb84705b1c87b088ac", - "coinbase": false, - "hash": "d3d9a5a90ce398d2886adff8a2e04eeeab0908f0542827a8f387ece5c8ab5239", - "index": 0 - }, - "script": "47304402207bc6369a4259f7d78725a8e4abc928946357210358c76a82a8cca315588e1bf7022040348aec87b32d315fc7af82566b500a4008e6576df75e7de809ad0178677f11014104b0236c572eb6198c0c9f830f9a7835fc1ae0ad7f9110bb4fa7513eb26cd50c836208ab581e14a64fefd3dfaaaa1ce613ecb18e57cc5c39487418b78154d1d09d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "448d2ac3bcce569418a073dc78489c3884be690a9af662beb8f90a866c697274", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 663750, - "script": "76a9149ee7123de82cc79a5468a13099e3f6735ac94fee88ac", - "coinbase": false, - "hash": "448d2ac3bcce569418a073dc78489c3884be690a9af662beb8f90a866c697274", - "index": 1 - }, - "script": "483045022100bfb5293ee182e28728ca5ec3b8deda07c5b01a6e6e85e889e8badb0d19360bdc02205dec9aaf561956a32c29686e4acfa84d2dbce7e31a9181cad62669994f8ed3f301410415382af4c83299598c1f6c98d533d5cfda3f5199e4a4e1acd235000369d37d37d0dadd1670fefa7813d12b041e490f8ea6580fb99e6ed19cd06ffcfc72367685", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9d078a6e2ad469f982804db6bf6823420a2100701fbf98e2119f52a85d26df59", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 712500, - "script": "76a9149ee7123de82cc79a5468a13099e3f6735ac94fee88ac", - "coinbase": false, - "hash": "9d078a6e2ad469f982804db6bf6823420a2100701fbf98e2119f52a85d26df59", - "index": 1 - }, - "script": "483045022042afa0df8d313231348f50d3939921a4a375061972e26d3076982ce6dc4fe387022100ec343736d2b4640efb397453ba611316ade12900bd4b320a52461d68c814386701410415382af4c83299598c1f6c98d533d5cfda3f5199e4a4e1acd235000369d37d37d0dadd1670fefa7813d12b041e490f8ea6580fb99e6ed19cd06ffcfc72367685", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c04031af2955c2e04a4992609b35908419ac9939877f896d5af1684caac43f49", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 832500, - "script": "76a9149ee7123de82cc79a5468a13099e3f6735ac94fee88ac", - "coinbase": false, - "hash": "c04031af2955c2e04a4992609b35908419ac9939877f896d5af1684caac43f49", - "index": 1 - }, - "script": "48304502203765b30276508134d8b6239dcb1c8aaf99232bc4de830e3e7d1ccc3cc7bd65b2022100c6c8b4b5890198eb75bbaa25922b2bb870c3571027512339c06f9bcdbcf71bcb01410415382af4c83299598c1f6c98d533d5cfda3f5199e4a4e1acd235000369d37d37d0dadd1670fefa7813d12b041e490f8ea6580fb99e6ed19cd06ffcfc72367685", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d725e4c0921a6ecece44c7208821b1bc1fc6fa10a5952ac14dc089173d80492c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 875000, - "script": "76a9141a1c313aa0b15d36a4eb60114e618b334857959388ac", - "coinbase": false, - "hash": "d725e4c0921a6ecece44c7208821b1bc1fc6fa10a5952ac14dc089173d80492c", - "index": 0 - }, - "script": "47304402205cf33d3d0d321bd02a959abd1de9c8d964e13b5837c750196ad10b0720ea91e2022060b2afd37cc560ebd20b0e923d8ebef6a2423d87648d77454aa8b8b05937d7a9014104e20c9ca2589d3b3b81b88f6606fcf84d705ce506b33799943129d0a66cdf4ebcb62dccaea7859c0b9fdb13993ddad8ec4fd2dac5d117720579bcd7a3e4099c4f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "840dac6bb8fd5b5ca3a677d878d2cd18066f75cc4a04c959c482428c79823170", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 924630, - "script": "76a9142c458cad997e4774d4b25162ffb8c06e28bc365088ac", - "coinbase": false, - "hash": "840dac6bb8fd5b5ca3a677d878d2cd18066f75cc4a04c959c482428c79823170", - "index": 0 - }, - "script": "47304402201e3328cd2ca4c0c640206f8e88774b6ae9998679352aaa587d8e524a03b5ff6a022061775191167caaf14852a4de9d85378b2f2032be120758107e1be0c8fbe802c2014104292d978b510e534d6042266dd401bdbe8459ea203ef1db34cb8e78fe199bebfd309f2f6fb97792f1c59df661fdae98123cd5dafac6451ea7a77dd6933654e8f5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "712c623e7d6aa4e0e02b4bcacac96b819ca8ca62a032dc8ae20a1b254c632db7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 940640, - "script": "76a914259c7b493b96b4b02b9ce5b3201ecd8459f068a488ac", - "coinbase": false, - "hash": "712c623e7d6aa4e0e02b4bcacac96b819ca8ca62a032dc8ae20a1b254c632db7", - "index": 1 - }, - "script": "48304502207f754004633b001e9061574f1a41d8f6433c3c5c6e2de62d1549325f2d16749e022100bfeeecabe7933e4ebb5715999415874ba9f2dcbcb449c9aa339a62c15917f3850141045bce3451fc11f22d4d6210602173afe76363170fc5591860eab860a54ac8405990c8814fc21e904bbcd117c7029fe6562f92d6dcb92ad785257761dedcf08287", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cd7add4d5f1a2f9d11afa5fcf97ca31a88efa2c12a4f5bfcc6ecc1f3cad872b2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 961875, - "script": "76a9143b96fff6364a054e979f41afc7edb36d7d34e98088ac", - "coinbase": false, - "hash": "cd7add4d5f1a2f9d11afa5fcf97ca31a88efa2c12a4f5bfcc6ecc1f3cad872b2", - "index": 0 - }, - "script": "4830450220030fafb1166b17ff76b36360dc68091ba6bb95ce88675dcffc3a870419e5e0bd0221008accabb848daa57ac1cae7a50a8ab3c87d3e790636cf3265957c9ee03e5e32190141041fcd6901d896e47d7fea711c87e1c91c2a7349d0a04569b3a5c9311ddd5ef55f25db861a42f21dd4595041eb23128fae2091e9dc1930d4cafd06e8d4ae78e865", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ccff7409fe8c482a4e80e6378fd1993467b08796d05e6a4cc92e777f2fc37f3", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 967466, - "script": "76a9149ee7123de82cc79a5468a13099e3f6735ac94fee88ac", - "coinbase": false, - "hash": "4ccff7409fe8c482a4e80e6378fd1993467b08796d05e6a4cc92e777f2fc37f3", - "index": 0 - }, - "script": "47304402206a28a4e4db54960803d8ca06a64d01d9c92cb9585d1ecdb5a12550673764c07102203d79e03aef4186c11cc2676c1f008918de85a4caa90a7a61e8a8430fc549153601410415382af4c83299598c1f6c98d533d5cfda3f5199e4a4e1acd235000369d37d37d0dadd1670fefa7813d12b041e490f8ea6580fb99e6ed19cd06ffcfc72367685", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4743c9e7fd66a83c9a9481f6ad4b5826005ea0806e65c703b55e387a7c0459fb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1874535, - "script": "76a914b8b13e0c3a2df20e78840dd29a64b171d30b6f0c88ac", - "coinbase": false, - "hash": "4743c9e7fd66a83c9a9481f6ad4b5826005ea0806e65c703b55e387a7c0459fb", - "index": 0 - }, - "script": "4730440220225a9dfc49a60b5eef66c7df8f1548c95379dc54902eddaa1529e58ed49b4b37022038d1f84b4af98d18044dc4d515ef57b918f2a4a70e5dc1ad0ad1f004fca6f58501410401a5c74e84b7e249b3bb502a2a2875677dd68339f26443d14b0b0a15da261d3cdd1dbfb9ca3678e7f68c5a093623df17ffdb520929509f64748ff855efb5a6fa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d1114c4a3852c2976d395a7ecb3e0698773f65ea67ba15ba6062134a41497e96", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2141790, - "script": "76a914c6b9023216a7156a9939de2c025e5ea4415a057c88ac", - "coinbase": false, - "hash": "d1114c4a3852c2976d395a7ecb3e0698773f65ea67ba15ba6062134a41497e96", - "index": 0 - }, - "script": "4930460221008201de92d2b15c3d57c9be2e7dcabe1c8d88dfd4bc85871d4f656eedef3533f2022100e8a4db602d11c8fc82121f6d67604a24df2b452464d4b3756598075f8ec10b850141044c26aee65ebf0008de84d7fe3c930c8a21b52ac1f9c0a78ec23ad97cbca680fbcaa896e2d45ffa1204cf6ee9447451518194bf9c48087e6c4b0265c661a1d81f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bcdc4cfe921235098a7bd844d6f065b79098ccfeb1c352790e3d4bca261e79d7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4355000, - "script": "76a914be23007ebb9232f84a3f8d4b0c16fbab0182550088ac", - "coinbase": false, - "hash": "bcdc4cfe921235098a7bd844d6f065b79098ccfeb1c352790e3d4bca261e79d7", - "index": 1 - }, - "script": "493046022100e7fb3bf2922376661897c2fac7fb3dda066e0e4333aec4471ab9d9c6a873d54e022100a6dd6fcd75fa2628bc6b267524c64800bfc0d400585a3b534d56f15529b66a05014104d532af2a5d6d7ef209bbb4688ee5f9a05047b8314a707ea0aad96807cee00f6f0e9a0de612c0371eb1d4500202ce5bf6be9c1591c3d10f2abe61442cab9ce5da", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5de0b84cad5914c63a51851c5d20f1fb3fb357c5d104685ba024d358e6d00341", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 4379424, - "script": "76a914cbc6d8c7bd8ffffd7949793860b9d60d29ea6af088ac", - "coinbase": false, - "hash": "5de0b84cad5914c63a51851c5d20f1fb3fb357c5d104685ba024d358e6d00341", - "index": 0 - }, - "script": "48304502210081d612a5a78a1ec2d3e80b885ab6d3a0a53093c1f292eceb583365dd98035b3e022036ccaf4e5e36acf181ccb5976f2a1b8988fff365e11e814cedd57062b613673b0141047c2ef7c67a693aaecabc03f1ab0bea5ab3a8226d67d899162754ac7dc21fbb285fbec78f541a66184fc65f164c1021270f5fd0d62f4770e6901f28b457a88ba4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "aacbf0912ddc550548d2c0e992c6da2e7166033a946ddbf5e3e062286fb26454", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 6638275, - "script": "76a9143e8b51164977e0825aaaba3dd50e8f898be5a33f88ac", - "coinbase": false, - "hash": "aacbf0912ddc550548d2c0e992c6da2e7166033a946ddbf5e3e062286fb26454", - "index": 0 - }, - "script": "473044022020ffb5d5152d93f8f8036e34fdbe5a68989ee411cd8c6102b76bfe86b3156b630220310083aa442d910d08fb690acfb2dbb82a4c1c7d44257ce431e5b8b149ba70c701410404e20090ef0252d2daca0185b1ff23bbfaa64e708d6919a267bc7c1ae43e1d6b6f689a27a5420fb1820440a65fe23096f7b0e429a3ff718c8471ac45a7948c38", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9ed948beba965cbbfedfc80e47e172763563677f866ad7b586d96938e9746731", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 8312500, - "script": "76a9143b96fff6364a054e979f41afc7edb36d7d34e98088ac", - "coinbase": false, - "hash": "9ed948beba965cbbfedfc80e47e172763563677f866ad7b586d96938e9746731", - "index": 0 - }, - "script": "47304402204501199b922cca993b297c6a30965bf30e5ab446358d9673d214f6736d4bac3f02203d4118126e38f6c67533519ce27edbffb7f5b1baf3db025b94324ead5cb10e360141041fcd6901d896e47d7fea711c87e1c91c2a7349d0a04569b3a5c9311ddd5ef55f25db861a42f21dd4595041eb23128fae2091e9dc1930d4cafd06e8d4ae78e865", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9c0e2076162520e7a59c354e71c8bfedb436d7075d8376b1df90624e4ea059e7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 11870250, - "script": "76a914273af6faf129a29a09b1748533b611c90928f52e88ac", - "coinbase": false, - "hash": "9c0e2076162520e7a59c354e71c8bfedb436d7075d8376b1df90624e4ea059e7", - "index": 0 - }, - "script": "47304402207e2f0ccc162528a7e9eb9173c80af514a074ead42a4db42c64f1d3f9fd0cbc61022066ae98928021a673c403c22a5a0d920677e2cadb00754734502eb3d94668c5820141046d0a84c68ca26069686b5d1bb964e64ee1c2115d5c68605a55d3bd335cade0b8c0f242afecea2bf4c2930c1aa78630bf96ed33c0a580b141007d7cff5d0be85b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "620433a273d287a32fadd808eb90264e55ee34b2e74e468ab251b15b9cb4bd1e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 12990000, - "script": "76a914aa1d23190f28a060c3cc42959fe89be16dc9ff0488ac", - "coinbase": false, - "hash": "620433a273d287a32fadd808eb90264e55ee34b2e74e468ab251b15b9cb4bd1e", - "index": 0 - }, - "script": "493046022100f490d8bc50dfb8542f15dce274dbe9ade30c3b203350fa6cf1dbb404e13d6aa402210084e213055ee0009a39d9fe43e9935c20318afa0ec368b6e172d219e891ac0abb014104871b6f857e53611f097db4972faeb5a049052ee99bfe9a08434276088a59d383eedf42e92f86ee6e34781f9e61526e508cf876aef6aaa0c7813b41df09e5ed5f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "20373fb44c660de5e2cb5484c144e8121b8f0b488d5bc6b36954f4fe906fe668", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 18000000, - "script": "76a914b8b13e0c3a2df20e78840dd29a64b171d30b6f0c88ac", - "coinbase": false, - "hash": "20373fb44c660de5e2cb5484c144e8121b8f0b488d5bc6b36954f4fe906fe668", - "index": 0 - }, - "script": "493046022100a9175904a655b2cb156d9f52abbbfd723f1848833c4db417a3a9bff3ad5c16d9022100f83694ca4a9b8208ed71bbd68558c87493ad636d5afb7f521fbdaa2a15f25e3f01410401a5c74e84b7e249b3bb502a2a2875677dd68339f26443d14b0b0a15da261d3cdd1dbfb9ca3678e7f68c5a093623df17ffdb520929509f64748ff855efb5a6fa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0c418bf7309038740e0f738823193064abc7dc11cf6fe5c5f192857ab0f86f62", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 350000, - "script": "76a914b8b13e0c3a2df20e78840dd29a64b171d30b6f0c88ac", - "coinbase": false, - "hash": "0c418bf7309038740e0f738823193064abc7dc11cf6fe5c5f192857ab0f86f62", - "index": 0 - }, - "script": "49304602210088a11572dc77fbbefa9612fa1a29e98192e6fb809100090613f99d18f4d0271002210094c5da082613d67c1c9f2621601529b54396070a90d904858d6d2e517e3998d401410401a5c74e84b7e249b3bb502a2a2875677dd68339f26443d14b0b0a15da261d3cdd1dbfb9ca3678e7f68c5a093623df17ffdb520929509f64748ff855efb5a6fa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8e080270d7f5193bf9350e1de7e0807c5dc35768eb6d059d0e000aa391a5afa2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 305368, - "script": "76a9140f1537e149a4452c8b1a29342e2b25981518ee2c88ac", - "coinbase": false, - "hash": "8e080270d7f5193bf9350e1de7e0807c5dc35768eb6d059d0e000aa391a5afa2", - "index": 0 - }, - "script": "483045022100b4ea5f1586e8ea4ed86545be23c925c86dd8d09eaca2c9fb3b2e6368ea0660f8022011d6665d8dec2d754b27e817777346bfe7efb857e07484c8caf892309dd7b2da0141044bef85f93a7e009b8f64ea59a4ec4b47fd4f36439130ef75405c9e1838b8934c51ec3dd48047cd9d84c8bc2cb13c74ab9ec5f6d3d166e3cc8856a8d688f13cd2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0e906137b757a2bcbcb43757d95a66d5f907dba30d937e5fd09201dca5dcdba8", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 225000, - "script": "76a9143b96fff6364a054e979f41afc7edb36d7d34e98088ac", - "coinbase": false, - "hash": "0e906137b757a2bcbcb43757d95a66d5f907dba30d937e5fd09201dca5dcdba8", - "index": 1 - }, - "script": "47304402203886a9861e3a7b6508fff363e71c2be08a4e2694e73f4129c58db18321578fc00220249d6975a00d29d3637555b55b708258129e172f1363812e2fa4c9bfbb1c4d560141041fcd6901d896e47d7fea711c87e1c91c2a7349d0a04569b3a5c9311ddd5ef55f25db861a42f21dd4595041eb23128fae2091e9dc1930d4cafd06e8d4ae78e865", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cfffe6d3860739cef039b6b393e780aee4eccd19018d02e91ac1e3d10e429e0d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 208620, - "script": "76a914a48c35e18e369168a18029a75ceb84705b1c87b088ac", - "coinbase": false, - "hash": "cfffe6d3860739cef039b6b393e780aee4eccd19018d02e91ac1e3d10e429e0d", - "index": 0 - }, - "script": "473044022049c50dff6cabf6f0c58fbf6e248764e4cc24cc1fc83d3c4f05e41961e63f7d97022016913f131905e4e390f72b25750a945e4cb04b51c11b7c2c0012c2a006d98825014104b0236c572eb6198c0c9f830f9a7835fc1ae0ad7f9110bb4fa7513eb26cd50c836208ab581e14a64fefd3dfaaaa1ce613ecb18e57cc5c39487418b78154d1d09d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7b5155dd5aa45ae062e5faa7a80916e0dd071f55d2d9fd311476f57b72265604", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 198518, - "script": "76a914b8b13e0c3a2df20e78840dd29a64b171d30b6f0c88ac", - "coinbase": false, - "hash": "7b5155dd5aa45ae062e5faa7a80916e0dd071f55d2d9fd311476f57b72265604", - "index": 0 - }, - "script": "483045022076bfc19987c84a504d6e4d06874760239a404da0c178afb7bc9810f79e3ba7a9022100acf44f2ebca268a684a401be7fb7f11434c5e3ac8b434c06ce19f3a6bd09d13e01410401a5c74e84b7e249b3bb502a2a2875677dd68339f26443d14b0b0a15da261d3cdd1dbfb9ca3678e7f68c5a093623df17ffdb520929509f64748ff855efb5a6fa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c40a2217846bd232c177f1ef8d81ffb08c6fcb675b798da50fd2a119d1cf9201", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 157279, - "script": "76a91419047661f6c0ebff62713b975f3a72f819c7ce7588ac", - "coinbase": false, - "hash": "c40a2217846bd232c177f1ef8d81ffb08c6fcb675b798da50fd2a119d1cf9201", - "index": 1 - }, - "script": "483045022061cf7dbd4d4465d2ee1b4f17c0e761735a03f5da4afdc8ce45949bc220093179022100aa60a833c3f4ed9294bc8301da3ec22c9fa7f337c2f3c211239be2211ffa0538014104f96a5adcd60e878a6399e940d5719e116047ff7a73280e8ce80f7eb7224662b7ff0b81d8ee26b42db84022154672f32b65d120d537f38940ba6c82ebef051a6c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "885495c41fe0594b10c66b1954245a64d65b94ed74a4f21fd9acc06550159496", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 133400, - "script": "76a9143b96fff6364a054e979f41afc7edb36d7d34e98088ac", - "coinbase": false, - "hash": "885495c41fe0594b10c66b1954245a64d65b94ed74a4f21fd9acc06550159496", - "index": 0 - }, - "script": "4930460221009fcc2918b790d506100504bc6e84e4c2984a2e035949a6e813cb014ed4304982022100cd5171cf25d06b956f67c477b65adc364d588a924eda2635884354e8930303d80141041fcd6901d896e47d7fea711c87e1c91c2a7349d0a04569b3a5c9311ddd5ef55f25db861a42f21dd4595041eb23128fae2091e9dc1930d4cafd06e8d4ae78e865", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2f276219cb6ce8a9354954b81a0babfb76ca5054de51c1febfaaf9f50658ff4f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 112655, - "script": "76a9143664841e92e6f000e6335970187f3f51a36b946e88ac", - "coinbase": false, - "hash": "2f276219cb6ce8a9354954b81a0babfb76ca5054de51c1febfaaf9f50658ff4f", - "index": 1 - }, - "script": "4730440220530c0856a657c80c22f22b6d4dc775692f66530b1738216c4b17981a648567e902202b31cd49ed1c858dc910f7524b35502838157d638ced4e168dc35104750025e90141047b7dd10427c9e1ab556322885a63f2f2dfae0733ac9f35f87713749feb98c3dd88994e0a4188a9549ae83a86cf330ec18c5c857284d970001aa7380d831919e3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8900ae3f85ad69b9d0b18a86640d059ea11ddd572f1087b7e1d3504e7b0767f7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 42500, - "script": "76a9145f2893e207f963ba4d0144384891cfe290c2d43988ac", - "coinbase": false, - "hash": "8900ae3f85ad69b9d0b18a86640d059ea11ddd572f1087b7e1d3504e7b0767f7", - "index": 0 - }, - "script": "493046022100fb032cf8c23379824f8f704f6c3bbdeab9c272ba61c1e3795696e3baf2637ac3022100d6d8a8a14d16ee0ec38c977a6995d5404ce59c326928c3b7dc52418b1b356b1101410475a514c0edc8bac732649efe571a2b44fbb7ea9bd308112ad9439d3eef8f70a0b4ef44e67115ccf28af4f5f0b488c210afda8f664e3d371d7c44414a2d5309c4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ea56ed1d0b5fc9fc48ee3e991a58e04c05bc71a839f83223d965e78f29c1b3b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2700000, - "script": "76a914a48c35e18e369168a18029a75ceb84705b1c87b088ac", - "coinbase": false, - "hash": "6ea56ed1d0b5fc9fc48ee3e991a58e04c05bc71a839f83223d965e78f29c1b3b", - "index": 0 - }, - "script": "483045022100b0c5aa0abd1d0e38223a27090f40cfea72283d1b7296bac6fea5922eababd88b02207ccdd53ba33abe7b78a7aba5d827df6698ee43b523a357da45eee368de4fd153014104b0236c572eb6198c0c9f830f9a7835fc1ae0ad7f9110bb4fa7513eb26cd50c836208ab581e14a64fefd3dfaaaa1ce613ecb18e57cc5c39487418b78154d1d09d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6233ec393499de9c3833300db80c9be107f3316bc64ff681603fa7d89c3ba218", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 24000000, - "script": "76a914adf95b6304caef49ee8799a65e471f1ea1ffe21688ac", - "coinbase": false, - "hash": "6233ec393499de9c3833300db80c9be107f3316bc64ff681603fa7d89c3ba218", - "index": 0 - }, - "script": "483045022100c96731d13803e7c2bd7b8dd4e0221dae579a7dcb196970a3fd985b027d6496ed02207a502c0f680df8c9c553107d6396433af2a6fbe6865720017169167fdc323c3101410453850e38f09887428e8182248b318ab730ad09df2bdd74b6ae842af66ca71a01942679012c81f8f1760ac1625e2636c2740eee328ef3ad45f704a4928404aea4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f725c8db39a2724095db54b75a038d6c660d82596c004305692179dda1924287", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 78750, - "script": "76a914b8b13e0c3a2df20e78840dd29a64b171d30b6f0c88ac", - "coinbase": false, - "hash": "f725c8db39a2724095db54b75a038d6c660d82596c004305692179dda1924287", - "index": 0 - }, - "script": "47304402202d9221bd75093c0adceb58e30b1c963acf6a1ebdd6b0a0a919004ca6b75452c30220128468b7cd2c3d51d8cc73caeaa8ab5dc51c1be4e45ca9a09c5eb2853d5c3e3301410401a5c74e84b7e249b3bb502a2a2875677dd68339f26443d14b0b0a15da261d3cdd1dbfb9ca3678e7f68c5a093623df17ffdb520929509f64748ff855efb5a6fa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2b5159d1ee47808e4161e659b0f12b1b55e1438de80bd15f165845be68de1e43", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5500000, - "script": "76a914259c7b493b96b4b02b9ce5b3201ecd8459f068a488ac", - "coinbase": false, - "hash": "2b5159d1ee47808e4161e659b0f12b1b55e1438de80bd15f165845be68de1e43", - "index": 0 - }, - "script": "493046022100cc066621ea00c644a6339554fb1e6753ffb8102fb3d96e6f1b51f826c6a59166022100c1805e167c7c2ce288a64578778d311f2d4147c2a6261bdbc7c48ec94b4fdd4e0141045bce3451fc11f22d4d6210602173afe76363170fc5591860eab860a54ac8405990c8814fc21e904bbcd117c7029fe6562f92d6dcb92ad785257761dedcf08287", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c9bb583e9e87955bd9baec5a3b372ed4a230861e2b57d0be237afef9d373132f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 441600, - "script": "76a914be23007ebb9232f84a3f8d4b0c16fbab0182550088ac", - "coinbase": false, - "hash": "c9bb583e9e87955bd9baec5a3b372ed4a230861e2b57d0be237afef9d373132f", - "index": 1 - }, - "script": "47304402200ef17c54690759831b74b641582bdd259502e79eb7f43d07510aeba529470c0302204d28508df97352fabcfe028298e249462dd7e84363455455d7ae263d40325f36014104d532af2a5d6d7ef209bbb4688ee5f9a05047b8314a707ea0aad96807cee00f6f0e9a0de612c0371eb1d4500202ce5bf6be9c1591c3d10f2abe61442cab9ce5da", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4d7d8b42d9e52bf0dc616502954700aa329db06ffab1d7a830b4758d592abfe7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 145500, - "script": "76a914058ab1128c7c571725f73644b8ed2bfb87c7b03a88ac", - "coinbase": false, - "hash": "4d7d8b42d9e52bf0dc616502954700aa329db06ffab1d7a830b4758d592abfe7", - "index": 1 - }, - "script": "4730440220736b38c9bee9454985fbbfc003484e5b1ed8f89485322d03c23a0961e4e2c29402203ab6da67623a74623f44b9966f7c873ef57a568c92c3ce361c1b0de7d271c44e0141042e93ca33dfd4ef713fcbaa1d06f6abed8399f0e46c64d9c3d79fecc76f3471e82fd328db489e60fda17a397fd3fbf9e729499f07cecc9953c0da1eee46fc113b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "62129f0b28b95be2020f16bb81abb573e805d0812a483bb3cddc17a5b5dbce88", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 311600, - "script": "76a914a48c35e18e369168a18029a75ceb84705b1c87b088ac", - "coinbase": false, - "hash": "62129f0b28b95be2020f16bb81abb573e805d0812a483bb3cddc17a5b5dbce88", - "index": 0 - }, - "script": "4930460221009f59d510cc6a8ae0b55e0d878adfc986d462489410da64e8dd94a0a4f4a43813022100bd32100a68dd07e36a497e356943610132afd7683f27ca3f587c22b7b65a3f06014104b0236c572eb6198c0c9f830f9a7835fc1ae0ad7f9110bb4fa7513eb26cd50c836208ab581e14a64fefd3dfaaaa1ce613ecb18e57cc5c39487418b78154d1d09d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eba6e1421c5798a66bffad7aa60f42f59a95d708555c191b037d85cc1003f81b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 16787500, - "script": "76a914adf95b6304caef49ee8799a65e471f1ea1ffe21688ac", - "coinbase": false, - "hash": "eba6e1421c5798a66bffad7aa60f42f59a95d708555c191b037d85cc1003f81b", - "index": 0 - }, - "script": "493046022100f7b91ba3938e4be4225bc41b000745997e45afc24bb7b373c344edc5fe5d3056022100cf57a5ac07813a620e018157f44de069c6c9ca0283a49abed90a6fc58ec6ab7f01410453850e38f09887428e8182248b318ab730ad09df2bdd74b6ae842af66ca71a01942679012c81f8f1760ac1625e2636c2740eee328ef3ad45f704a4928404aea4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "90fa73f30efd222bdae6d016172402355d4bb5d03e250ac1087e88bbd08b010a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 345000, - "script": "76a9143b96fff6364a054e979f41afc7edb36d7d34e98088ac", - "coinbase": false, - "hash": "90fa73f30efd222bdae6d016172402355d4bb5d03e250ac1087e88bbd08b010a", - "index": 0 - }, - "script": "483045022034b7e0734400ef0e0d898c02e1fd8762356048789c0a86c9e170ea58f7409dfd022100b9c165cac035274475f462b7ef8baa668d954a484d99a5c1b4e23ec801dafc0c0141041fcd6901d896e47d7fea711c87e1c91c2a7349d0a04569b3a5c9311ddd5ef55f25db861a42f21dd4595041eb23128fae2091e9dc1930d4cafd06e8d4ae78e865", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a57fdd37133f1399e4f0d99569663b3f61f7e7db0a648f288a7b5ce7ae7b77ed", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 77491, - "script": "76a9142b48ca0cab536a7720182f48cfe789a132f9198288ac", - "coinbase": false, - "hash": "a57fdd37133f1399e4f0d99569663b3f61f7e7db0a648f288a7b5ce7ae7b77ed", - "index": 1 - }, - "script": "47304402204f21cebff29c1fcd4036a5a4930ff6b6a5cc71b9083ce7dce582687fedbbc0d80220607be8834f411b89a55960de53939e5d2858fc0b17df0191b430b1c3670fc492014104807cad7b28b3735ae6d58d4232348a721cb6216c0e01bf66328635472488af6efd67b2e3f95a4a3018acbd3d66cdad98dfe0476b52eedfae19cc81d76071cb5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d1ca3864d76e4099299f9901b58b6244df96056b9a085fe4d1f99e368fc396cb", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299968, - "value": 97491, - "script": "76a91415299d0815dd8bf5dd1e6f1a98744f9af850ddf588ac", - "coinbase": false, - "hash": "d1ca3864d76e4099299f9901b58b6244df96056b9a085fe4d1f99e368fc396cb", - "index": 1 - }, - "script": "48304502200a55d2040c0c5be31bf105cb4b1fa04739d4e01da1c65f1ff63aaf5b0ec91bc6022100ceb3429a7ffa2acd54b74bed58a6469395c0af3827fa6be68f95d1af58fdab29014104eb2ace7b797092ccf150c8be345c37de5e921b035c34f82399065bb123e7b5b39b596179591c882e69a2a25af94a29fc95e8420978fc6cb457dabc1bc6b28af4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 130135925, - "script": "76a914deb92e379612bd6ce76814e4babd5cf00da9e85088ac" - }, - { - "value": 34982, - "script": "76a9149acbb2f94a38b72e256290af1bf1cfc27d88b2b088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4dc8a701668a86986977dd079c17c955fcc8b0fe7eaffeb682bcf130ebf56f80", - "witnessHash": "4dc8a701668a86986977dd079c17c955fcc8b0fe7eaffeb682bcf130ebf56f80", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 372, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5c92531edf7b441ad27e876afcc0252aed04bde4b481833a03a9c95ab9df392e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 200000, - "script": "76a914da5dde8abec4f3b67561bcd06aaf28b790cff75588ac", - "coinbase": false, - "hash": "5c92531edf7b441ad27e876afcc0252aed04bde4b481833a03a9c95ab9df392e", - "index": 1 - }, - "script": "483045022100be9bf5ec5fc59be9687b5bc58f055c79d2eb2efce39e966f02deb68e45758b24022072aaf787538cfb4d9ab9c31963db2d6172808adee3fe94cd32b0b713589e8c590141049de1c8260ad5729982fa9589f0aa795a76dbd9695418c232963098eac9c1a2b3c74669555f94f6e3fe7800916a8e30651dc7eefdb82e773bb096358420818d5a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "717411473e05e85d6aeb27bad1093663c23f6af57f88193c969a9ec7e1e18322", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "717411473e05e85d6aeb27bad1093663c23f6af57f88193c969a9ec7e1e18322", - "index": 1 - }, - "script": "473044022006424bd8b16f58e4da6070847c268af41df018b1fb4c95fe7fbbc70c87af7a810220187eb30a58cffd8e2696020cee07fa3a59fcb6f3512968b453e5da168ec303db0121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "71b6e6dcd17c363564632f3e0beff40bf37d03d31fba02c3582d45ccdaf66871", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "71b6e6dcd17c363564632f3e0beff40bf37d03d31fba02c3582d45ccdaf66871", - "index": 0 - }, - "script": "47304402202fe042b2c005152adbd0951bfeedcd7c2a86d9d60470b0b0ee4503662b3f3fa002206c1b7869309f166399a879a464c11e74ce77b9edebe2e680aef1caad99be034a0121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "73d3e30fa43df3ab291fb8d45220f468bc58898cd3bf341ca8765fc374c9118d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "73d3e30fa43df3ab291fb8d45220f468bc58898cd3bf341ca8765fc374c9118d", - "index": 1 - }, - "script": "47304402203da67fc1d5915b7840914b01896d5052b162209d9925ebf34722a5436487940502200fbdbd25d2d32816b88dfece2c73486a192ac3b0d9da69f07f51ac6a50e2f8d20121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7f973335d82e6668a7720a2f4fec9e8d1e0a07127c42348620b2cba1b9f9a6f4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "7f973335d82e6668a7720a2f4fec9e8d1e0a07127c42348620b2cba1b9f9a6f4", - "index": 1 - }, - "script": "4830450221008f6c763068bf945a82cf202839fe8da5f57538fd59050aec304c1aee44b662b202206adac1b8e517b6844e9f99fd2b7f3cdfff1bc9c30776658395021412aafbccf20121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7fb63bb524223dec5ae80e3123d3be3c6c3ce83cab451666fdb14cf9ddae1d77", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "7fb63bb524223dec5ae80e3123d3be3c6c3ce83cab451666fdb14cf9ddae1d77", - "index": 1 - }, - "script": "483045022100da1aa9fc9c0e40fec20728918b3deab6c90a6c4e188f4cc7ae0a4d18587a3e35022000baff783e5fd6505bca945b87c10d0080eadab4c82091a66bcbba1dd0666e250121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 390000, - "script": "76a914534f420c13b4af49c9cde2dd34f6dd78d1996dc488ac" - }, - { - "value": 40000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c6b3298c1f18dfa15743f85bb3b7eedcb5f323542067cb6294451eeb14c38c83", - "witnessHash": "c6b3298c1f18dfa15743f85bb3b7eedcb5f323542067cb6294451eeb14c38c83", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 373, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "95c0b1bd9a0e759dec2c00acc231715928c90720156e2af91ddb1d2ed0bfc68f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2400000, - "script": "76a914626ebedca70103f5c1e06ed5904f0bc478a263df88ac", - "coinbase": false, - "hash": "95c0b1bd9a0e759dec2c00acc231715928c90720156e2af91ddb1d2ed0bfc68f", - "index": 0 - }, - "script": "47304402204902009b0ca45dc7d9dbb0c034e0f685f0fd1adf0db2ce28d437f71b8eb6138702206c40ac9863f07ac7e778aa5364347ed57476bbadd5085a0b8c9717f82965d712012103cba05903e33c1522407602b64d91ad92d7bc33df9cd74d5a97288d5379296128", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "19d30f5af2e3ef036bc8c98678d6696fd998966bf7d4a83b94902945fa7034ed", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 143727, - "script": "76a9140cc7a4cb0d42a97ad29cfc0a49f955d78bd0362388ac", - "coinbase": false, - "hash": "19d30f5af2e3ef036bc8c98678d6696fd998966bf7d4a83b94902945fa7034ed", - "index": 0 - }, - "script": "4730440220413bfc424667bc34a80e58ce9c6d68b71c87ecbb33af5c4ac07697fc5a478d3e02201f62cdc76ff27807ab664da7a945e1ab14ddd68ba05a19035f0b486edb84d381012103a16de31da538ba5e6a898e7aec2100633438578d1cca07a6d09fbf228d1924df", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2979d3a427d4fb291aaf340d0825a538a89faa1cddd7743d23ac71abd798d90a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2780000, - "script": "76a9140ce83376b1facac4399b0bbb23ecd34e959948e688ac", - "coinbase": false, - "hash": "2979d3a427d4fb291aaf340d0825a538a89faa1cddd7743d23ac71abd798d90a", - "index": 1 - }, - "script": "4730440220469bb1dd4e91eb975896621bc7fa812bba770d9b9c7f1b68e503cea491f6fe1002201128167d697e3a55b41f727715fea67d9853882dabde32fd3e109547aa2d920e012103676a3b89cad4d66490c0449ec3ba11062fda2d6cb64ebc18dfe80ec9e70d7bf6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4200000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac" - }, - { - "value": 1113727, - "script": "76a9143df5347730ee414c9d4bd0f1197dc73c2cc81a9588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fd306868152c68855f6907cef165938a80db86a4e37f2cec1d9a3f1e3287db52", - "witnessHash": "fd306868152c68855f6907cef165938a80db86a4e37f2cec1d9a3f1e3287db52", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 374, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b363c86e178c71bedbfa13a10e57ad2c509684c2e6700dfbe49d088ce21af51d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2625000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac", - "coinbase": false, - "hash": "b363c86e178c71bedbfa13a10e57ad2c509684c2e6700dfbe49d088ce21af51d", - "index": 0 - }, - "script": "4830450220043a174b6eb03a64cff60f997c9ca81ab2251e3ffee93efd773a864ad718ae0d022100a7154850c8efae4fa272ab2b5ca9fc3c2f03c0d2cb0f2a3cb4e701708a52924c0141048372c61c205da3b5d1535fb2cfc18830af5f2ed8d06356657d514b47ee7b08bbe9265438708cef0c13738c52ae607c9e2cb6076697b7cea63b9e69dd1e98dd97", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c6b3298c1f18dfa15743f85bb3b7eedcb5f323542067cb6294451eeb14c38c83", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4200000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac", - "coinbase": false, - "hash": "c6b3298c1f18dfa15743f85bb3b7eedcb5f323542067cb6294451eeb14c38c83", - "index": 0 - }, - "script": "47304402204b97ac21f37b5b1de5436d57c7ed4b034288541306af6ee0dacc4cd032a20d4b02207775c86aa57234d8d6928c560c7a925a250a16eccd12acc70f566fc9e74941950141048372c61c205da3b5d1535fb2cfc18830af5f2ed8d06356657d514b47ee7b08bbe9265438708cef0c13738c52ae607c9e2cb6076697b7cea63b9e69dd1e98dd97", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1900000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac" - }, - { - "value": 4915000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6196df27275169d550a93bd2f364c83c4c61d4e7a3281109f122b0cbf06ce2ab", - "witnessHash": "6196df27275169d550a93bd2f364c83c4c61d4e7a3281109f122b0cbf06ce2ab", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 375, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "fd306868152c68855f6907cef165938a80db86a4e37f2cec1d9a3f1e3287db52", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1900000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac", - "coinbase": false, - "hash": "fd306868152c68855f6907cef165938a80db86a4e37f2cec1d9a3f1e3287db52", - "index": 0 - }, - "script": "483045022100b80f379fdfbf29681c40e5e6cff5ff8a39633391046545e2a1121db81e0e96af0220707072e60fc1aebfb5d7a1b99c7932f60ad19ce45aa1f627cde3a32562a7366c012103c78b7a24d207c3cdf4411fa2f7c36e2816471c17fa0a6bd46d4296d11fa060c9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10000, - "script": "76a9147363eacab96a7b0559009192b3f04fcb2af62b2d88ac" - }, - { - "value": 1880000, - "script": "76a914788de3e892875e1652dfdf9bf9677b84086e415388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9678b90ba885d3f1dc6141907e470756c62935a17ba8072c06b1d0eecd974528", - "witnessHash": "9678b90ba885d3f1dc6141907e470756c62935a17ba8072c06b1d0eecd974528", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 376, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "07387d5ecf34c7d6bdc886c759d8f919dece7d9eacac0ef26185ffc54ef77398", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2100000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac", - "coinbase": false, - "hash": "07387d5ecf34c7d6bdc886c759d8f919dece7d9eacac0ef26185ffc54ef77398", - "index": 0 - }, - "script": "4730440220663d67a2b52c1cac0f5d972ad46450f363a1b5dff74731c574be17b4ceb6b63102205109f55beafbcf041076eb7bbeeac2d534322a340c69e7a7a975bf5d68a9b70c012103afd34045d7080e5f3d8fc0efab187951caed4b06571c7cc617d01d9abe8b36b5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "088c77db73d9fb409a040417cb8eeb0c6f0de3271c1ffc24be2c56baccec4d5a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1180000, - "script": "76a9148b3c2ecf5918c1e4e6f019cf790eb54ad781c63888ac", - "coinbase": false, - "hash": "088c77db73d9fb409a040417cb8eeb0c6f0de3271c1ffc24be2c56baccec4d5a", - "index": 1 - }, - "script": "47304402204df38911acaafab4d7d18635e582ee95eefb49d6e7a05b04ffb31efe8378a1020220167577ab2a445427ac3025fe86553c1d7e9aff0096a468907a86b05ed2544b090121038c66b442ad6b314d4dc000be3c34353689b7f3355e56add76f73457a9bb91be7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1991d117785fc3ecc712de706828d17a80fd900f4ec25043014a7ee9b86fc465", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1080000, - "script": "76a914cdd6cbd410b70ecbca00b02d0f962b710a7fdec488ac", - "coinbase": false, - "hash": "1991d117785fc3ecc712de706828d17a80fd900f4ec25043014a7ee9b86fc465", - "index": 0 - }, - "script": "473044022027c1fae2654e94fcdb6b579597246bf8f60240b504c8f0b9371d0d0e6db066c602205f78dc17c66669afbe843ea86aadc4007aa769f12446c346237bdccabd3254b6012102e6b43d1e214b69683b25be7a393e0008727b47b84a16a4f6bd5250bac26b6463", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3675000, - "script": "76a9144cfac679e9a205c3d654815b6cab6445c52f5b7688ac" - }, - { - "value": 675000, - "script": "76a91417add6531a3e51bb5e5510f18b8933575d0e038788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "bfec0f882068ae83f87ee0a99d5b3ba241710460183fa4f319b537d72fc98613", - "witnessHash": "bfec0f882068ae83f87ee0a99d5b3ba241710460183fa4f319b537d72fc98613", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 377, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ba38a77e49f1b30633d232d8c2b58cc9a33995bf04e8fd9bf401313cdac825d9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 12828608, - "script": "76a91498f75bb86fb906805f189de0fdff60767336c44e88ac", - "coinbase": false, - "hash": "ba38a77e49f1b30633d232d8c2b58cc9a33995bf04e8fd9bf401313cdac825d9", - "index": 0 - }, - "script": "47304402201aa9897801ab7c569937b563f4dfc21d58354382e8368c3e7451e6a71f1e5fab02201e505bde82b3bdfde68b8c09777af39e25ca81b2ade3f364ea7c4e0f124a5bab012102139dd251c92fdc687190f513e2080bcc70078fa4a6a897bd22ec1fb9e7e3d1b6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d3320aac850774b8e0cbcd5a643aea945e2c2f81c549cd1e1930c3592e6fe683", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 17520654, - "script": "76a914a6219ebe2a09ed27774b29bc9ce0ad66f3ab2cd388ac", - "coinbase": false, - "hash": "d3320aac850774b8e0cbcd5a643aea945e2c2f81c549cd1e1930c3592e6fe683", - "index": 0 - }, - "script": "483045022100ff8ce78cc887aa9ee9873bce315f83293aaebefb6c88af939857a5d24b78673402206fb841c16c9b74db79dc9b36e8a7fcfd4e7814565e5847180e30e8b970bd8b2b012103e28a7f639fdbc5a2d98782d4b461dd7bff1238a7f0aab91c4dc69ff2caeedf60", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4da221b3c75437b1dc283978eb938542f2ce07689078894b287862e5af4dc6c8", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 2134765, - "script": "76a914340ec7c6c55382eb57a989298a2bb00b9bfec54288ac", - "coinbase": false, - "hash": "4da221b3c75437b1dc283978eb938542f2ce07689078894b287862e5af4dc6c8", - "index": 0 - }, - "script": "473044022012d09833d2a5cb926c94b3c49e5ee7b8ee4f5d3352f7b315d64b170276133e13022019c07f5f7cf6f02dcf292f5e5d71e373b3cfd892251f0dbdfa8503aef29edbf2012103cb89cdbb0035b531fc97f46d53978e037959ac8c0e801bd6064657354be03996", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1300780, - "script": "76a914131079f3df589c4c8b2e473bd3f4758f6ecd967788ac" - }, - { - "value": 31173247, - "script": "76a91401c3ac995c0c7ac126e42cc0c0f83831f5e5e0b988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cc6fc850057bf7ecc25a2a8150d3696321895cb4d18b0a0509440bb4c02f533c", - "witnessHash": "cc6fc850057bf7ecc25a2a8150d3696321895cb4d18b0a0509440bb4c02f533c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 378, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "92c3d38654f4eedb7ef12f9d65d4ffe0a88611f9a8a3598c228d2a28a1d1ca41", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 33806243, - "script": "76a9141ea0426701ea21acd2c506cf73c487df87fb079288ac", - "coinbase": false, - "hash": "92c3d38654f4eedb7ef12f9d65d4ffe0a88611f9a8a3598c228d2a28a1d1ca41", - "index": 0 - }, - "script": "483045022100edf9c3590511749f036530fab19239afdffa4cd713da3c98dd5f96956e1a62fe022038e0c30c906b123c7996a9484182f81283e5ffa8cb24b989f26b5c6b0c9dd36c012103e8d00a52bd78a6ddea33911254588ab6fe9ccdef92fba69acf24ffd9c549ad56", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cd88f498f3f0dfee8231e353b711a7eee17f55eaf20ff0bf653aecc1bea33450", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 69253333, - "script": "76a914a0998ff28967b718d895a63e633535be525024d988ac", - "coinbase": false, - "hash": "cd88f498f3f0dfee8231e353b711a7eee17f55eaf20ff0bf653aecc1bea33450", - "index": 0 - }, - "script": "47304402207ad7682256577daf9a34893d71acf2a1950f2bfe465ebf6a1b7d8302d700225c02204ee106df4e487fabe5b8feab99b258be3d619d38b1e60728a212dd9e012adee8012103e5999decc57972ba68821734ba71002f7c25e7e02ca9ff64632700725f382756", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0b3ec64a91f7c379ee23225d4b782bbe25323dbd4f525eef7b5011adb8532d41", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 9478934, - "script": "76a914d28ced1ebb1fb1a33a4dd7d15900a9355601a89d88ac", - "coinbase": false, - "hash": "0b3ec64a91f7c379ee23225d4b782bbe25323dbd4f525eef7b5011adb8532d41", - "index": 1 - }, - "script": "47304402200eb7e814e112264c546271059a20e415e6dcfcf53cde33562472a0926aee1b7d0220434bb1d0b295c4c3b906cf053dc2a02e5c0e17458e18bbdfd50c04445186031401210287ef83f69ef662812799f509a1888fde55c018c9b3d76c77d49c6e6631f9a7fd", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 109990000, - "script": "76a914795bd8d7b8af78b24f62d09d0d4cfe26f7fad7ee88ac" - }, - { - "value": 2538510, - "script": "76a914f98d5e49b82c4ad384239efdceaaaa3f6fd6555188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4de5ba2d4d06cbc1d4feaad87309646768829c6a1680b5e9fcccf115bdd124dc", - "witnessHash": "4de5ba2d4d06cbc1d4feaad87309646768829c6a1680b5e9fcccf115bdd124dc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 379, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ad1f912113a902413e4840c85bed595658facaf90e96b3d0cdde85f5b2ae7e29", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1500000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "ad1f912113a902413e4840c85bed595658facaf90e96b3d0cdde85f5b2ae7e29", - "index": 0 - }, - "script": "47304402206a471d8b0eb9c8000f9b104230c0a2a4466ddb58da1bb1efe0edc625af0fd1d40220338360e452694319069647297b3155a36fbc5fdff90d02fbc7e471aa7b854966012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "356595ae408e69233079e0b375b539a9ac41e0aef5b7d185996a57f7cffdd039", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 136509, - "script": "76a91417add6531a3e51bb5e5510f18b8933575d0e038788ac", - "coinbase": false, - "hash": "356595ae408e69233079e0b375b539a9ac41e0aef5b7d185996a57f7cffdd039", - "index": 0 - }, - "script": "4830450221008a9deee7e7e5e3f2ca8703ecdee54b896d02d9cb93f15244e3401d48de3a778b0220792351d5d1a1139f1738ec90eeb20c189a884e6693d4eca0b758385b593db720012102cf94f3a2d2b9740c23b538f316aa83c4843251dd1d2d2d554d81162103271282", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "36542389072b94bcd06872cdab7753ebeb1410a11d219c142aa7d680f6f80f97", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1680000, - "script": "76a91459ab87f2518ef5916684a0c13b30d234e20ca35d88ac", - "coinbase": false, - "hash": "36542389072b94bcd06872cdab7753ebeb1410a11d219c142aa7d680f6f80f97", - "index": 1 - }, - "script": "47304402202bfe2aff98d4ab177912442d2d239e6ca2f3ecce79be58703b9a971d57c3b93e02206b42880c1e7e2e247b5f6f844fcb11a493c802f04a46518f4fd41a5a2ae8e420012102192c62062f08ebbf621a1dd691e70ea2404759abc1d0192a33b35a39bbeca87a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 681509, - "script": "76a914f42f924dbad1de266f02d1c5054085a0527da61f88ac" - }, - { - "value": 2625000, - "script": "76a9148444e446b0e0b673a9df7f9f141b1d69673c701488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1f6f4156d701061c4e6175f2c2e042fe235e2f9dcc5a4cb4d09b39864ec4af36", - "witnessHash": "1f6f4156d701061c4e6175f2c2e042fe235e2f9dcc5a4cb4d09b39864ec4af36", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 380, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2db268abfc2f8316b4b1b890fae958c81cc99f1817dca68fd83f03041514b2d0", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297086, - "value": 1145130, - "script": "76a9145e296eebeeab44195de2443b44c0c99cb32e733888ac", - "coinbase": false, - "hash": "2db268abfc2f8316b4b1b890fae958c81cc99f1817dca68fd83f03041514b2d0", - "index": 0 - }, - "script": "483045022100c5767f7ada65ffebdd53c36eeba434bb2d8cb4c58d865918aad77bd0d1d5e49c0220043dca9e386e8a9179a85b1362707486db438b392045007abe04f417bba6d2dc012103e7ecb2a148dc071d8c4661ab5d7f583a97d44d6a86ca84ff97f17cc5c16ec911", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7095864550aedc5ee5e580f2d4a6c4e95205022d9b6414177d1bea1376e430ac", - "index": 49 - }, - "coin": { - "version": 1, - "height": 294076, - "value": 20000, - "script": "76a914428464d37e24a0b866b50732f4a9636bd7a0161788ac", - "coinbase": false, - "hash": "7095864550aedc5ee5e580f2d4a6c4e95205022d9b6414177d1bea1376e430ac", - "index": 49 - }, - "script": "473044022024546dadb60d87301c2776cbfef03ac46f8b560f1900428460877b45c1ca750c02202b6a5009de73b90535823e83260677833f679c0e85a7b60d9ee921ee79dfb8f3012102f63b754491e2df8e0b85ead46172da16d1945cbb4220d56105a9537dd7952bd2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e2747a62df274fb63474098fdfbd7a729b45e7ac3fcb2bb54e5d41d9835301ef", - "index": 0 - }, - "coin": { - "version": 1, - "height": 292945, - "value": 122868, - "script": "76a914428464d37e24a0b866b50732f4a9636bd7a0161788ac", - "coinbase": false, - "hash": "e2747a62df274fb63474098fdfbd7a729b45e7ac3fcb2bb54e5d41d9835301ef", - "index": 0 - }, - "script": "483045022100d070ad1ef0e9dc7fc1bf0f9f3c682b01c363ce36fd5c59b8c4925b06f09183b10220535bb6a2f08c2ab0615e0f329e39eaa70ad966000f12289db9661680b2ac0ef0012102f63b754491e2df8e0b85ead46172da16d1945cbb4220d56105a9537dd7952bd2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 277001, - "script": "76a9144f7ec7f9a11e61eefbb8292886f8e1d5b71c4e9688ac" - }, - { - "value": 1000997, - "script": "76a9148a1ec8b5fff50cac1ad90368ce3add65567e3b9888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "05364c74c9b04ed51e20cc48438a6768a25c675dcdfd1a3fc461604ac38e8fcc", - "witnessHash": "05364c74c9b04ed51e20cc48438a6768a25c675dcdfd1a3fc461604ac38e8fcc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 381, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1f73b122a46db62446165a5939216107c67556e0041230c6c217c5bcbb1ae35c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298793, - "value": 773675, - "script": "76a9145b07f7114832a5c0b2d75fcc1384ef45cd1ad1d688ac", - "coinbase": false, - "hash": "1f73b122a46db62446165a5939216107c67556e0041230c6c217c5bcbb1ae35c", - "index": 0 - }, - "script": "48304502210094ed67747a11b7028179470cfff80a144b774ca0409e96cab6c5f3536c7a3d27022030bf21e22494faad91d7dc90ecca3585e016181896f6ddd14e2cb9d0eeb287b2012103d0acd72d105abdf40a2c90f024fc6f7b24d2f50812229d014415e0b5176a175e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bd9fe10a3156ff933dabebc8af4907db2f09262228328b7193f9c358646ba9ca", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299723, - "value": 3084665, - "script": "76a9148c984e730b3c768c6fb2d9fd2887eb37b024984e88ac", - "coinbase": false, - "hash": "bd9fe10a3156ff933dabebc8af4907db2f09262228328b7193f9c358646ba9ca", - "index": 0 - }, - "script": "4730440220537cb6ad46c2474b93bacb720f058b124e0bf1808ab27181339df3d7414d4cbf02206bb2f317481a99d686bf37ef8a1912615c6158c4af4b07f65d6f5ef74102144401210338bacc443f5993f5f5e9c75a04f4a985de1348ed43df0ffb40ec32173d365e11", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fa244b5c2ee33e2b71ed0203fa736f3fc73bdd9c33ee6730cb43df2c1193adb6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299586, - "value": 2565675, - "script": "76a9145b07f7114832a5c0b2d75fcc1384ef45cd1ad1d688ac", - "coinbase": false, - "hash": "fa244b5c2ee33e2b71ed0203fa736f3fc73bdd9c33ee6730cb43df2c1193adb6", - "index": 0 - }, - "script": "483045022100803b2258205d1749defd76452e1903e7c302747a813219e95fdff80a86e441d202202bada0b9afb8378ee40cd60138e95b2f845d5d69856e74cb7a346b52c4e80a5b012103d0acd72d105abdf40a2c90f024fc6f7b24d2f50812229d014415e0b5176a175e", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6080000, - "script": "76a914e70b1dc0ca9fd59e54f80e3b5d7e3421d84bd67388ac" - }, - { - "value": 334015, - "script": "76a9145b07f7114832a5c0b2d75fcc1384ef45cd1ad1d688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "19d3527f7b8630a37044cbfd66f080d310951f1171eca8d22c61a2b75d430b3a", - "witnessHash": "19d3527f7b8630a37044cbfd66f080d310951f1171eca8d22c61a2b75d430b3a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 382, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0f53aaf128623a5173402c20f4f3cd034f9f73545abce470a623d4411f765ba7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299733, - "value": 420572, - "script": "76a9140a2db4c4f396059f12eb4a741a5db9717446df2588ac", - "coinbase": false, - "hash": "0f53aaf128623a5173402c20f4f3cd034f9f73545abce470a623d4411f765ba7", - "index": 1 - }, - "script": "483045022100c59dc4b17fc561116cd78660c4ed37125cb1eb23270369ecb1d1149cc98e283a02203d3ec51e9ded564cd8bb28472e616311bc982f518241531b66a9f7feb92cf7fc012103bfca9490aeab5010090635f88588e433c830f09e3e1d9684155f30cfc71f8556", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6f108220e6ccf8418736457cc706d4b8757093c7b867efe815796184c58ceac2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 550000, - "script": "76a9148dd5db43482a7df52ebbae3af4e005045e29e0c588ac", - "coinbase": false, - "hash": "6f108220e6ccf8418736457cc706d4b8757093c7b867efe815796184c58ceac2", - "index": 0 - }, - "script": "4830450221009de3116d77723d784c4334505c59497d077fc92aaba2ea6cfc3ae7dc0ba487aa02203f67dab4f04b6a111f8dd723fe113759d77918944f2206d80d5da2003957c836012103063ec131a7d2f917b506853cac277ea3958f4170b77bfb422df410611eaf856b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0ca1cd37cf05aac26be3e739b9443bce1b815fd0ddec1d2db712c78817ca6e04", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 540000, - "script": "76a9140d4412bfcbe01246d6deec6ecf8f0ccfe8d0d2e288ac", - "coinbase": false, - "hash": "0ca1cd37cf05aac26be3e739b9443bce1b815fd0ddec1d2db712c78817ca6e04", - "index": 0 - }, - "script": "4730440220796c74b1f09625e3105b4967cc5ff8967214e9024220c4898f4cd26419ff04f602204378412e975dc426d11fffc7c1712d1276594f51020ce022949cb915806eb463012103c6c3164e66de4e236409d30a9e6a78df28750d7aeaf7a79b225474a9fabadc61", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000572, - "script": "76a914c426803960e08d50a8d07590fe1be6f24477c5a788ac" - }, - { - "value": 500000, - "script": "76a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ccb8d8e14361594cd1664b9ee8c39d2cacb6429a89e4f33047d4c2cc22873aeb", - "witnessHash": "ccb8d8e14361594cd1664b9ee8c39d2cacb6429a89e4f33047d4c2cc22873aeb", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 383, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "19d3527f7b8630a37044cbfd66f080d310951f1171eca8d22c61a2b75d430b3a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 500000, - "script": "76a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac", - "coinbase": false, - "hash": "19d3527f7b8630a37044cbfd66f080d310951f1171eca8d22c61a2b75d430b3a", - "index": 1 - }, - "script": "47304402201db57cc83fa1351bd475740b7e1ed2ce670a8c4d3cf957f66ddcd2f39a95646002206f5e5d29a984b6ecf7e45a68be0cf7049036e480ab7458955b9bb5a49efbc824014104da6bc6a6139bb008454bfc8371141a5fb8ba6de87e9ab1578ab4c31e1b25513d6d1b1b0e66b0e39a29f6baf19f9f0faaf51d22bac02b1c07eb08058498763784", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 190000, - "script": "76a9140a2db4c4f396059f12eb4a741a5db9717446df2588ac" - }, - { - "value": 300000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8390d6bb1e04d11042412285be5fe0921ef9c2ec9cc579d403510a794fc0fb8d", - "witnessHash": "8390d6bb1e04d11042412285be5fe0921ef9c2ec9cc579d403510a794fc0fb8d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 384, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "70ab3e4c6284233ad8f7b713186221aef2866b4b0c802e56c63c16fdbd872260", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1004181, - "script": "76a9146034bcda63975118f9f2f5f93e8f6a31519287b788ac", - "coinbase": false, - "hash": "70ab3e4c6284233ad8f7b713186221aef2866b4b0c802e56c63c16fdbd872260", - "index": 1 - }, - "script": "483045022100eba4624669efecd12d556068575260753d7930c704d1088ad839a74b5182bc03022004f177b5901fb1347c2988b07804b63b7989da03f26c248fe095ec1ece59d3ff012103eb974d0f3bf503ac33c16b3cc0b7f53f465ef577326e74b95ab94f4d86a205bc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8c128ea57e9367620b6138f0a77ad68209479ffc4ccef3b226b1449a5a35e304", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1990000, - "script": "76a9148e01074be3f9e82f3c537693beda79a1fd15e5b888ac", - "coinbase": false, - "hash": "8c128ea57e9367620b6138f0a77ad68209479ffc4ccef3b226b1449a5a35e304", - "index": 1 - }, - "script": "483045022100d6ba42b7a2b9eddaef67583bb657abb454b5c462427a080e73af820da621ad1f02204eda7097d79e1eba710b5eb2d7987d0454120c6064200b217673d67fb6ee8c6b0121020de0998f4f812dc32226cb0243728025762d0715a0fc5db41bb88824b04bd634", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1d395b03730e9e6e4d959fb7a365ed43e4a062a63ea51395301f9b329e17ce06", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1474435, - "script": "76a9149bf549bbe4f62b0fa6b299ef152d600543920d0088ac", - "coinbase": false, - "hash": "1d395b03730e9e6e4d959fb7a365ed43e4a062a63ea51395301f9b329e17ce06", - "index": 0 - }, - "script": "47304402202796c528d97343610fc151fa705299ab7c3c75a8aa1521b9bf3db5b136b2267f02202c3815586509211c853ec9013ce4f5a049be9217c417d49e72fc905cefc7558f01210343612c84b58199cf04731e4dbaa1e8b062afbfa449652c7d58ace7bc92e5128f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3107500, - "script": "76a914fa38554efae9f068a6d6346556e89520c75e990d88ac" - }, - { - "value": 1351116, - "script": "76a9148e01074be3f9e82f3c537693beda79a1fd15e5b888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "eac7126fe68802d1c966a78b89c0119ad3593e2fadb735f0652147f0df66bd60", - "witnessHash": "eac7126fe68802d1c966a78b89c0119ad3593e2fadb735f0652147f0df66bd60", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 385, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0c4884af71ac4d81fc6017701a7cd8a129cde30cd9fdfbb097099b1ef98796d7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2300000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "0c4884af71ac4d81fc6017701a7cd8a129cde30cd9fdfbb097099b1ef98796d7", - "index": 0 - }, - "script": "483045022100a71a2b40d89ec07bd1fcfc09d1418eb7cf8bf4e2482b289d688e9782c5b492f1022000de4c0befb85776740fc55ec9aacdaeb4297587027ad36f34d1e8c76bd3d836012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3b445c9e30764600ebbc5d911caf90bf336c251be613d15d4833fcb892db1cb4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1270000, - "script": "76a9140cc7a4cb0d42a97ad29cfc0a49f955d78bd0362388ac", - "coinbase": false, - "hash": "3b445c9e30764600ebbc5d911caf90bf336c251be613d15d4833fcb892db1cb4", - "index": 1 - }, - "script": "4730440220039c670497871fd150f0643c881fd81329676bae7a0c00fe1cc82365f07cacee0220631f783726c401c9cb48c27a582c4fa97132cec04eb0f4ae57f2b18a0d6d72ad012103a16de31da538ba5e6a898e7aec2100633438578d1cca07a6d09fbf228d1924df", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3cc2a285c3dd5db916f6d67ffff2a556504d8524a51a88e87b93576fb4a52abc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 2780000, - "script": "76a91438bb181091ee71cc4a0259dc2fb43dc01622d71888ac", - "coinbase": false, - "hash": "3cc2a285c3dd5db916f6d67ffff2a556504d8524a51a88e87b93576fb4a52abc", - "index": 0 - }, - "script": "483045022100ec99aa96e8819e5e5534655823973c058aad9ea85d699252d0da95cdbc9663310220186d9e51c22a21d95122e6443798fbdb9fa5fd4b3b926eef42283e9969e382c00121021937f42a76525fe8fb3b593afa27ea24df13f0975dec3dc209e5ae0fc5072f3c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2315000, - "script": "76a9140ce83376b1facac4399b0bbb23ecd34e959948e688ac" - }, - { - "value": 4025000, - "script": "76a9145e93e0f7f835cc5c65d9f6c064b81767a2596de588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1a6377f2d7ac370f0d038971903e8be4de8e4dfe5e80400d766bdcbfe55f370c", - "witnessHash": "1a6377f2d7ac370f0d038971903e8be4de8e4dfe5e80400d766bdcbfe55f370c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 386, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "38ec7f990aa7079bbcba2f1de076eb4db81f4550e5e41fb717a021d7a94e5058", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299950, - "value": 14637843, - "script": "76a9141cfbc11b6f8dd6a96f219a4f67914e32c1907df488ac", - "coinbase": false, - "hash": "38ec7f990aa7079bbcba2f1de076eb4db81f4550e5e41fb717a021d7a94e5058", - "index": 1 - }, - "script": "483045022100a8de7f562b6ec659682e2d956bd29a3d9361a848b8d2979195346979377ae8750220259a92182be94ba22ac58a7bd106e9ee73bae4c08e8e40bad7a84e6257a92c4f012102c803c70353d446f0512eaa8836d60470193947fb94a386ee3281c5b6ec6acfe7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d16d23ff484b99525f4874f00c2720d3211d902a5d62e77287a2532856eea7ea", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 5000000, - "script": "76a9149cb5ab4346140ebd9d42f08f3070d8011c94fbb988ac", - "coinbase": false, - "hash": "d16d23ff484b99525f4874f00c2720d3211d902a5d62e77287a2532856eea7ea", - "index": 0 - }, - "script": "483045022100d977c7364b9e643f9910b5cd33e04244c8815dd61b7666f88cf3f3210547b8f1022022c7917d343dc3c6f8fce020a571686edb7fc8d2557beb88aed12a189cd729fd0121020215dbeeec00df216b679efde72e054243fcb561469fa8bdf4d3237553a61020", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "87d4ec5c9ba433202e46243df9d382031fd71c521f1d3b95ff68d0c538be29bc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300009, - "value": 25000000, - "script": "76a914e5c06b0c04637c96c40b86012b8104fe56ac896988ac", - "coinbase": false, - "hash": "87d4ec5c9ba433202e46243df9d382031fd71c521f1d3b95ff68d0c538be29bc", - "index": 0 - }, - "script": "483045022100ecb3a7d632c39b362632cc52aff9b8bdfa6dce61464b017561c1bfb16790516e02207271167ad9f1e0e2be0045292707f824a47e465f1e91a4b8954b1cd2b0f2f121012103850e0db0113b89154d366fe4d9dd62f46d8c60914ca243ec9582286b3474df81", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4677843, - "script": "76a9142d6f073b78fc50e25c47802ab93047b32e57ad3c88ac" - }, - { - "value": 39950000, - "script": "76a914d7c51041c0b572bbe424dce395d8b400de4e8efb88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6f9511cbec63e6fe8bf0877572d0230c809d03fbff74f1038c7c7494c25d1776", - "witnessHash": "6f9511cbec63e6fe8bf0877572d0230c809d03fbff74f1038c7c7494c25d1776", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 387, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "719a3d43412965ec50c91adba3b0756cf594480268ca92d442f97527a12482f2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 190000, - "script": "76a9146e24f8d88925eeb0457df7cfb968118cc31e1c2788ac", - "coinbase": false, - "hash": "719a3d43412965ec50c91adba3b0756cf594480268ca92d442f97527a12482f2", - "index": 0 - }, - "script": "4830450221009ca183049694409ccc664b40f3df33837c491313366d0cf5bf3ed681f7003e00022019750a8e0148395a1bf62c008080c8ed7ee9bc16100eb7c71e85ef5b99f94f10012103a6d0b315a938d846b56ea32e7452e4770e376fc9dc87bc61b3570015ebb2d754", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c3c7064a893895f86d177994e7cea2b5c8044149eeaeb2de29b45a8a87a69797", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 790000, - "script": "76a914148e5773ddf8d376d8976b4f877641aa8bf2c46888ac", - "coinbase": false, - "hash": "c3c7064a893895f86d177994e7cea2b5c8044149eeaeb2de29b45a8a87a69797", - "index": 0 - }, - "script": "483045022100efdf49349bf0065b297ea3746fd87e0bca59a44c188e2aba707a971260288a0a022004076498588f9ee23b159c16cb3466820dd905618252cce6d03f92e53887ada1012103072bb08796f38bc30c1190c82cd4cbd15ad597b5a65dd863edf764e453338145", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f510aa80811dd8b29de49b1c7ce74a28648d6bc2bdc3e65ff15a34a26fce5f63", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299730, - "value": 550000, - "script": "76a914b0145ac7cdb7d8cb6098565836f160864ba3ab9b88ac", - "coinbase": false, - "hash": "f510aa80811dd8b29de49b1c7ce74a28648d6bc2bdc3e65ff15a34a26fce5f63", - "index": 0 - }, - "script": "483045022100e81b0538e6a6d1d5bef795264eeee794476693856c695ddc3d0feb25105d9c27022065678d9dcf63a6c187b8f49be997bc5fb7da7dc30cc9e74131193ca178d4f0d9012103a6f96febceac23b0ccc4bd653189ac43bb0a08fbcf63097cbece1c34456b175a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 400000, - "script": "76a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac" - }, - { - "value": 1120000, - "script": "76a914434760f16030d21cfac0386098a96111fc948bf288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "375b170205148fcc644702e0d124511fd8b2757d3cb84b75f439ba59a631b3f4", - "witnessHash": "375b170205148fcc644702e0d124511fd8b2757d3cb84b75f439ba59a631b3f4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 388, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6c60074b32bbda15c6009a3349a3eb2439c120c12c9c1022dd5cadaf9bd45fe9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 1153214, - "script": "76a9144fbe75d017a876272793739f7fc26c0cacfc4e1c88ac", - "coinbase": false, - "hash": "6c60074b32bbda15c6009a3349a3eb2439c120c12c9c1022dd5cadaf9bd45fe9", - "index": 1 - }, - "script": "483045022100ae6d591380a67ab5c3c43a53cd4404ad3dc5041870282d31f60a6fa96fd73cc1022003373a78a1e115204b2e9eea5cb2da7622e92bf8e063beb8f542c84cc9af56ab0121028ef4b723e65c623113de23f08d96050d16fb2cbaed363e51ed7fdaf18ba95a4a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "91fbee07653d38151b3ac628624716c7ed0822245335368b4cffdafdfddba2a4", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 900000, - "script": "76a9142884d9aaeae23dec849e6dfbca011de267f2da1788ac", - "coinbase": false, - "hash": "91fbee07653d38151b3ac628624716c7ed0822245335368b4cffdafdfddba2a4", - "index": 0 - }, - "script": "483045022100d8d1a07ffd355129956286477da978073191dc338ecdcefcb7287334abd69c36022045c5defe2e76be135bace7327dc9fa0a2306973292bdb3e26ce221fadfdf38a80121022c3ac8a323d42bc8d07944d72a64cb649d9ff4da9442c09564abf778b53bbc91", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "91fbee07653d38151b3ac628624716c7ed0822245335368b4cffdafdfddba2a4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 1090000, - "script": "76a9145b9211b1b81fb40924b49d91e412819488842a0788ac", - "coinbase": false, - "hash": "91fbee07653d38151b3ac628624716c7ed0822245335368b4cffdafdfddba2a4", - "index": 1 - }, - "script": "48304502210083a00a16da3ec25ba04a369b4f5a0ed021449c3aa4699b822d04bb25fb29d1ec02207eedb88cfa5a9125142f9c6830582c1ef1ddcd97b94884ecf4695732382840f401210399c99b7a9d6348e07236777e1961ff6bc03603cbc8f97cfff029b81e8be691af", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1800000, - "script": "76a914387dd1595941f6ace550cd32d967ce3770f2539c88ac" - }, - { - "value": 1333214, - "script": "76a914481cf7e3fc5e01e1025b0e01ed3cd81e4363762c88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d8b50a8a188e5863b06c3e8d53bb4080f76090aa40acffd440ea9b1e74e0e135", - "witnessHash": "d8b50a8a188e5863b06c3e8d53bb4080f76090aa40acffd440ea9b1e74e0e135", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 389, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e1e441194192161b687d5069d3c8aac0749b1c4fb4ae634d5ead0af4c65ab1f8", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 1000247, - "script": "76a9146f0acdad5237523f9a051a39cfa1ad9498bab81188ac", - "coinbase": false, - "hash": "e1e441194192161b687d5069d3c8aac0749b1c4fb4ae634d5ead0af4c65ab1f8", - "index": 0 - }, - "script": "483045022100e1b3eadea81b8a1f0c23709fd09efe8bf8d32033ea9a827b0ffe4d2704918c50022076cc620eb5cd5e4d18e5021c2775cac996727ee322bd9b22c4e411da5b85735d012103f179fea07aba0dbab938acac2a4fd1fb3ae2476d561d8ed5862ac301450cf183", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "43d7790452acbc4b3d7dfc8bb3c5284dc4b10b27119f02360416c3c4e4a389db", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 1001016, - "script": "76a9145dbe649ec241dae9a348610ae8b9972da57c4cfe88ac", - "coinbase": false, - "hash": "43d7790452acbc4b3d7dfc8bb3c5284dc4b10b27119f02360416c3c4e4a389db", - "index": 1 - }, - "script": "483045022100ee647c454457cc9de67a42f7e65d944ee35202022365bbbc6bd278820d873e39022035f0485a51b712618b8382d63a9832928484a7b98fa6e224a92976879da0dca70121036be4fa371f2277d8a461525a88323419307dc96af513aeabbff8024857e28e04", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a799e89deb5c75b5027c2d2ed1412ca6501f6dc0bb48f963765ad7981f53ff71", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1001838, - "script": "76a9140caa9417187dd3e3ef86cff8d43c95f2a715330788ac", - "coinbase": false, - "hash": "a799e89deb5c75b5027c2d2ed1412ca6501f6dc0bb48f963765ad7981f53ff71", - "index": 0 - }, - "script": "483045022100f48565935e3da89a95b397991818d720e0750df2c70999c178f4ecb753e610e1022022fb5257afff21e5ee6eee6ff09ecef4e5462be59acd28907161372972aa48f8012102a7cfe4e2bbb305a6bf3afecdaa903efb9c00456122bdca630e2238d8d25d135d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1756207, - "script": "76a91466b739bd6881a2dbd488456bf6a60b9641732d3788ac" - }, - { - "value": 1236894, - "script": "76a9148f81d0ce181b69211668085886f6990c4dfd7eb488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "21d57c6f0cf8125a35bb0aa8620213ac5256d44ce2b0d65b4a1220a1891b2e2a", - "witnessHash": "21d57c6f0cf8125a35bb0aa8620213ac5256d44ce2b0d65b4a1220a1891b2e2a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 390, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e710ac6ab29d72f7a1b39668209ffa3d0d7b8c762438e36b45c55584edda5b21", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2200000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac", - "coinbase": false, - "hash": "e710ac6ab29d72f7a1b39668209ffa3d0d7b8c762438e36b45c55584edda5b21", - "index": 0 - }, - "script": "483045022100dbdd1d0fd7c54fc9c2cad284402334732831a075d932ff707b503b57550a599802200186598401de51cc171b85012c52bb92fa900547bccfaa8218f5b7fca8a9290b012103c78b7a24d207c3cdf4411fa2f7c36e2816471c17fa0a6bd46d4296d11fa060c9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39384880ff17bfbc3ef9d1cf297b6f97f0b79f95008960cea9940e741a65143c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 262493, - "script": "76a914cdd6cbd410b70ecbca00b02d0f962b710a7fdec488ac", - "coinbase": false, - "hash": "39384880ff17bfbc3ef9d1cf297b6f97f0b79f95008960cea9940e741a65143c", - "index": 0 - }, - "script": "4830450221008b4c804294469fbb29623f920c2017de20f1fdaed8dbe9c6b3ee452aa0816a4002204c5d52643ebe0d14da2793ef8e7c7e6232d7c4e88bfa29f04f06f5365829eca1012102e6b43d1e214b69683b25be7a393e0008727b47b84a16a4f6bd5250bac26b6463", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3a78dd5632aa5c706f6f082c694c3b68536765a7dac07ba71eb75733c5db64ea", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1680000, - "script": "76a91459ab87f2518ef5916684a0c13b30d234e20ca35d88ac", - "coinbase": false, - "hash": "3a78dd5632aa5c706f6f082c694c3b68536765a7dac07ba71eb75733c5db64ea", - "index": 1 - }, - "script": "483045022100aad03daf9cd1df8c3e47838a2f8d15079b323ac58cf964466029b568eb4708bc0220391f8461dde37f937e3a3f1f312caa8676e3bad8f58eb85610ab12dafa0e93d6012102192c62062f08ebbf621a1dd691e70ea2404759abc1d0192a33b35a39bbeca87a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3080000, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac" - }, - { - "value": 1052493, - "script": "76a91417add6531a3e51bb5e5510f18b8933575d0e038788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f9736d135dcc43f318df1edcb661a161509f309d23f86585cd125f08c4d23fff", - "witnessHash": "f9736d135dcc43f318df1edcb661a161509f309d23f86585cd125f08c4d23fff", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 391, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3ae96ed7dcf039b0f99e4a1412cfcf173ca9a402bb83b2a5dba8063a41231076", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 80000, - "script": "76a914481abefcdee6df84d9452b866dbe1cb696574c7088ac", - "coinbase": false, - "hash": "3ae96ed7dcf039b0f99e4a1412cfcf173ca9a402bb83b2a5dba8063a41231076", - "index": 0 - }, - "script": "483045022100feb60003f053972d357f21a42764ea55f087d0b302d17989a0e271b5d1389bc6022041b9db06bf86fc3cc9933a53eec4907c15f2913318ede3c05d6ed7f9d5a3f6140121038bbd3214f644fcdba1532e644373bf6aafd6385f76757536dc8f4f06a36a91d3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fbadb361a0d96738184659e802a9b2c64579bca34394d5fd9d5457822690980c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 180000, - "script": "76a91489632368cd5145406b32f7af02e97b51966f48e988ac", - "coinbase": false, - "hash": "fbadb361a0d96738184659e802a9b2c64579bca34394d5fd9d5457822690980c", - "index": 1 - }, - "script": "483045022100e402fcd2dd8376139b6589d5e0f8d05c64b11557bbec1ac5521800a33870474702202c3597802a5814b919cdb495bdbbc28fa58e225138e1214b8cbfaecf7ed106ab012103e61f3cc2ebfbbe7db7ba79ec27bcedb3a532ef5a5eeb5bc3e8b279fc19a5a6ce", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5c92531edf7b441ad27e876afcc0252aed04bde4b481833a03a9c95ab9df392e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1170000, - "script": "76a9143a3c573b1f2da608c4c1cb97cf8a6401b532735588ac", - "coinbase": false, - "hash": "5c92531edf7b441ad27e876afcc0252aed04bde4b481833a03a9c95ab9df392e", - "index": 0 - }, - "script": "4830450221008ebd19f2a634eb45ae08426026722f30051308f850161db81e47a0c0927bf59d02200ed64859e15a9049611aceaa94424f742d92c14127e2620214c56b27d2d3a1e901210358ba9b9a30ef48229cbb18ffeaa12ce64b9bbf15e92615944326c74fd1621c48", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1020000, - "script": "76a9145958b5e1e2bcff8f6f1076b3289dbb98b81920f688ac" - }, - { - "value": 400000, - "script": "76a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6f243746bd2b4e4c98e482da7fcc91f6f7f5d45a835a586d0c9295de45434e87", - "witnessHash": "6f243746bd2b4e4c98e482da7fcc91f6f7f5d45a835a586d0c9295de45434e87", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 392, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f9736d135dcc43f318df1edcb661a161509f309d23f86585cd125f08c4d23fff", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 400000, - "script": "76a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac", - "coinbase": false, - "hash": "f9736d135dcc43f318df1edcb661a161509f309d23f86585cd125f08c4d23fff", - "index": 1 - }, - "script": "4830450221008a90df42195c72480a510e14fa2a88456a13e90bdc5da37999a649b7515e0ee802205b70c4d3463b047c9be937f92efa39d7c746f6facb0dc44784abde1b7bf233b4014104ccc493c773ed7b190fd3fec0fde94df66605923b5ba6781968921e3f7c86060f62799e085a6873cc5dc1592e99a9090951cad28102cb920da361944d1a827916", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 110000, - "script": "76a914481abefcdee6df84d9452b866dbe1cb696574c7088ac" - }, - { - "value": 280000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1222410d68f5e956b43a5c7e5bdf90741c6debd698d09592dbf8a132e204f208", - "witnessHash": "1222410d68f5e956b43a5c7e5bdf90741c6debd698d09592dbf8a132e204f208", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 393, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "19d3527f7b8630a37044cbfd66f080d310951f1171eca8d22c61a2b75d430b3a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1000572, - "script": "76a914c426803960e08d50a8d07590fe1be6f24477c5a788ac", - "coinbase": false, - "hash": "19d3527f7b8630a37044cbfd66f080d310951f1171eca8d22c61a2b75d430b3a", - "index": 0 - }, - "script": "4730440220467b67c7e677c6c099209c47efb8945a87dd7c02d406d76e35f332e94aa7dd5a02201be753c0a08fabefe6fd3858311bf1273ffae2374998e4fc4723b366aee0a07101210245b68bdf03a46b02a4fd18f7b3a00fe851e5b68c1db8b4b4a17d199ea3a52116", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f9736d135dcc43f318df1edcb661a161509f309d23f86585cd125f08c4d23fff", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1020000, - "script": "76a9145958b5e1e2bcff8f6f1076b3289dbb98b81920f688ac", - "coinbase": false, - "hash": "f9736d135dcc43f318df1edcb661a161509f309d23f86585cd125f08c4d23fff", - "index": 0 - }, - "script": "47304402202ba393708208a23954edbcc3a9068145699bbfed7fc493f3087cfe75eaa6cd8c02200ee3a8a0d0558a78e3e34cdf0909e611a8eae7473e787275efd86ae9bfe1790b012102a8bde065b6fbf6edb2aa31f41c56488bb1a5ce78560fcdeecbbbdf485e87b112", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1810572, - "script": "76a9149fbcae35c39e1e3a1bbeddf504b5075e2733a89688ac" - }, - { - "value": 200000, - "script": "76a914da5dde8abec4f3b67561bcd06aaf28b790cff75588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "221f15c4babeef066b178bfe0d335422f5ea7bf5af76c3ab4089fc8d568d8b4c", - "witnessHash": "221f15c4babeef066b178bfe0d335422f5ea7bf5af76c3ab4089fc8d568d8b4c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 394, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1222410d68f5e956b43a5c7e5bdf90741c6debd698d09592dbf8a132e204f208", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 200000, - "script": "76a914da5dde8abec4f3b67561bcd06aaf28b790cff75588ac", - "coinbase": false, - "hash": "1222410d68f5e956b43a5c7e5bdf90741c6debd698d09592dbf8a132e204f208", - "index": 1 - }, - "script": "483045022100b02a47738ba9c9f11040cb08a9809b503e04811bd74713957242c635fe49361e02206a8cafed06382cec2bc606944976ac919b816810784fa14ed757a5625b1113bc0141049de1c8260ad5729982fa9589f0aa795a76dbd9695418c232963098eac9c1a2b3c74669555f94f6e3fe7800916a8e30651dc7eefdb82e773bb096358420818d5a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 30000, - "script": "76a914c426803960e08d50a8d07590fe1be6f24477c5a788ac" - }, - { - "value": 160000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b0f066f7d5cc618046edb31c488b02cbaba612b3ac481155ef72e97a03dd75ef", - "witnessHash": "b0f066f7d5cc618046edb31c488b02cbaba612b3ac481155ef72e97a03dd75ef", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 395, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3c10df434e3bad248bbe88259bd22e446c55ffff1803d7dc299cf3733b27c594", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299902, - "value": 79850000, - "script": "76a9144e3e71ef1d658322ff5b68e6a741c0ff5b614dbe88ac", - "coinbase": false, - "hash": "3c10df434e3bad248bbe88259bd22e446c55ffff1803d7dc299cf3733b27c594", - "index": 0 - }, - "script": "493046022100aa06e297cd5b52920469f106f370dfc18c97aea80360ceedc84c4320655091fc022100cab61f188a75eec004f8f95b8a665ea4cef942761f96d6542a8e74ab4a5ceacd012103f5bfef358ee6a6cfa922f9d589817e8ba71266194f97d1a959a8122f78aa8d9f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ed03932656d7862f61f5fe71926c2e193db4b145a1983aaa049aacfa758f860", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299692, - "value": 8140000, - "script": "76a9146e46711e25da1c0de2ff2ac34766cd9cde0c24d188ac", - "coinbase": false, - "hash": "6ed03932656d7862f61f5fe71926c2e193db4b145a1983aaa049aacfa758f860", - "index": 1 - }, - "script": "483045022076f29a329c249f87f57070ce0e1208f2c465ec0ec68489f89015a13dbabd86b20221008d3bc03fad305e2596bb4ed5bc3c5a83ba3c4a2f603ffe6cd85df25fb82c74de012102306b644943920aee5bada7f7c3f81a7d56648087fb6699a0a83f72e591bf1754", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7c3c7ef6a63a5524c78c9298307ee2c27782f1d7be6cfb44f8036e2cc2860eb6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299406, - "value": 16130000, - "script": "76a914a85a4bcc76c433afb8a848fbda6d669689d4b62688ac", - "coinbase": false, - "hash": "7c3c7ef6a63a5524c78c9298307ee2c27782f1d7be6cfb44f8036e2cc2860eb6", - "index": 0 - }, - "script": "48304502207a1b38d0fe61840f5dc592450f84cc339301140a2fc8de37f4122ae2946df71c022100c9869128c71598f758bbbeb89d3d0608341ec467bb91ca35646c8c7c97ef8dc10121024c6902b379af5aaa743370abdd22e1b08a64fa1574dbafd182bfac352ac1def2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4110000, - "script": "76a914a6aecba9d8089b127fb626ba6df8b38021e4266f88ac" - }, - { - "value": 100000000, - "script": "76a914a5654be21cd173cbe5c2354a63df23a1bfc459b488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5708f3c63be2baf9d478256cded8787c84f1eb8262c6751993a84cd04cf89373", - "witnessHash": "5708f3c63be2baf9d478256cded8787c84f1eb8262c6751993a84cd04cf89373", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 396, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "656240110cb4fa631333401b950c587e02e5a194b6c543eee773a9d37dd7c085", - "index": 359 - }, - "coin": { - "version": 1, - "height": 299969, - "value": 10094584, - "script": "76a9148e7445bbb8abd4b3174d80fa4c409fea6b94d96b88ac", - "coinbase": false, - "hash": "656240110cb4fa631333401b950c587e02e5a194b6c543eee773a9d37dd7c085", - "index": 359 - }, - "script": "493046022100fac44490c1943a1492e8c4331e5daafac56d844c1653aab9aae5ab2ad0ddd3e30221008130cb69429507b560a4a129c94ce4a8ec8022cf6baa59b57c7be459c61603750121023abd0e81d627e92dc18937a5a79f680b8ab49fe23ba9852f14044d8e72db8305", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a2885cec6163ff722c855ef077f64782553af41afe270eda2450e97951d36f5d", - "index": 343 - }, - "coin": { - "version": 1, - "height": 299798, - "value": 9359327, - "script": "76a9148e7445bbb8abd4b3174d80fa4c409fea6b94d96b88ac", - "coinbase": false, - "hash": "a2885cec6163ff722c855ef077f64782553af41afe270eda2450e97951d36f5d", - "index": 343 - }, - "script": "493046022100e5997201f2a4a863b77141253a8ac22319ba4407378395994a4678e23353e44c022100e39660051677a04977b0c94f215119bf1014912d4dc65ded379fa7e541b7afd20121023abd0e81d627e92dc18937a5a79f680b8ab49fe23ba9852f14044d8e72db8305", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "96ec6b88f5b914fdae9c6eaa7290e0eab9d8fab2a0e218e7c79fb4213178f57a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299689, - "value": 15515, - "script": "76a9148e7445bbb8abd4b3174d80fa4c409fea6b94d96b88ac", - "coinbase": false, - "hash": "96ec6b88f5b914fdae9c6eaa7290e0eab9d8fab2a0e218e7c79fb4213178f57a", - "index": 1 - }, - "script": "493046022100a33065f89a8bca93e3bc33733426f21087605f7ba79130ab4b154bee53787852022100a33a1f0b41f9d7356f1d5963f50bd3c3d1dbd3ea99d145b53546a1230fdd308f0121023abd0e81d627e92dc18937a5a79f680b8ab49fe23ba9852f14044d8e72db8305", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 19440000, - "script": "76a914bbd538b8364a8542983f9fe61b433fcb1776215288ac" - }, - { - "value": 19426, - "script": "76a9148e7445bbb8abd4b3174d80fa4c409fea6b94d96b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5ceec2d8ee90cb4b956870fac6055bead9333570f656ec3014307031de518cec", - "witnessHash": "5ceec2d8ee90cb4b956870fac6055bead9333570f656ec3014307031de518cec", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 397, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "89baa6934a2e790699804c1ae4a0b8f4e537244fb4dc78e4cdd5aabf59b2ea20", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299901, - "value": 5460, - "script": "5141044e7194426b519391acd0efd21eda207b0283837d508a0b4f31732fee0016a7d948ad72b4270ecf627b1078ccef539446d150e3e0fc661c9fca40ecec6d9652c5410462e044eb7cd618a2da9d8f7581a5196d331bcd0d38d1cef49ccb86bec16fe6b2793f6da5a6d17f9f75479c3b6915ae61eed7ba721075a683d82692e958ea05762102f884647516015a0f5861633406a0c8b2ef2d8967aa61a97a5fc2b14bf0ce23ba53ae", - "coinbase": false, - "hash": "89baa6934a2e790699804c1ae4a0b8f4e537244fb4dc78e4cdd5aabf59b2ea20", - "index": 1 - }, - "script": "0048304502210097e0b36ee0022544f3cdbc19d57d4543633eea38a88b623f66ffc9b5f88a9c5002203100e367444753cc933205c24ead17765e4761165b52377533e1f97e037aa73401", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "89baa6934a2e790699804c1ae4a0b8f4e537244fb4dc78e4cdd5aabf59b2ea20", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299901, - "value": 5460, - "script": "514104135a3af7994ffea92ae3fe31bbcf171774f6710b28020a4aae8a60c2067a5bb4d9e78ebaa7835d8b5d1eaf6b2d0cab8798c07a4f3fb25039763a534f420de3f24104a80e6bb472850549ae160004e60892ed7a33ac65af1db8cab114db519260adba9b3d80317af4c1e867833eb8f05d36e4569fe1470892ad4b067f6e63941c04992102f884647516015a0f5861633406a0c8b2ef2d8967aa61a97a5fc2b14bf0ce23ba53ae", - "coinbase": false, - "hash": "89baa6934a2e790699804c1ae4a0b8f4e537244fb4dc78e4cdd5aabf59b2ea20", - "index": 2 - }, - "script": "00483045022100be52576b14e484b114348bdea7ea0faaabb517ab3f3f19058db1406097fc17390220206147e81accef9d7499d07910320c253cec78113906d233144f293e70b2365f01", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "89baa6934a2e790699804c1ae4a0b8f4e537244fb4dc78e4cdd5aabf59b2ea20", - "index": 3 - }, - "coin": { - "version": 1, - "height": 299901, - "value": 5460, - "script": "514104b73c797f606d9c12bcce9dde31152fb57ec8b2ddf224f44539c1b743c6186bd8234cfd1427fad5ea8e3e738a80cf9161ddc1e9c09bddfb8a555938e6ff3d814e410424646ed408173bb594defcd11cd7554cfdec25ab542d99dd47c83e1a529ce15ccfb3148f3c8961fbb5475f25200f08ebfd805eb058dccbaf878b75a2d77fd1792102f884647516015a0f5861633406a0c8b2ef2d8967aa61a97a5fc2b14bf0ce23ba53ae", - "coinbase": false, - "hash": "89baa6934a2e790699804c1ae4a0b8f4e537244fb4dc78e4cdd5aabf59b2ea20", - "index": 3 - }, - "script": "004930460221009951ffbeddd35f0a1db466eca3932c408ce657783a6267d932fc91f0efad9d77022100af018d9cccda3c92f229c4cad151de0015c25746083320c7eab0d7aa33876c1701", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 6380, - "script": "5141047b00000078da0dca3b0ec2300c00d0ab4466ed10e763272c6c9ca052972c69e3884a9022084215e2eef0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e4104fb45eddb6b50b7dc4ea9c1000fb95ff771fb677285b46374b4d83097ea6d6509d5a3b3993912c5a071e658d18bb38e0a1a31dee45a84b5c10cdf1f3cb92415002102f884647516015a0f5861633406a0c8b2ef2d8967aa61a97a5fc2b14bf0ce23ba53ae" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8b5b05427f111bea94883ce7a5bdee7e7a0bcfcfebc2babefd54db202e857529", - "witnessHash": "8b5b05427f111bea94883ce7a5bdee7e7a0bcfcfebc2babefd54db202e857529", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 398, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3ae96ed7dcf039b0f99e4a1412cfcf173ca9a402bb83b2a5dba8063a41231076", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 500000, - "script": "76a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac", - "coinbase": false, - "hash": "3ae96ed7dcf039b0f99e4a1412cfcf173ca9a402bb83b2a5dba8063a41231076", - "index": 1 - }, - "script": "47304402207a8f520d099f63cfbf18aa07801992fe7ceba854b0b3ff407c7e2b135536c8e3022034d561ee2080012fe1ba770f9874fd07c84df1135a8ba7a15db896e0ed8c8a1c014104da6bc6a6139bb008454bfc8371141a5fb8ba6de87e9ab1578ab4c31e1b25513d6d1b1b0e66b0e39a29f6baf19f9f0faaf51d22bac02b1c07eb08058498763784", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6f08b190fe567e63f15d8d436a5425f44faeae187df2cb16df8f36b955bcf1a6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "6f08b190fe567e63f15d8d436a5425f44faeae187df2cb16df8f36b955bcf1a6", - "index": 0 - }, - "script": "483045022100e48d81251c0f2d332f350288c911cadf0fdd5504635b6af312dbde27835d6dca02203d378d128a1400cd4c3a7ae1bf3439970a92438453f9f986db71f40f6a4889570121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7069a1df16e76c224615fb97ed574ea8704b78b395f91f4f29598b7d7b73393b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "7069a1df16e76c224615fb97ed574ea8704b78b395f91f4f29598b7d7b73393b", - "index": 1 - }, - "script": "47304402206cafdaf07b353474ab271885ad843adb48a943030ebdf1604a0bc5d0e877288d02207327868c3745007e9e199284e47373c6453dca7004fae70780f7c7affaba9a5a0121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - }, - { - "value": 540000, - "script": "76a91486bee458d3d0ceaec4616c0852c1c403754ff1f688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7860c680270ac315785b4f5b83bbd05fb5bb53cbf611fba9f42db80f22e3c693", - "witnessHash": "7860c680270ac315785b4f5b83bbd05fb5bb53cbf611fba9f42db80f22e3c693", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 399, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9928f14fc34ab9a3dbbba2fe5cfac1eb7a11843d05e62a082a2186882eb83fef", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299758, - "value": 532148, - "script": "76a914335653470d9b86a60cd470e3e9816c644280896888ac", - "coinbase": false, - "hash": "9928f14fc34ab9a3dbbba2fe5cfac1eb7a11843d05e62a082a2186882eb83fef", - "index": 1 - }, - "script": "4830450220244b9230bd4f9291f2fde13e02eabaae67fe9de20d33819c7d27f765e0e6a64d022100ebf042d6fbbbb2cff37e5ded5a0cb5a2e5f58e6632927ccc251d13ec687664fc014104c1482690c2eb21a404373ef3b184f7202fab723a38b671c3ff16c82a19f0a93064da8dbe23ab484344dccfb5147e78eb702affa69a0f1051b677fc3819f78a4f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a18c67234a9d59f4f80a265252bf9421f539279cdadf253021e148c31911993a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299762, - "value": 6101970, - "script": "76a914335653470d9b86a60cd470e3e9816c644280896888ac", - "coinbase": false, - "hash": "a18c67234a9d59f4f80a265252bf9421f539279cdadf253021e148c31911993a", - "index": 0 - }, - "script": "483045022100e641396cd334bb368016dbb9e2db9648b2950671a9478411757038d0e0c9a7ca022007217bac57e0ca8a847fd678803bd620b7eeae94d416cc69f8f078279087d9ba014104c1482690c2eb21a404373ef3b184f7202fab723a38b671c3ff16c82a19f0a93064da8dbe23ab484344dccfb5147e78eb702affa69a0f1051b677fc3819f78a4f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "93aaa3e672673fc885ff3637b864ef625753e684df0ea167739f6b887f081315", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299873, - "value": 8800000, - "script": "76a914335653470d9b86a60cd470e3e9816c644280896888ac", - "coinbase": false, - "hash": "93aaa3e672673fc885ff3637b864ef625753e684df0ea167739f6b887f081315", - "index": 0 - }, - "script": "493046022100c676608eababb610a9158f014737bf2bf8c51a648b4f00d354d0c1af023c98bc022100c351f1ec277494524c5bf4dd557c9f17aa42a3f4f31b2797a73e6274f8d2087e014104c1482690c2eb21a404373ef3b184f7202fab723a38b671c3ff16c82a19f0a93064da8dbe23ab484344dccfb5147e78eb702affa69a0f1051b677fc3819f78a4f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 15424118, - "script": "76a914651d03dd005e308a44d3e5d13aba18e8e523e88a88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dec2b78570167698d549bd8bab2382e541a449316ccf02c23da8ec33635ef4a9", - "witnessHash": "dec2b78570167698d549bd8bab2382e541a449316ccf02c23da8ec33635ef4a9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 400, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ac4448d0e0275e6243bddc98e1561d3944e73395d48ebcb47b74ce29bfdfb1d7", - "index": 659 - }, - "coin": { - "version": 1, - "height": 299025, - "value": 12820000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "ac4448d0e0275e6243bddc98e1561d3944e73395d48ebcb47b74ce29bfdfb1d7", - "index": 659 - }, - "script": "483045022100d228f58bbc5e8c2d0dd677dc510e15f46b97f9d17ac5e539cbaa880996e9f21202205bb7d219a61b9ee5122ea6803eadf92da0c4c2b2d7584bdb5e6496a56f914684012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 666 - }, - "coin": { - "version": 1, - "height": 299989, - "value": 13100000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 666 - }, - "script": "483045022100fd8d544d9b46f98e4a3d37fbf4bd34baa049e9cc499b7feac1254adab42ad5e6022040105056b2fce27e0593c0783410458934b61b2432a2b786de117b14aa27d552012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "954906d69483f669be155a0da0df2c6a215ef6098847affe70d4d1b733e47472", - "index": 654 - }, - "coin": { - "version": 1, - "height": 299167, - "value": 12920000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "954906d69483f669be155a0da0df2c6a215ef6098847affe70d4d1b733e47472", - "index": 654 - }, - "script": "49304602210098122827483bbee54fe936896f3bb5f157911df9bedba936f00e71da86e201a8022100ff2de68bcc0471837aef2909b3e236442af31dbac2a1658d82a2e20058806dac012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "af468b8cfe46cfadd6b8eac0953e7221994fa9f2dade0009e52750edb450bc02", - "index": 657 - }, - "coin": { - "version": 1, - "height": 299497, - "value": 12840000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "af468b8cfe46cfadd6b8eac0953e7221994fa9f2dade0009e52750edb450bc02", - "index": 657 - }, - "script": "473044022058880ec675058c4da2565a4377f53d216f4dd7eaca7a7e940c664c748dbf382302201aaf27d0b6bc84cdfb826e115a8e5f96f6e0d33c7130939a68f7bc74223af83c012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c1fdd01af7c85d1754cbb5609e8785f1cac67261bd4c62121080f3fddcc9dffe", - "index": 619 - }, - "coin": { - "version": 1, - "height": 298874, - "value": 13210000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "c1fdd01af7c85d1754cbb5609e8785f1cac67261bd4c62121080f3fddcc9dffe", - "index": 619 - }, - "script": "473044022026ec971bcbc9d21d745102b18d51c0d1dc660dcf7c6b49c981b694289402ee43022079d826da85bbccf1e101d3eb0b24acdcb49c7f4c5d752863ed0a9afad896002a012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b66c4d633fd3f96dff48fc032ce633458ecb5a8526930a7e304506b0808e6bb8", - "index": 655 - }, - "coin": { - "version": 1, - "height": 299650, - "value": 13060000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "b66c4d633fd3f96dff48fc032ce633458ecb5a8526930a7e304506b0808e6bb8", - "index": 655 - }, - "script": "473044022021f345f5d0bb0e8c1dfa7493cb37ad4affca6a8195c3edcc68e32b8b7f3c82d602203fad110880a050cf1f68229fec2a1e4882e0d2a7e4d7b2188452be13ba92a27c012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "98ce8f278f2692d6f32528efd2430e96ed0baf51a729999000699acb5bcaf158", - "index": 651 - }, - "coin": { - "version": 1, - "height": 299305, - "value": 13050000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "98ce8f278f2692d6f32528efd2430e96ed0baf51a729999000699acb5bcaf158", - "index": 651 - }, - "script": "47304402200bed344b99f6dd20f3ded810c779b0f505593978a6447fae6b692ca8c7846dce022026e2d73a1168e5161051f2ffb24d314fdf4d5d6e78830e8cfd5e47c09e404e3b012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4eb649ea1c85956a9059e24d41ee0d972572ca4c18aab0d96f1698d94d8b417f", - "index": 672 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 12890000, - "script": "76a9147ebebd3240de0ca288d45e91354327f67773828588ac", - "coinbase": false, - "hash": "4eb649ea1c85956a9059e24d41ee0d972572ca4c18aab0d96f1698d94d8b417f", - "index": 672 - }, - "script": "48304502210082893a88c3dbedde45bc709be4a3bc1c664886164142f01b880b8cd1e41cc21802203ea05778db1785386cf8b6ac0b94d8f9173dc21788790ed410db7b16ceba12fc012102bd453bfeaa9b48ee521d85ff9bdd5b713cd9cad6f063622aed2241624c977888", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 103870000, - "script": "76a9149d3195622f29ca77f84382d03c9f50d1b66ab14588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "7366d9110ef570ccaf33483039fe5822777b387d9f444cd4b213a849eb743f76", - "witnessHash": "7366d9110ef570ccaf33483039fe5822777b387d9f444cd4b213a849eb743f76", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 401, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "42f328d2697615acff34271c78b4975ff2622f489c3ec1d307871b5fa6c57329", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac", - "coinbase": false, - "hash": "42f328d2697615acff34271c78b4975ff2622f489c3ec1d307871b5fa6c57329", - "index": 1 - }, - "script": "47304402200abac7ddacad100c5995aa04bff4723fcb16d154d25a92cea5247ef39c0db27c022042bea5f4d703f8d56748bfaac5fff07815e7d06fa88bc74b1edbd0b11fb33210014104bfa71464809d4495b30e075ae06ed258066979d4e4073fa82b3e92a51c7a10d9f31872401ed1fb5117c5299d55de005c56d32b4366b4f8c06f08f0219701dddc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cbd7650c55a2dade874b3932c51547280676bade0103e9a8a1c4895631d4027c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac", - "coinbase": false, - "hash": "cbd7650c55a2dade874b3932c51547280676bade0103e9a8a1c4895631d4027c", - "index": 1 - }, - "script": "4830450220667d7fa7b3ec768e25b9b8f779a54be81daa04341c6e42ee1185ce71bdc9b7ac022100e6cd46857ac61a130943d68d11726cdf1ccedcbc5b5b4730bd4c87e08604667b014104bfa71464809d4495b30e075ae06ed258066979d4e4073fa82b3e92a51c7a10d9f31872401ed1fb5117c5299d55de005c56d32b4366b4f8c06f08f0219701dddc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "21d57c6f0cf8125a35bb0aa8620213ac5256d44ce2b0d65b4a1220a1891b2e2a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3080000, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac", - "coinbase": false, - "hash": "21d57c6f0cf8125a35bb0aa8620213ac5256d44ce2b0d65b4a1220a1891b2e2a", - "index": 0 - }, - "script": "473044022073cc17eab1166bae34bae23f0353cd6fc5a0b55e078ba9c784fe72df653b9d46022016b41d9b3ed60519204272ed721bb7d9fb222a669b35423848e11e939d4471a8014104bfa71464809d4495b30e075ae06ed258066979d4e4073fa82b3e92a51c7a10d9f31872401ed1fb5117c5299d55de005c56d32b4366b4f8c06f08f0219701dddc", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1100000, - "script": "76a914835b0a528ff00bea04da24da24e11518044e1f9588ac" - }, - { - "value": 1990000, - "script": "76a914121a978f8980426a357064eb8f0b2d9d6444a12588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4845defad6a1729d7ac88a50f76935df3871a7095fdc821a060ba3dde81ef201", - "witnessHash": "4845defad6a1729d7ac88a50f76935df3871a7095fdc821a060ba3dde81ef201", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 402, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "38e7a78f55f9221018b9a276928b5a6fc6e48e52bf29931fd948d43a6189981b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 600000, - "script": "76a9145a23a3cde9467dcc9adc1324951729d4e58e9e7e88ac", - "coinbase": false, - "hash": "38e7a78f55f9221018b9a276928b5a6fc6e48e52bf29931fd948d43a6189981b", - "index": 0 - }, - "script": "48304502207070063b78a85757fb39c699e52eb893663a2e28db0b3122e2827871433d44a7022100dbced026257481435a42bc8d98602e0fa61575c16259269e9ef51c629a5ea8e30141041f8325b57d39bd960fd3cd3732e2c6e1d4d6a601478eb122291aa79098a80bb767ed24624fec760d9e058d90c187943bbf3560a267f457b488294e28fc98d551", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "363e5803483b6c5f062c424b73fb967043b1ea04f6925956800a2b345f10a92a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299842, - "value": 1206722, - "script": "76a9145a23a3cde9467dcc9adc1324951729d4e58e9e7e88ac", - "coinbase": false, - "hash": "363e5803483b6c5f062c424b73fb967043b1ea04f6925956800a2b345f10a92a", - "index": 1 - }, - "script": "48304502202ce44e21f2826198a426d72c221121ca473d09cd704987eabd26c1c4e500dd43022100a131ef6f59d7aa31213d2ee3cadd64b109884a89d70f830be86cca1f8a8762ec0141041f8325b57d39bd960fd3cd3732e2c6e1d4d6a601478eb122291aa79098a80bb767ed24624fec760d9e058d90c187943bbf3560a267f457b488294e28fc98d551", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5f1a5794b558aba170a223a7a0a923083a4c8edd43c2ee304373edd8e1d1b034", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299877, - "value": 1873785, - "script": "76a9145a23a3cde9467dcc9adc1324951729d4e58e9e7e88ac", - "coinbase": false, - "hash": "5f1a5794b558aba170a223a7a0a923083a4c8edd43c2ee304373edd8e1d1b034", - "index": 1 - }, - "script": "47304402204bcaf42e2fa51f4d6bbcf5a27b8056ca54531c254e144c532a05b6e3ffbab77c02201829de5516dd9f23aea94d580632de7b3c012d3458204f36e5bcf0588e759b1a0141041f8325b57d39bd960fd3cd3732e2c6e1d4d6a601478eb122291aa79098a80bb767ed24624fec760d9e058d90c187943bbf3560a267f457b488294e28fc98d551", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000000, - "script": "76a91490b9ab91dec16f1e609378a8ddf4c0ba2a7c6dd788ac" - }, - { - "value": 2670507, - "script": "76a9145a23a3cde9467dcc9adc1324951729d4e58e9e7e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "1ccbd36c8cdf1d497b190e13606be80e1ff297fcdccfd5cc74066668e55ad6cc", - "witnessHash": "1ccbd36c8cdf1d497b190e13606be80e1ff297fcdccfd5cc74066668e55ad6cc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 403, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4845defad6a1729d7ac88a50f76935df3871a7095fdc821a060ba3dde81ef201", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2670507, - "script": "76a9145a23a3cde9467dcc9adc1324951729d4e58e9e7e88ac", - "coinbase": false, - "hash": "4845defad6a1729d7ac88a50f76935df3871a7095fdc821a060ba3dde81ef201", - "index": 1 - }, - "script": "4830450221009c5d12617e46207841c0640b70c587cec9d6f2653f88664f23924e77284d018e0220713fa490ce46bed7be55162a1feb52650ec14a56a4eb56dc0c24ab43a033264f0141041f8325b57d39bd960fd3cd3732e2c6e1d4d6a601478eb122291aa79098a80bb767ed24624fec760d9e058d90c187943bbf3560a267f457b488294e28fc98d551", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000000, - "script": "76a91490b9ab91dec16f1e609378a8ddf4c0ba2a7c6dd788ac" - }, - { - "value": 1660507, - "script": "76a9145a23a3cde9467dcc9adc1324951729d4e58e9e7e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3bc1ff9cfe257902b98fd8cfd22c037700dd0ad1c4917fa0d3fc51d9e67c8003", - "witnessHash": "3bc1ff9cfe257902b98fd8cfd22c037700dd0ad1c4917fa0d3fc51d9e67c8003", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 404, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "09becaf4f90a60e7de8fa0f0c2b4169c6928c2e76401bf540109c86b7cb426f7", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 10000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "09becaf4f90a60e7de8fa0f0c2b4169c6928c2e76401bf540109c86b7cb426f7", - "index": 1 - }, - "script": "48304502205cd94b7f3e87f04aefe84d4efc930a02bb077dccbafbadd5370e33e72db80efc0221008755106c0e8e851dd9e3bbc488a2a71c62e5c31f07e684927f4eab84fc800c4601410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "94821654affca7dbcaa76d8fa99701a5cd785947cc4da85c39a2710120ff7715", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 10000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "94821654affca7dbcaa76d8fa99701a5cd785947cc4da85c39a2710120ff7715", - "index": 1 - }, - "script": "483045022020b0efd408139d784bedec0835b978f71410f7cbd406950355cf41d5609b3beb022100feaff63234e46e713d625ccf9bfc2ff9f3fe648bd22ca1e25669ea57a1dec88f01410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1423c09e9b39cde095b27047b85402c346631920cdc994dca8885761acbb2771", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 3655583, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "1423c09e9b39cde095b27047b85402c346631920cdc994dca8885761acbb2771", - "index": 1 - }, - "script": "473044022054867952741dc71b467e1d630e774251e44affa72869cb741b5c31f98a3afa9302204a46ae579aac8d44efc94abba45b9a4b5a5e8a5c1705fe5d973db445824b08e501410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1700000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac" - }, - { - "value": 1965583, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c9c45b678e0a8a1eebe9377d8abcbdcc1936e4f75600635488e97f79c2108726", - "witnessHash": "c9c45b678e0a8a1eebe9377d8abcbdcc1936e4f75600635488e97f79c2108726", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 405, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "3bc1ff9cfe257902b98fd8cfd22c037700dd0ad1c4917fa0d3fc51d9e67c8003", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1700000, - "script": "76a914e4d9de21d4128b92129528f5922ec23101be9beb88ac", - "coinbase": false, - "hash": "3bc1ff9cfe257902b98fd8cfd22c037700dd0ad1c4917fa0d3fc51d9e67c8003", - "index": 0 - }, - "script": "483045022100a9459c2e1f02c6e90a52c38e71d9a961d43eb81dac56b202e48f1f8123f7bbc902206f0a64a669598cc92b8962507e29b7f0dc58c311026380c6a39fcb257a8b073c0121037bedeab7fcb8f05bc5fca2bb43525bd7af9f125035149ab4f48843db0ba37c8f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1680000, - "script": "76a9140cc7a4cb0d42a97ad29cfc0a49f955d78bd0362388ac" - }, - { - "value": 10000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "6e4f0ec2e2e89a76a1be0b3c88e0a0467a0ccd15861b807f424c5f99dd8a70f5", - "witnessHash": "6e4f0ec2e2e89a76a1be0b3c88e0a0467a0ccd15861b807f424c5f99dd8a70f5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 406, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "63941799ebd8cf7ba8c5bec7a75e99ae983951af1194d6aea50640484d93ff83", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 1640000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "63941799ebd8cf7ba8c5bec7a75e99ae983951af1194d6aea50640484d93ff83", - "index": 1 - }, - "script": "483045022100b1e8a3dc70ea31d6d60dbce9c57bbab0ba89ce3f85938efc21e371d39b33ff3b022060b3a18a810add684c8acf3863cce5264f6f8a5b9f786f2f8585b78affb7c1a501410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9b653ddea62de87fb8ea9f25e63d7145211b5489402f3556464fd0338768a479", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 1190000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "9b653ddea62de87fb8ea9f25e63d7145211b5489402f3556464fd0338768a479", - "index": 0 - }, - "script": "483045022079a6207727ab035242d05ec42543230c1c73fea241e7a9fef6d35c8951bd448a0221008adaf4c7ab7af1598a78ccf85dfea470577b34b79246cde34b3c98879f91b7c601410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "70a3a1d666ef8e501990a6dab8c58d5e56ed95c2d3eeefd7186abb9f478cae13", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 1555000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "70a3a1d666ef8e501990a6dab8c58d5e56ed95c2d3eeefd7186abb9f478cae13", - "index": 1 - }, - "script": "483045022100a28f5cd36b32c6e998f488955d8e3fcd9bfecbaf29a467be8f9dc85c86207dd20220425e3bb1406132f12717b3f50662a8355328a5b8aa378e8ff26ee7db8a6db48801410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2800000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 1575000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d567fabd3dd262b8b263ce479c2ab3d3877ca7433c0c470650fc529d21450582", - "witnessHash": "d567fabd3dd262b8b263ce479c2ab3d3877ca7433c0c470650fc529d21450582", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 407, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6e4f0ec2e2e89a76a1be0b3c88e0a0467a0ccd15861b807f424c5f99dd8a70f5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2800000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "6e4f0ec2e2e89a76a1be0b3c88e0a0467a0ccd15861b807f424c5f99dd8a70f5", - "index": 0 - }, - "script": "483045022100db9fb9c2d11c05590e0b54c121985d5720956de950e772f78ac24a5c3dc1950102204c6633f42068ebeb478eaa5dbb94bec2c1c10df953305f835d9415ace8e1a6d60121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2790000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "adf4a990f1efd92696da227159e80433478b77dd2125c3d712ac7077be541695", - "witnessHash": "adf4a990f1efd92696da227159e80433478b77dd2125c3d712ac7077be541695", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 408, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1a1d2be01d2a0093ee3bb16c3e42decc8102b17f6b6d661c1b4d8682c880caca", - "index": 1 - }, - "coin": { - "version": 1, - "height": 295638, - "value": 3325, - "script": "76a9144a326316cdbc9a22bb23a569287e4e32b82eb7a688ac", - "coinbase": false, - "hash": "1a1d2be01d2a0093ee3bb16c3e42decc8102b17f6b6d661c1b4d8682c880caca", - "index": 1 - }, - "script": "493046022100de526d85c9e4b2b565c67de926b24b88ad8a66ffbf3522e606e2abaab53684ce022100bdc634abaf7f25cfd40f42cad3cbed4d6f4d6eab703e31498a5a3e04fa6508080141045d5e4096cfab6d184bed5183c7633074dc4cdcdaa380cce6be809bfcf641ebca30b27b5022165e56bf31e882a090df696b2a62cc2da7f7182ee8d423dfb9034c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c59e828223bb083c3d2857c5cebbf763489c83c064245026ec4ce5abf8ee76e9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297309, - "value": 10380000, - "script": "76a9144a326316cdbc9a22bb23a569287e4e32b82eb7a688ac", - "coinbase": false, - "hash": "c59e828223bb083c3d2857c5cebbf763489c83c064245026ec4ce5abf8ee76e9", - "index": 1 - }, - "script": "49304602210086538a305166b9016f8908f8ec9207398d3aa6d2e04c551bc759276d4d9da405022100e7dbde7cee496e2fe990243aa2e985b0d0c18add384af8708775a4ab9cdf258c0141045d5e4096cfab6d184bed5183c7633074dc4cdcdaa380cce6be809bfcf641ebca30b27b5022165e56bf31e882a090df696b2a62cc2da7f7182ee8d423dfb9034c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e8b0ef45bd114a2a8f5e4a7a183f298063c3705225d3ca0ee1d2ef059ba5fa65", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 46090000, - "script": "76a9144a326316cdbc9a22bb23a569287e4e32b82eb7a688ac", - "coinbase": false, - "hash": "e8b0ef45bd114a2a8f5e4a7a183f298063c3705225d3ca0ee1d2ef059ba5fa65", - "index": 1 - }, - "script": "4730440220274a7da5e70f721d6892277c9b39bf212a9f4bd539eb653c82b89a070b3a6041022068d052ad184106113d0f3ea18b706f930b2a22007cfb6612f1f78b6b66b471c80141045d5e4096cfab6d184bed5183c7633074dc4cdcdaa380cce6be809bfcf641ebca30b27b5022165e56bf31e882a090df696b2a62cc2da7f7182ee8d423dfb9034c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 55000420, - "script": "76a914f5de083f859cfb4b06021c6e4fb52135c99442a588ac" - }, - { - "value": 1462905, - "script": "76a9144a326316cdbc9a22bb23a569287e4e32b82eb7a688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "78d955590ef9e4bb73609820ccc02ba89d580c93c84c94f0c3a2ba256116c296", - "witnessHash": "78d955590ef9e4bb73609820ccc02ba89d580c93c84c94f0c3a2ba256116c296", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 409, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ed6d476daf7aae7f5b2f2ac559fe6e121932956ad32381c14dde7bbbaa20f424", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299618, - "value": 82578, - "script": "76a91440007f40140f77435f0cdf53018696db1c0a650e88ac", - "coinbase": false, - "hash": "ed6d476daf7aae7f5b2f2ac559fe6e121932956ad32381c14dde7bbbaa20f424", - "index": 1 - }, - "script": "483045022100a920137476ab00e96648fe8fa45315fb30fc14406696c9fbbc1b14dac9fb95bb0220530d8db38067ca8c8997e1462814fee7552f575653249811904059095d711bcc01410466972e76a3953e6f6125a7f1899e176ef45abb0607a559c154f0ea1cbdf5ea9a0f2e1bc10dbaa1190b0ad2ac065206340ef4d7b3817fa4fac3c0b76eab6f9392", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d5b0519b2e7cbdf159fc4f1d8eaa974af9fef805d4e08a6598aa60026c9d4647", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299966, - "value": 1186470, - "script": "76a91440007f40140f77435f0cdf53018696db1c0a650e88ac", - "coinbase": false, - "hash": "d5b0519b2e7cbdf159fc4f1d8eaa974af9fef805d4e08a6598aa60026c9d4647", - "index": 1 - }, - "script": "483045022100f208e73734f1fdd97fb2dbdaad73e7f11f26480b6fb4bbba3010bc15b47a290302206703535825bd243fb677c334f73679cdc2ce890e5ceeb141eaeb9dec5b1f04c901410466972e76a3953e6f6125a7f1899e176ef45abb0607a559c154f0ea1cbdf5ea9a0f2e1bc10dbaa1190b0ad2ac065206340ef4d7b3817fa4fac3c0b76eab6f9392", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2a936eefb5ce285e9f651c822003d5a2c242c781a6a95f82de913405762ee873", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300001, - "value": 93845000, - "script": "76a91440007f40140f77435f0cdf53018696db1c0a650e88ac", - "coinbase": false, - "hash": "2a936eefb5ce285e9f651c822003d5a2c242c781a6a95f82de913405762ee873", - "index": 4 - }, - "script": "49304602210084c4294026591f42cc3252b8d41e5ac8c6d7243f2537986e2c6610759906e14f0221009c32dd58e4c9cc3a18327787b4a68050ad8442043f486436bc01f1d1ad03900d01410466972e76a3953e6f6125a7f1899e176ef45abb0607a559c154f0ea1cbdf5ea9a0f2e1bc10dbaa1190b0ad2ac065206340ef4d7b3817fa4fac3c0b76eab6f9392", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 94717828, - "script": "76a914719c457b5d1bb1579c36fe6118a35b00a4a12e7d88ac" - }, - { - "value": 386220, - "script": "76a91440007f40140f77435f0cdf53018696db1c0a650e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "47c8bd81046d92f3452eeab8bac9bdc40c75936ef09365d825841ac7ca47f1d4", - "witnessHash": "47c8bd81046d92f3452eeab8bac9bdc40c75936ef09365d825841ac7ca47f1d4", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 410, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "8c012c1f7215a8f349a762108617c1f70931954b4a876a83dd10633f7c4dc581", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299428, - "value": 90000, - "script": "76a914292e209d298d032db33bbf7630b12d3fc2e6467888ac", - "coinbase": false, - "hash": "8c012c1f7215a8f349a762108617c1f70931954b4a876a83dd10633f7c4dc581", - "index": 1 - }, - "script": "483045022100e393a0bd7e525e5902a02a7bc5f0e068e78e35769c4432c603661b9ffe54e3ce0220353dc575c00e6c01ec04fbf744dcce2322713e62114de860648c99df362564d7014104040420a47a1c1e0f036b9bcdc27a65cb0984b242fca002c062fd1e9d65511ee2eff20b920a3af9b9179007c21e1d8622278c3b8e48372aad90ce098af9608877", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bac4c4f77ea5fbe7153f77202938367b5e675575792a5365ddaea90bbb198262", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299904, - "value": 1590000, - "script": "76a914292e209d298d032db33bbf7630b12d3fc2e6467888ac", - "coinbase": false, - "hash": "bac4c4f77ea5fbe7153f77202938367b5e675575792a5365ddaea90bbb198262", - "index": 1 - }, - "script": "493046022100a843216215697291a9f9e3979af34e99bacc7c6040ff7f12818f010a536d4395022100850b691aa9fcf54abd81751e5533b11607ad783e80d6cb40d8a3f8279e9c8382014104040420a47a1c1e0f036b9bcdc27a65cb0984b242fca002c062fd1e9d65511ee2eff20b920a3af9b9179007c21e1d8622278c3b8e48372aad90ce098af9608877", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2e8571f58adfcbb3e6ecdd62ae76494e1cd9b3a22e2944e03309f5f2b71ac1c4", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299987, - "value": 1590000, - "script": "76a914292e209d298d032db33bbf7630b12d3fc2e6467888ac", - "coinbase": false, - "hash": "2e8571f58adfcbb3e6ecdd62ae76494e1cd9b3a22e2944e03309f5f2b71ac1c4", - "index": 1 - }, - "script": "48304502205a428f100183920a3d2a25b422bf74f284c118cf0e7af8c3c3a638543f9f6b61022100a6f23f80e7585ec6b9bb2e575e0be1120f5110d780fd7e56bd839ed7a61bb65b014104040420a47a1c1e0f036b9bcdc27a65cb0984b242fca002c062fd1e9d65511ee2eff20b920a3af9b9179007c21e1d8622278c3b8e48372aad90ce098af9608877", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2500000, - "script": "76a91404305c6da9ae49b91469f19fa8930a05b436c2f588ac" - }, - { - "value": 760000, - "script": "76a914292e209d298d032db33bbf7630b12d3fc2e6467888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "23df19b39310369364fe62ae1bc9036bbd93183906fff659bc60e6e84f7a5350", - "witnessHash": "23df19b39310369364fe62ae1bc9036bbd93183906fff659bc60e6e84f7a5350", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 411, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e444436c9f41eb45043bc0f48d7b8b780b6547ae05d1256a7fd34df6c93669e0", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299879, - "value": 125076, - "script": "76a91456d399b3d328484138cb302c9a0148d5c3a6ff6788ac", - "coinbase": false, - "hash": "e444436c9f41eb45043bc0f48d7b8b780b6547ae05d1256a7fd34df6c93669e0", - "index": 1 - }, - "script": "48304502202c073a7ee6b1fa8a778a8432469d32ddf942557afc042078b9c9e09051a6e8a9022100ed2068a7a5a6f1391bef455243867b2d9e57512019fe2082d8e027db5800ece60141044c504815968d2226a0dcac740b203951d5faa9854e8055204ef6c44569460292e5f8c1a88953aeae27475a0163a812e573250945d2b1676d7c1dd3a37dbf2aa3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "edbbfde0d80075e52da78c304bbb0d9c28d8a9f905f99105a517a5ffb5224d7d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299881, - "value": 10000, - "script": "76a91456d399b3d328484138cb302c9a0148d5c3a6ff6788ac", - "coinbase": false, - "hash": "edbbfde0d80075e52da78c304bbb0d9c28d8a9f905f99105a517a5ffb5224d7d", - "index": 0 - }, - "script": "493046022100e7055f8ddc5d068496a9dbc2596c8778aed6112c49eb8d9f58003507d868f92e0221009524c0843b194b6fa60573308d9b3d6eff08fe3ef42e20c8270b8e78bf86de620141044c504815968d2226a0dcac740b203951d5faa9854e8055204ef6c44569460292e5f8c1a88953aeae27475a0163a812e573250945d2b1676d7c1dd3a37dbf2aa3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "94a5241c4eeda717a58d557e456697419cfa77fed8cb9e507452d9229bfaab05", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 30000000, - "script": "76a9142fe47b5c3d8088d9249fdd2cfb9969ef46946bc088ac", - "coinbase": false, - "hash": "94a5241c4eeda717a58d557e456697419cfa77fed8cb9e507452d9229bfaab05", - "index": 5 - }, - "script": "483045022100caac4b1c83cad903166b9ce6d58b939d0cd7cdefc07ca3a888552c1adf314dc00220540bfd02de6bccbcadb257159845447a4dcef285650231ad746fb9c45f1552c60141049d7fb3db416e09c7aa47daaac3a6f2ddd549e8b5b64e58f0ac7a266a535fdf5985f23581c259ff4c9e6a6f5e0a42e802b4f992b05920475e790085cc12982250", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 30000000, - "script": "76a9146f43e84e2c462dffc13b43df21981949d13de89888ac" - }, - { - "value": 125076, - "script": "76a91456d399b3d328484138cb302c9a0148d5c3a6ff6788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "bb1e3209b494b674237de2d8fc8a4902b4e2fd6c42d57365136011fead6a312f", - "witnessHash": "bb1e3209b494b674237de2d8fc8a4902b4e2fd6c42d57365136011fead6a312f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 412, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "1ad931bb0d0781dfa46bd8dd3c6f241108d1e49cc80d61ce52cd610cdd013258", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300009, - "value": 1820000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "1ad931bb0d0781dfa46bd8dd3c6f241108d1e49cc80d61ce52cd610cdd013258", - "index": 1 - }, - "script": "4930460221009e0d8197a0454e43afdd27e1d76b070b53f1a20bf8e8e61ef2330bded226c410022100f7b18dc3be0c6152da944184aaeddc5df4010e19c100cf125c82e23102c8534201410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dd66b6ef77a3b3f72a31921f659371d1e0be8a1e2df607bc50313f8c29de2d97", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 10000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "dd66b6ef77a3b3f72a31921f659371d1e0be8a1e2df607bc50313f8c29de2d97", - "index": 1 - }, - "script": "48304502206b5d3564771edcd8c61d491e2a7ff4099c665df9874d43254faa3088e428b1090221008f95e15ef7e857a44b06eae2c8ec00ebdbcc9fe7eba0b8c45b0c5897503a70f201410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "34cdfb8a56099d3e72e7f54179273e99fcbd58fbb4b72a44b73730ce0e2649ce", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 1780000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac", - "coinbase": false, - "hash": "34cdfb8a56099d3e72e7f54179273e99fcbd58fbb4b72a44b73730ce0e2649ce", - "index": 1 - }, - "script": "48304502203fc08b9dfb9ba97452d6c5c532169d88f5d359d242f1c20d0b13d5fc89698e5b022100a109ac371524c01f0540fde1637bbe56fb9a889aff740db5ffb1eb910da0c0dc01410448a7b4e3ec44fc73d42a566b8e2f92948765d32049c360cc8561ac63c455c7bac53da724164046c4bf7f1c8d25b3301acaf5c987c4047a83a82417f5e2be67b7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1900000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 1700000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "05473a1714b82763591a4c2549c845e2ffcbe3c56326f672f8bdd1a3d55b2a5a", - "witnessHash": "05473a1714b82763591a4c2549c845e2ffcbe3c56326f672f8bdd1a3d55b2a5a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 413, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bb1e3209b494b674237de2d8fc8a4902b4e2fd6c42d57365136011fead6a312f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1900000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "bb1e3209b494b674237de2d8fc8a4902b4e2fd6c42d57365136011fead6a312f", - "index": 0 - }, - "script": "483045022100da7a2b790db754f6a78f23198eafd6ad37f29e586edac722088bdb492a48016702203708443a0158d33fa136345dc44a3233147fb67bcaaa3715ee08424145c36b8f0121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1890000, - "script": "76a9144dccba2bf57f8d639f30a0f77d62fbcfa5290e7488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2596c9633ae8fe573278e48fe7dfda751e5f8b630234c69c75e5e398da127397", - "witnessHash": "2596c9633ae8fe573278e48fe7dfda751e5f8b630234c69c75e5e398da127397", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 414, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2f5c7a8afd7a00fca6b747754ce904978e8f5966fd3dac315a817e26e646e4fb", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 3325000, - "script": "76a9143ee4ffe242d35ca3e4ea053dc78f02a7fcc0341e88ac", - "coinbase": false, - "hash": "2f5c7a8afd7a00fca6b747754ce904978e8f5966fd3dac315a817e26e646e4fb", - "index": 1 - }, - "script": "483045022100ba164f97978fbed50613bded8bd38ff6a0cf9f155e0eb23903e7d4755223d34602206d5c1603f382eddb47481af46cf4a2174576b61b8db404e37b86e652e880ecad014104234dda6f8ed186102cc545b1a96df1e05f156bfdd4c77eaa44ab718cbae96f9a987adf2bc7b0e51e842dc89ca016fc25745911354a201facd5ee5cab49b981b2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1991d117785fc3ecc712de706828d17a80fd900f4ec25043014a7ee9b86fc465", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 10000, - "script": "76a9143ee4ffe242d35ca3e4ea053dc78f02a7fcc0341e88ac", - "coinbase": false, - "hash": "1991d117785fc3ecc712de706828d17a80fd900f4ec25043014a7ee9b86fc465", - "index": 1 - }, - "script": "493046022100d361bbb9c31f006e391e48a407bffe45fd4346776944facc9028af0646a5b680022100f5fbcdbbb71b5de0116784d0a62565fe081ff1d4cc9adda713bca5bf2867e0bb014104234dda6f8ed186102cc545b1a96df1e05f156bfdd4c77eaa44ab718cbae96f9a987adf2bc7b0e51e842dc89ca016fc25745911354a201facd5ee5cab49b981b2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e61faabc2a8b2d23b6b376bfc219431c5968cd8a78d6e537633a8c78eb187858", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 10180000, - "script": "76a9143ee4ffe242d35ca3e4ea053dc78f02a7fcc0341e88ac", - "coinbase": false, - "hash": "e61faabc2a8b2d23b6b376bfc219431c5968cd8a78d6e537633a8c78eb187858", - "index": 1 - }, - "script": "483045022100aea10a365eaf8eb2604e8322cb0aba5afa8a73bc8be0b5da3e7f41939a20cae40220181dc995be5f24510a56b64cd7039059b6c6e6cff6663fd823e2245f27d313f6014104234dda6f8ed186102cc545b1a96df1e05f156bfdd4c77eaa44ab718cbae96f9a987adf2bc7b0e51e842dc89ca016fc25745911354a201facd5ee5cab49b981b2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2800000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac" - }, - { - "value": 10705000, - "script": "76a9143ee4ffe242d35ca3e4ea053dc78f02a7fcc0341e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3fb7ebfbb23edd275807130ab5d092a3c1e78703fd079d65b24ea2a16ddcf2b5", - "witnessHash": "3fb7ebfbb23edd275807130ab5d092a3c1e78703fd079d65b24ea2a16ddcf2b5", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 415, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2596c9633ae8fe573278e48fe7dfda751e5f8b630234c69c75e5e398da127397", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2800000, - "script": "76a914a48b825a1a10309dcbaa0441b623eeab0cda273588ac", - "coinbase": false, - "hash": "2596c9633ae8fe573278e48fe7dfda751e5f8b630234c69c75e5e398da127397", - "index": 0 - }, - "script": "483045022100f9e16e4c75d64ddca0fcb9a16aff029afbb9ad29fb57187970559c7a0293422402202b2e0a55decfb07db042b8abc632775b76bedd4e73ccf00b7a0aad8c7552640a012103082934de52ac6d2d5f0806d5ad5bd240e7733d75952d2cb06ba4b782ca4ed0d6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2780000, - "script": "76a9143dfeb05e14625b32bfe7be9c5454e599dc2d74b788ac" - }, - { - "value": 10000, - "script": "76a9143ee4ffe242d35ca3e4ea053dc78f02a7fcc0341e88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5f21a6529eea61bee04386318caedd18282c77b2e257821fc3d258befc3b9f43", - "witnessHash": "5f21a6529eea61bee04386318caedd18282c77b2e257821fc3d258befc3b9f43", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 416, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "669b50ed77b11217122bdd22528d50f40456ba8d6a0ca7046340f1f40dcfe44e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac", - "coinbase": false, - "hash": "669b50ed77b11217122bdd22528d50f40456ba8d6a0ca7046340f1f40dcfe44e", - "index": 0 - }, - "script": "483045022100f43129c3dc958c2d94dfcc645c8e8bc5b7fe6d83e139eb138157a1990a6cf44a02205d15542d523784e11b192a50621c74e2dad5c004a072c9099615823c16dc2add014104e104b1a7cdb22d7ee5acf80865fb952360ff0af8498a7d141a5fe4d33742ecfa42ec49ff4eb8313b57cefea35b9e916cb39fa1405b3b8944f369220094bbb3cf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "209cf32afd54f3ac3cb8281361672c6c93e9cd79086bfcb9605f0b548a614856", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 10000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac", - "coinbase": false, - "hash": "209cf32afd54f3ac3cb8281361672c6c93e9cd79086bfcb9605f0b548a614856", - "index": 0 - }, - "script": "49304602210085679530b03801746ecdd4296adaeaecfc5ab5be3c1c5e7b559de899af4fe712022100b8f1c3046f69f7abf8491377dbd82267c5d5b9540a5a8816294aa0b40e1fdadc014104e104b1a7cdb22d7ee5acf80865fb952360ff0af8498a7d141a5fe4d33742ecfa42ec49ff4eb8313b57cefea35b9e916cb39fa1405b3b8944f369220094bbb3cf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e8b6d97295a4e7f4ce1748d486fb653cfc31eb5e6bef2e9bc929a40f5107ceea", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 3850000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac", - "coinbase": false, - "hash": "e8b6d97295a4e7f4ce1748d486fb653cfc31eb5e6bef2e9bc929a40f5107ceea", - "index": 0 - }, - "script": "483045022100af977847d57d036ed73563ae6aeb9ba9578446446a14f21633017222df540e70022039eae3a8c2d99c92909f8a287df7545ec6745e6ced9d72f662425464c64dedb6014104e104b1a7cdb22d7ee5acf80865fb952360ff0af8498a7d141a5fe4d33742ecfa42ec49ff4eb8313b57cefea35b9e916cb39fa1405b3b8944f369220094bbb3cf", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2800000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 1060000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5d7d97093c1bc4f1b7502d5b8a57345557f8bb3a43f65b1c59ed27ee5688358e", - "witnessHash": "5d7d97093c1bc4f1b7502d5b8a57345557f8bb3a43f65b1c59ed27ee5688358e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 417, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5f21a6529eea61bee04386318caedd18282c77b2e257821fc3d258befc3b9f43", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2800000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "5f21a6529eea61bee04386318caedd18282c77b2e257821fc3d258befc3b9f43", - "index": 0 - }, - "script": "4730440220188a5e7e736dfe398367411ba5d6fcf1e416ff7cad8eacab2dea91ac1fd6e07c02206ea3eaa6e8410e889a7d20749b4baf0468cab635880dac3b69d243296662f2890121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2790000, - "script": "76a91484f8e86e0c5b63d57f3c05e3e0152ce40e86020088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9f3161fd83c30070ca715b7e1f3f7edaa8542f6c1b04e3658b3a6985ec3c79e3", - "witnessHash": "9f3161fd83c30070ca715b7e1f3f7edaa8542f6c1b04e3658b3a6985ec3c79e3", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 418, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "833134f7294b463140285526461b962c366316c594dbdad156eb1e8506f90b48", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1700000, - "script": "76a91439487a1300ef94b72b8f72cf81d6eef17550a4d488ac", - "coinbase": false, - "hash": "833134f7294b463140285526461b962c366316c594dbdad156eb1e8506f90b48", - "index": 0 - }, - "script": "4730440220235f22a1ba0db24fd52e4fcb2573a99b8027f91b8bf8bf699f3fa9ac8a53e3080220133c1fbcbaa1f0e09710e8e1db26a20ff92105bb8947efb50149706612055a36012103afd34045d7080e5f3d8fc0efab187951caed4b06571c7cc617d01d9abe8b36b5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "29fdee8fc1dcd2240f6066a0bd636aadf4d7a394a687d74aa0f17643f70dd056", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 306167, - "script": "76a914f42f924dbad1de266f02d1c5054085a0527da61f88ac", - "coinbase": false, - "hash": "29fdee8fc1dcd2240f6066a0bd636aadf4d7a394a687d74aa0f17643f70dd056", - "index": 0 - }, - "script": "47304402201a565adf1e3435d38069c13e4cb705fc76e7877a45f848b1c13fbb337365794a02202c3c172485565704fca5c596ee53b30eb6a1be077815018fcddf14cc295fde09012103f53c59c6119fc8584763dc3ae50e10c0dc71573cde9a4c80497d037592241e17", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2aa2c5588031bf7a21509f7a3b0718d0efeebcd4b52def0a24e047139ed8cb9b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 415004, - "script": "76a914788de3e892875e1652dfdf9bf9677b84086e415388ac", - "coinbase": false, - "hash": "2aa2c5588031bf7a21509f7a3b0718d0efeebcd4b52def0a24e047139ed8cb9b", - "index": 1 - }, - "script": "4730440220503d11f1c6d04843efb9d4ef4b814ed79b9af457de76b87d5cefd9ee3bfce6ef022048abe9164f29440580b44e7b220beb398a559138af0541ef2e52cc61af4a71660121039825548e7935988a268c4f56a3f42a9ca18a78f75089261bca28a5fd57020e99", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2f5c7a8afd7a00fca6b747754ce904978e8f5966fd3dac315a817e26e646e4fb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 945128, - "script": "76a914fb2cc2d580e8db8440810e9f4ba58ea8f86b59a188ac", - "coinbase": false, - "hash": "2f5c7a8afd7a00fca6b747754ce904978e8f5966fd3dac315a817e26e646e4fb", - "index": 0 - }, - "script": "483045022100e2593a7607b2f4db61c25dd48592ccb055c73fa6c9d180677e1192fcdc98005d02206e7204e41e8248b1501b47336319b15883cd9d15b47edbed5558d1df8a6ca30f012102bcca29223dd34858f5ca1e2c6513258455d6763e42a113c2ac46216fa9224dd1", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 381299, - "script": "76a914f42f924dbad1de266f02d1c5054085a0527da61f88ac" - }, - { - "value": 2975000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "eff4cc10df0bf0c5fb76fa58e388b7255dce8e19b1db8e2440dbf635236311fc", - "witnessHash": "eff4cc10df0bf0c5fb76fa58e388b7255dce8e19b1db8e2440dbf635236311fc", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 419, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "530f4e3ae27b5ece4a63e38096de02d6ad8aa65af7bfbcc053c4268067053e35", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 10000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac", - "coinbase": false, - "hash": "530f4e3ae27b5ece4a63e38096de02d6ad8aa65af7bfbcc053c4268067053e35", - "index": 1 - }, - "script": "493046022100f34770188ed5ec96687b825558b0cac92e354cd3016f7c42a5c85dfff9fe18d7022100e371cc886e03bd1c3652ee08249857bedec71c53afce351608b92c7ff4cb2de001410408e0b2378aa23e30a4de4774fdf540f6a72449c99d29ace5a07ef04537dbf29504b7c4c4d5f82a0f949a7f039e386d68a3f1d04da7c86988311ae7ac824c9cb7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ca7a6cbad1676b3b096be7584af7ebac5d2c5ff5542f271a230377778f115b00", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2450000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac", - "coinbase": false, - "hash": "ca7a6cbad1676b3b096be7584af7ebac5d2c5ff5542f271a230377778f115b00", - "index": 0 - }, - "script": "483045022100e20d5bf6192577a58973f7452114abb51d1f328fafce2021d0f91690eaf5ba66022019b9336ba539aaf9116317c3720739e2c14e2403ddc4e7d683e2b13518e8676101410408e0b2378aa23e30a4de4774fdf540f6a72449c99d29ace5a07ef04537dbf29504b7c4c4d5f82a0f949a7f039e386d68a3f1d04da7c86988311ae7ac824c9cb7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9f3161fd83c30070ca715b7e1f3f7edaa8542f6c1b04e3658b3a6985ec3c79e3", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2975000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac", - "coinbase": false, - "hash": "9f3161fd83c30070ca715b7e1f3f7edaa8542f6c1b04e3658b3a6985ec3c79e3", - "index": 1 - }, - "script": "473044022055017abd4677dd1cf5cc3e45ac1e2535034cf097ef678ad2ed704dab1a940fb202206923f2fe5af568aadbe1cb9c44398c593f96b56bbd1d58abe04d2196b9a2c47101410408e0b2378aa23e30a4de4774fdf540f6a72449c99d29ace5a07ef04537dbf29504b7c4c4d5f82a0f949a7f039e386d68a3f1d04da7c86988311ae7ac824c9cb7", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2400000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac" - }, - { - "value": 3025000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d7af7189e0413f0a8a3196c88eeae139cda6ebed7c3bf7c08e935fa0a522e9ec", - "witnessHash": "d7af7189e0413f0a8a3196c88eeae139cda6ebed7c3bf7c08e935fa0a522e9ec", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 420, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "eff4cc10df0bf0c5fb76fa58e388b7255dce8e19b1db8e2440dbf635236311fc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2400000, - "script": "76a9149d3f4d63e5e219a8650adbfd4988a440c36151bd88ac", - "coinbase": false, - "hash": "eff4cc10df0bf0c5fb76fa58e388b7255dce8e19b1db8e2440dbf635236311fc", - "index": 0 - }, - "script": "483045022100b6931d6acedc18af238cd113e11c222680735db5eb27f6d7c81fe7587ba0cbba02206acc26a7bd167d321595182d89394b394371be9a16dbad53d939a7fe5d179d430121029a286ed95f951c9f08fde917484676b2a7578f16f16b86fd887f124995de4f5f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 2390000, - "script": "76a914c155bbf97a7e153008badab6e745184614e8426588ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "f5bbb1351ab5c53ef1543d87fee9abc124d81d6247679bc6b24ff2c10db15b87", - "witnessHash": "f5bbb1351ab5c53ef1543d87fee9abc124d81d6247679bc6b24ff2c10db15b87", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 421, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "d6ab1f1e1ba112447b8b06a0fb676b62986bffe0ba9af4e6137587a5782fb074", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299971, - "value": 19980000, - "script": "76a9148a230ee7f9252c2ec48795c10d967d5e9674771088ac", - "coinbase": false, - "hash": "d6ab1f1e1ba112447b8b06a0fb676b62986bffe0ba9af4e6137587a5782fb074", - "index": 0 - }, - "script": "4830450221008f9b291abc83c20479583bb9415cc4e7f6d9334565a3f1057f8a13a08dfdf0cb02207dc6a109c61cf36cba267d71d46d840c3602d0afe66fe67110a08e300ffb9b7d01210375a4f74749c455762283c130b3f4be76ecb328835065acdfc7f30cd0fdbab720", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5b0d7a2c20f79870db3fb40442a712e560677d7b9e002f0f9260e1e223dbd821", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299960, - "value": 6000000, - "script": "76a914ab745fc00ba0c8f3dd40999650a2527749f0fe8188ac", - "coinbase": false, - "hash": "5b0d7a2c20f79870db3fb40442a712e560677d7b9e002f0f9260e1e223dbd821", - "index": 1 - }, - "script": "473044022045e6b7cbdb1502b192ccbdbb1fc98b34aee09a168b2cb06bc91608d4ae459e7a022052e6823336505c999040bd9a27fe4f05d07962225be475d20c9e02cf85cf4026012102977ed868dd339c73e7816aaf412b6cfbda9fc1cfade3dfa0d8e918dea002c45f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f4e8a9c9202c1942985e8faa4522b80e7c6803b2fe87ef1e8f913eeb0316bcad", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 9990000, - "script": "76a9148b108c319344c6fdcf2232acff475d5876f3c89c88ac", - "coinbase": false, - "hash": "f4e8a9c9202c1942985e8faa4522b80e7c6803b2fe87ef1e8f913eeb0316bcad", - "index": 0 - }, - "script": "473044022022b6db44c782320951f823688774e7b622290518fd7a73e589c604ab1f6a2ab2022044f8c3704505f7ea6d1b2b5be874bf738f46b7ec1d683ca199784b167191dc61012102768d86fc99754f8574fe91a0150fd4c9e44938474449f4773e96dae93b37ba85", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4a1124959551d9341e8251e583e941eebcc03f18bfde95a095934d3efb952ee3", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 6000000, - "script": "76a914ab745fc00ba0c8f3dd40999650a2527749f0fe8188ac", - "coinbase": false, - "hash": "4a1124959551d9341e8251e583e941eebcc03f18bfde95a095934d3efb952ee3", - "index": 1 - }, - "script": "48304502210096abbf805663f338910c39dc4d4678c33cb40e0b5210e6ff6d296f017040150e02202421c512844cf9aae3144ef4796f86c6423851a465b7dd892941028614d14a1e012102977ed868dd339c73e7816aaf412b6cfbda9fc1cfade3dfa0d8e918dea002c45f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1515192, - "script": "76a91476709fe3e30c6d691677c4d289964474922c4f6288ac" - }, - { - "value": 40444808, - "script": "76a9143661433ac657d59f5fa3f6b2cb903b67f6a0b6da88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3d6241e48e7f8869ef21044bc396f526e0c59b1e4a121b2f38f82872fc18ef64", - "witnessHash": "3d6241e48e7f8869ef21044bc396f526e0c59b1e4a121b2f38f82872fc18ef64", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 422, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "867f5e4a6a5937789107a65df2623e0ccab65591711660a3c556202859d319cc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1216928, - "script": "76a9148a44eae0b80e6e59144906649df82794077690b888ac", - "coinbase": false, - "hash": "867f5e4a6a5937789107a65df2623e0ccab65591711660a3c556202859d319cc", - "index": 0 - }, - "script": "4730440220519cd5739d2691664551f097a0b7b4d6d4af0542ebf1414b7cbeab28a50dd94802200228c4aad56e9ba13100b3c766bc09ad9b05310be09c3440e3f819c7220ea7dc012103c2727b202a8a02d5e9898df8437adb2a4574c830aebacd5121fbc017332fdd57", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bc00a2ce19906c12f999f86997dc66bb675c4ea6dd738867d4b323800ff42f29", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299990, - "value": 9940000, - "script": "76a914386f6d320e2d67ce48f3de940a149e72472c5c4b88ac", - "coinbase": false, - "hash": "bc00a2ce19906c12f999f86997dc66bb675c4ea6dd738867d4b323800ff42f29", - "index": 0 - }, - "script": "483045022100e9ad89f05420a4e6851841f55436051f7b2732ab5325e6b142804c839b6fdf33022023ec2ca587adf9953491809eb66b6e73b35648eb7d77fc46d7060b4fbf1beec50121024ab35d9780005e89b5f19d1e2a363bf542719cd716cc3ec11977bf65201100f7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5e2d00a93760438cac0f040c56c9f924c0aa4fb64b4b2606d4eec2e7c7f1a444", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1265102, - "script": "76a91488d2c3f6fa466fcd8543543c24f6f521b91fe47788ac", - "coinbase": false, - "hash": "5e2d00a93760438cac0f040c56c9f924c0aa4fb64b4b2606d4eec2e7c7f1a444", - "index": 0 - }, - "script": "483045022100c3742969f1138716f619f21e2691f31f0547382129bbb0d0f6eacb4f8a70084e02201b3da7b3336315aac95dad0cddf467bc4b300627847f50b8ffbcec8c6451f8610121033818d003072db940b9ac8b12f86a1a1a544ff45fd3834c9d97cfdbb24535bcc4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3d2faeb23296b10cdb6073b7d12037890a1d4d27fdb18cb9b2e6298a3eb1d1dd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1432089, - "script": "76a91487996b75bbbfe66ecb3057c84025113bf8e0b99288ac", - "coinbase": false, - "hash": "3d2faeb23296b10cdb6073b7d12037890a1d4d27fdb18cb9b2e6298a3eb1d1dd", - "index": 0 - }, - "script": "473044022036f9679e0391728f757a38c9d8d290626377616626fd187db7f6a497a99cd0e002202528f8bd3d7bacbefa719f5f28475d9596d23e505571642c80389adbde1a9d2c01210224f0a1ea4c7a0ec22fe1da9506d0ac3a402d7925f777443553ac6a2a8f705d7a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 12644560, - "script": "76a914f9060b9b96663cd154c1a4c9b47def11c75c147288ac" - }, - { - "value": 1199559, - "script": "76a914f1b0f3bc78b8c898247a709e73a6497c53bf2d7d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "92fb83ccb76bcbaf223400a4104d6726d075d89031f345f52835d89ae6d89e07", - "witnessHash": "92fb83ccb76bcbaf223400a4104d6726d075d89031f345f52835d89ae6d89e07", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 423, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5119cd2e7f7381801d32a01a326713c40ed87c20196cabc078ce730eeb2d4865", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299709, - "value": 10000000, - "script": "76a91447ab4db7a718983092a750b0eb5fd99397c5fd5588ac", - "coinbase": false, - "hash": "5119cd2e7f7381801d32a01a326713c40ed87c20196cabc078ce730eeb2d4865", - "index": 1 - }, - "script": "483045022100ac7dcdce544ac52cd5fe2a10cf8412dd7790d6ed2b2818109ef1230a7be1ac9e02204111645906669dd6e84bc8002f42ffba17ed9f3eeccc239b04d413ca547de51a012102253a3018b8d4afd23a2ebc25ef18ae624d448f12924a2e7da3484a756ef9aee4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "59bcd375a284c42d4192eac28abdf8b0b5ff6de4c627e99b68747dea18d80fe6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299717, - "value": 12000000, - "script": "76a91447ab4db7a718983092a750b0eb5fd99397c5fd5588ac", - "coinbase": false, - "hash": "59bcd375a284c42d4192eac28abdf8b0b5ff6de4c627e99b68747dea18d80fe6", - "index": 0 - }, - "script": "48304502210087ee0291446282ce0a0b7f19328bfac6fc5ca89d6e9267647ae6a4705ec35b5d02202eb349f835b0b37f8f8774e78619b7d2b446b59d27e056977e2cb94cf6830a6f012102253a3018b8d4afd23a2ebc25ef18ae624d448f12924a2e7da3484a756ef9aee4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "20e62e35369085a9eed4f4149b5344559778d418f788bc7ebf1a124d5fd4e44d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299018, - "value": 4035000, - "script": "76a91461c40cfd8090ddb7f04ec1a1cbcd2986a526ab7088ac", - "coinbase": false, - "hash": "20e62e35369085a9eed4f4149b5344559778d418f788bc7ebf1a124d5fd4e44d", - "index": 1 - }, - "script": "47304402202074379f5efb33533157da2a3d742d95b9781b038de2ea4fc528631d295738e802206215731ed048c62c60714d9580eebe4a6b23ff50731c441f77236e73c846ce160121026b1f3905e013136c982604a255ff32fc8d24799dcd2e3a3c0e10340e15294fa7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "639722361df4d68f92527d3da58d0f34fd06eda0785ed98166659e811afad584", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299609, - "value": 500000000, - "script": "76a91438fc5a9ac96d66706f0da3e3827a140e59e170f388ac", - "coinbase": false, - "hash": "639722361df4d68f92527d3da58d0f34fd06eda0785ed98166659e811afad584", - "index": 0 - }, - "script": "483045022100c5cae7f9fffa1b69fb1e8cc65d9b8265cab9795148cbfc644ba1e169fcae7f340220487a343af0f3e2d462c5783683d3404b6fe0ec78e0e538e05021d253744b4092012103e4e15e76dae6c5f5c99857d9a0020a6986c352ba219531ec9ff0d3ae5eeebd33", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1025000, - "script": "76a914d0b0d1bc89fec562fc3c5739c06cb19ca9213f5388ac" - }, - { - "value": 525000000, - "script": "76a914c4b65b5ae5492fb89cf2ef0af8272fc857ec255388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "cba9ede8786b12994ceb35023c9d59ee51fff7211432d894481459e353e6f74e", - "witnessHash": "cba9ede8786b12994ceb35023c9d59ee51fff7211432d894481459e353e6f74e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 424, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ac375ebed5d83b0d11a8aa67ccfe871de10946fd8c5ecd07a23e3033bd6e0fdc", - "index": 150 - }, - "coin": { - "version": 1, - "height": 286229, - "value": 7273315, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "ac375ebed5d83b0d11a8aa67ccfe871de10946fd8c5ecd07a23e3033bd6e0fdc", - "index": 150 - }, - "script": "48304502201968b9cf6f04836a428c5f79a375ec2a71787c0e8d2c47bbb981f21cc157d1870221009573e3122de5ad3d58e87f801233e73ee5e92296de74d0b19d06143eeaf6a3b90121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "948808f63b060e4733a7fffe610f2b644e0f2258724c4b2af5c37415fa37ffe5", - "index": 150 - }, - "coin": { - "version": 1, - "height": 290887, - "value": 5299350, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "948808f63b060e4733a7fffe610f2b644e0f2258724c4b2af5c37415fa37ffe5", - "index": 150 - }, - "script": "47304402201b3e7db4e854ab7af9043edc7734096a0293efd39336343371c72c8b66f1e3ab02202ed96871d07fa8e0f1326042609e82e3d166191dca455def88f7ae8b6fca88f30121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "88c6393fbde7b0f621f4bd982fdfac856f0b80c1fb67a6f18642beb0cf7f0a04", - "index": 150 - }, - "coin": { - "version": 1, - "height": 287435, - "value": 6565020, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "88c6393fbde7b0f621f4bd982fdfac856f0b80c1fb67a6f18642beb0cf7f0a04", - "index": 150 - }, - "script": "47304402200e57d7e1db32dc085fa98ad795c37f08ba43f14a91625fb84f042766fe1ec78f0220008beeeb728fcdf554b3044b6694c6e050b09a7f806113be9699141f0c4082790121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "54585341ef96a683d43e1547db782401c97d7b17fa75938a7ae8fe0cc4600609", - "index": 155 - }, - "coin": { - "version": 1, - "height": 284992, - "value": 9477090, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "54585341ef96a683d43e1547db782401c97d7b17fa75938a7ae8fe0cc4600609", - "index": 155 - }, - "script": "493046022100cb5344dd9a2be4fd704eae31c275c3d78ddfc02ece7b1cd3968eb9d833e364bd022100db0cb1e5bf006b26fdec4881c47e3bdbbacdec76f145aea97439a1c4cca46d7f0121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7ef2f95249fc0a9914006503aec4c778090798fdd1a82cafca2d73d95478b681", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298340, - "value": 1045328, - "script": "76a9145bbd1efc540bbe7cea3bb3dbc8dbef1f14a74fab88ac", - "coinbase": false, - "hash": "7ef2f95249fc0a9914006503aec4c778090798fdd1a82cafca2d73d95478b681", - "index": 1 - }, - "script": "493046022100933caa57e254e7b3ce983c43daffb9c5215c718034a2e377fcae1c5e478b8248022100d23fd97bb7da78b092c48d495c9600c45fbe9df8191572abdef46cca05e05baa012102e16e65b7fd50ccde1c7bfda84e92a4005ce95018f82550000b6e25ec3ce743f9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "24975358f660dcb80324d7edfa2a6f09cb0e46c7e8b08c8c19b49e0b48692a93", - "index": 150 - }, - "coin": { - "version": 1, - "height": 288641, - "value": 6707365, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "24975358f660dcb80324d7edfa2a6f09cb0e46c7e8b08c8c19b49e0b48692a93", - "index": 150 - }, - "script": "473044022007c452d79f24d804048308783852d742b2ef8e3bf5cb0c4f39d8e172dad726e4022076cf0804de5cc101190556d5077693cec637346666849648a7e5ff9ed44ffa240121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c97f362c46112a9b25c79e26641c20ad673831bc2fe18456458824163d611a4d", - "index": 156 - }, - "coin": { - "version": 1, - "height": 283803, - "value": 10428915, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "c97f362c46112a9b25c79e26641c20ad673831bc2fe18456458824163d611a4d", - "index": 156 - }, - "script": "473044022022dcf0bcb29024aa1da3c07bd78d749f2de438b3d7ac4bebe0e774b6c5baec140220422a13bdf147be5735cba86f567a8e06325192e304c78ba0f1000db5f69435dd0121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e14a963038b1cea05803702761eb0251eb1432861d2b5804ac9cb5c247411d4c", - "index": 144 - }, - "coin": { - "version": 1, - "height": 295661, - "value": 30660770, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "e14a963038b1cea05803702761eb0251eb1432861d2b5804ac9cb5c247411d4c", - "index": 144 - }, - "script": "483045022074dac03981ba56d08e938e7d56fdb98fb55b47b1d9924624b83073ffb97c0ae6022100a479c64296baf7cde30e5b35f56539550c68b64667505d66a1507fc6a73430560121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "65fb438561c120471b97488847d8f8648fdc0027b05bc252dc5d9aefa6ef57c1", - "index": 150 - }, - "coin": { - "version": 1, - "height": 289747, - "value": 4892895, - "script": "76a914906be421fac0166422d341a78de3339d6722718888ac", - "coinbase": false, - "hash": "65fb438561c120471b97488847d8f8648fdc0027b05bc252dc5d9aefa6ef57c1", - "index": 150 - }, - "script": "48304502203e057517dd82e16777d51dffe6123c150fea8dc44e26180d540762d635982d63022100b75d4cb9873d454eb69612bfe3c0009756853b2ae01e4850dc9dd52abfe6ad040121028db7d30d096282cfa0472e4dbf59155301df5dde93fbe47312539937206e47ba", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 82330048, - "script": "76a914f2954b6e6eea412034aceeab9e8c4f7a8ebff6b188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "73250d51c1c51b318db872362fb0875b3a403c4ef011be7688ad78f1640cc727", - "witnessHash": "73250d51c1c51b318db872362fb0875b3a403c4ef011be7688ad78f1640cc727", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 425, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "338d72890609397bca9de5624029b4cfe4799698bd73ec0a5ab139ad6971dcd7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298401, - "value": 126710, - "script": "76a9148b1e0e7d92ccdf0247c6d22b26d1b40b5d532b7d88ac", - "coinbase": false, - "hash": "338d72890609397bca9de5624029b4cfe4799698bd73ec0a5ab139ad6971dcd7", - "index": 0 - }, - "script": "473044022067b52ec273537eeb32fdd66478616eb17a0b706e2ce460c58754bcd228a4612a02206219c849c05132b5532944937ad6a3665f96c456843fa90f70c4107582619acf01210377f2fd2cc39ae425b8fef5c36612d73ad29954da8c1d4d8050719ca466b37257", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 552 - }, - "coin": { - "version": 1, - "height": 299989, - "value": 16980000, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 552 - }, - "script": "483045022003ff8c555186062fe4ca09c05820b8a1b1abb23aa371fae4bc02c04225bc17a50221009c15f7a9ade50fc3f73db25d3f71bc46eb27fd10f8e0c520195f11bb9034babd012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 40 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 33957423, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "736503603c664044d44622aa8d1534af9ba7804fd8da5d70d8385ba0ab5cc8f4", - "index": 40 - }, - "script": "493046022100a510f3dd46638d0460c7c1b9613c9c9302b5cab7297fa366d0ec7fb5eff0f4c2022100a28f68c4204a5b840d7a8fad564780d2662e249bfd2ec7eae907ea3a86f298f2012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ee7545f30601db733726e854dcb3835ababe93db94a3a58a37cbade4562aaaa", - "index": 11 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 33970518, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "4ee7545f30601db733726e854dcb3835ababe93db94a3a58a37cbade4562aaaa", - "index": 11 - }, - "script": "48304502205d1a4e62bab69c60336df0415b48c82be47d80b1ea9903820d716a88a510f13b022100fa9a3f73dde6c4c81df44526d6f2ade5ff8d51721b3fde940ddf00b689f4d2b3012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1125772f810c64c5b83f74c3cd0cb6807efb0c2e3bf31f2585a885edce033e07", - "index": 78 - }, - "coin": { - "version": 1, - "height": 299867, - "value": 38245765, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "1125772f810c64c5b83f74c3cd0cb6807efb0c2e3bf31f2585a885edce033e07", - "index": 78 - }, - "script": "4830450221008a3f1e6206c741c34e9132ee5225bbe467b6e2059c7657ff372e33ed2b192ed102200db5fff35f5c4d5dc6fb788a38099da0bdc2d4a708a0db7846b1885f13b252d7012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b31a98c5ca7d274882b930380b8716b5c0ce9b24625b301104e3cf926a2ceec", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299674, - "value": 184723, - "script": "76a91480baa22d422d91211a8fe2d3dac369804451216788ac", - "coinbase": false, - "hash": "4b31a98c5ca7d274882b930380b8716b5c0ce9b24625b301104e3cf926a2ceec", - "index": 1 - }, - "script": "483045022021d1bd3f691bad961929319b5c7a946f126c2a8431c58bec4cd583b4b7368040022100bee212086692e763747eb4783f93c04cd1f2a8922f39c899469acaa7ae8593e901210322bdb897fa51f20437991e24ecd67407b39ddcf8751d0140868cd75296d6ab91", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0ed3917a39ef4c58ad0ff1fe0099b25794fda951116d1ea4ccf0af19e691cdb6", - "index": 35 - }, - "coin": { - "version": 1, - "height": 299686, - "value": 36145029, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "0ed3917a39ef4c58ad0ff1fe0099b25794fda951116d1ea4ccf0af19e691cdb6", - "index": 35 - }, - "script": "493046022100ebbde6f489fac91f2c63d7ec9ed27fa9965b12fed74a401037cd787a47358348022100a25df1ae6480035af2afa8fc70f0916d578057d4c9a8ba88c57bae5749e24605012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d7f8b09b8cc8b01132022a6fe56268daecf9b58f5fac1bfe793a67f742495215", - "index": 72 - }, - "coin": { - "version": 1, - "height": 299795, - "value": 34990228, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "d7f8b09b8cc8b01132022a6fe56268daecf9b58f5fac1bfe793a67f742495215", - "index": 72 - }, - "script": "47304402203d1cc790b239a0a6a9a37b631794d6abfa9238e8f509534fb30dfba49c92b8dc02206b74bda058178524dade139c4d2a78ad03a6c53f919af89935e408a4a3b696f0012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4eb649ea1c85956a9059e24d41ee0d972572ca4c18aab0d96f1698d94d8b417f", - "index": 564 - }, - "coin": { - "version": 1, - "height": 299822, - "value": 16810000, - "script": "76a914d52a805a8a2bd4e45616be2a268a540c33eec36988ac", - "coinbase": false, - "hash": "4eb649ea1c85956a9059e24d41ee0d972572ca4c18aab0d96f1698d94d8b417f", - "index": 564 - }, - "script": "473044022068f20e98d29d198fc95408caa05ef606ac33f4184687dab42a4ddbea3568270f0220391916957360293399642b6cddafd89acef6e44e4ba9ec2aa0069ab13da378ca012102e358fbd042e1468ed95efd8801faa6a40c5978aed536b817f8b889a3d21e2672", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 211300000, - "script": "76a914eeb28d08ba975cc4935e533d177df4afce3f13cc88ac" - }, - { - "value": 90396, - "script": "76a9141757933c24c9a515d6738a04026ffe7b42a4a0ce88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9822434809fe66c59bef56cca22c7aead23ad7e9127898d49f811422bc8413f9", - "witnessHash": "9822434809fe66c59bef56cca22c7aead23ad7e9127898d49f811422bc8413f9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 426, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a62970947d77324014fe23084dedb8c92a7712b3658b30697ce1e16d93de9963", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1147051, - "script": "76a91494c97f7f7e338bc96e877063ca35f84cc606965188ac", - "coinbase": false, - "hash": "a62970947d77324014fe23084dedb8c92a7712b3658b30697ce1e16d93de9963", - "index": 1 - }, - "script": "473044022012eeb96527f18783639b680f327c37a6a5f3fb6f9af71231cf614f9c14aed02a0220169bafaa9368d456a2268434674017ee69488eef45eab49ab25579e251d45f0f012103c580e8e71727e91d0cc31b3158b82be336aa2ab3124bcc3b337484a8f5421cb4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fb5614ddf4d05ebca913835daddfa84f267636d49c3bb14ef487c2a73675e788", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 100000000, - "script": "76a914cecafa021013cd18d4e29748d3f751edc57d081e88ac", - "coinbase": false, - "hash": "fb5614ddf4d05ebca913835daddfa84f267636d49c3bb14ef487c2a73675e788", - "index": 0 - }, - "script": "483045022079af9d5cd0974fb681775769a4a76344d98c3bfa6c77f05efe27f13ccccc5207022100b54a5e3dc07631e088355d675f3e9115673d4ee0a3de77726a9d65e471d207f501410466c1b7ecfe283bf899e93688878de6752dca59233c54d0a6daea6fa80f10ea0e935335ee811f2958d5b61020b9b5b0fabf049d4b226a31478de0080113dce7d4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5678bcb1677a60e71aee1d87bbfd1bd924be6edff28c7e1a4cd34df1670cd2dc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 38175294, - "script": "76a914d4166d5513f4153b965b06734598471212967b0688ac", - "coinbase": false, - "hash": "5678bcb1677a60e71aee1d87bbfd1bd924be6edff28c7e1a4cd34df1670cd2dc", - "index": 0 - }, - "script": "4730440220412dcbcdbba90f8ef94f696b84b16dfdf3de963d21d2391dccf22e4a38d878df0220188604f4b5068ab8cbf1716433d527f1627adf87f325293f81093b296e5b889a01410447cb35ac4589c827dca5bc316020da954dc119780096d19c23a66e217a14ed6d42f694bdefb7f57ce57aa862d0b7dcb53ae5ed78adf03d6454fc007b790c69d3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9e1ed5e256ba736cf0aa628104c0239ac73431aff9d751a61e71e927f241a457", - "index": 0 - }, - "coin": { - "version": 1, - "height": 296322, - "value": 1055776, - "script": "76a914c187b955b5e7270ec431f237bf264e4ba761eb4688ac", - "coinbase": false, - "hash": "9e1ed5e256ba736cf0aa628104c0239ac73431aff9d751a61e71e927f241a457", - "index": 0 - }, - "script": "4930460221009e8b6d171ce8f8b460580c973bd9643fbc10b4e9e0748ca349041dcb3d92c621022100c95557caf8b8a6d8aac6cc84f25fb1fa9a5ec65efed5c0472dd856d72edd1ca80121026946de541770b4ee2764b189f5f7093fa36f3e0a4376b9e4276131809cafa7d9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000001, - "script": "76a91467322d434d1f57b24c9e6453176321dc0b3731a988ac" - }, - { - "value": 139368120, - "script": "76a9143afc1c87063e18b0122e3549e0db61521df0198188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d9a013e0f7948aac38eccfc2d0b021fbe7754141b8ea0539afba8b0568afdc10", - "witnessHash": "d9a013e0f7948aac38eccfc2d0b021fbe7754141b8ea0539afba8b0568afdc10", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 427, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "c57b74a60e8239988f438b80ab17d4f23e2ead4aa91a9b7426e5f4f93c9a4368", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299958, - "value": 2800, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "c57b74a60e8239988f438b80ab17d4f23e2ead4aa91a9b7426e5f4f93c9a4368", - "index": 1 - }, - "script": "483045022038b093f2396e4f3a6890db9d88e64feb24cdeb26696b655252872537c3a7a882022100a9f95076ef53b77ea2bb14084e54c136686abdeaa4ad515f36680976f18945040141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8fb61ecad53d89e2d02ebeb516f4f7b18f4ab4921072021614aa72875f0ed63c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299959, - "value": 264700, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "8fb61ecad53d89e2d02ebeb516f4f7b18f4ab4921072021614aa72875f0ed63c", - "index": 1 - }, - "script": "493046022100b43347a122ac34f5c8d27e8b4974a888a8516e60d43a685f75f6c97fb2514a56022100a90ed3234c94f061931abdbd1296685ed40b49aaa4813b4f9a74dd9d798402710141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9fd1cff1410bd501c05e94c5f636a090d73e42aa9dc2561153526e1a466e48c6", - "index": 25 - }, - "coin": { - "version": 1, - "height": 299959, - "value": 13241400, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "9fd1cff1410bd501c05e94c5f636a090d73e42aa9dc2561153526e1a466e48c6", - "index": 25 - }, - "script": "47304402207eb1ff2ecba283ededf568007d247738f73dcd15c2d4742ff477916fc2f84e83022066b504ded9d971730b0966dafeb8397a349e23b3f1d77750e948803a799d7fee0141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ff4c34cd2f08e5d2f805331e688ab83b7665ef0c83d9b1da66af960dbf3527a0", - "index": 24 - }, - "coin": { - "version": 1, - "height": 299966, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "ff4c34cd2f08e5d2f805331e688ab83b7665ef0c83d9b1da66af960dbf3527a0", - "index": 24 - }, - "script": "473044022009d8e3961ba9cf1869ed7ee2fadc79bc784b05cf306a62a82eea2a944e6a2001022011ede2632723647fd88814f516bc28c52072bde75fdce355d8390fbf5d54745b0141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4194042b8ae06e7ca26d549d15f8943699985129626ef8ed1860292102b0d948", - "index": 25 - }, - "coin": { - "version": 1, - "height": 299971, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "4194042b8ae06e7ca26d549d15f8943699985129626ef8ed1860292102b0d948", - "index": 25 - }, - "script": "483045022100eb2440a49cf2d484b6c5891d68798e1dd42e0ef8de0a1f51fa8c17bfa071b9b00220359c7aa1e14f3088f0adbad85edc785db85f48d3ed8ce01f4783bad71353f8250141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d7f79246c57c176a0eac2fbbfe3f3b9c81152dc34c652538dd68f9be7231e735", - "index": 25 - }, - "coin": { - "version": 1, - "height": 299977, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "d7f79246c57c176a0eac2fbbfe3f3b9c81152dc34c652538dd68f9be7231e735", - "index": 25 - }, - "script": "493046022100b658ab4e8dd278d741357f1f34ed82ab9a253c56006e5e5d5b93285d5c0e2c80022100c9d0ab70f6ad8f98a88f0930f9ef1803eaac17e07942f923000ae989b363cebb0141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "36e1e332c111ed2056cb7bdbcd91d44754c848a9cf46d50cba6e7ddb22438c5b", - "index": 24 - }, - "coin": { - "version": 1, - "height": 299988, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "36e1e332c111ed2056cb7bdbcd91d44754c848a9cf46d50cba6e7ddb22438c5b", - "index": 24 - }, - "script": "4830450221009acde065a9583531985bc090cfb341ddfb47bca33a70588fae53e173635567a8022040815869013cb48ee7ad07ff5e3143b7b2cbe909428876b97861ed1598736b6e0141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "450294edd1db3db0d6552f7d47bb9448eb999d1b843aa7d5b18d14dc1dda64ba", - "index": 24 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "450294edd1db3db0d6552f7d47bb9448eb999d1b843aa7d5b18d14dc1dda64ba", - "index": 24 - }, - "script": "493046022100c044d78bb09cc87b6dc1606f7ac7ceb4ea0413688d7e5d9d983be2525f65ed84022100ed129388997b9b61c048ee9557d00b7497aab895cd88cb5f06b3124a212d0dee0141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "127ed5c2bc6a7c28deaea8e533847b429d348fb39c0c1cdb3d8deb0b2fffb931", - "index": 24 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "127ed5c2bc6a7c28deaea8e533847b429d348fb39c0c1cdb3d8deb0b2fffb931", - "index": 24 - }, - "script": "493046022100ad669ec6367b5ef1bf9230a28310e823ef38bff8a055c2ed2b93a980ffd6caf0022100cba180054ceda0917c26da83ce87b9e3dd4effaafccb209c550d4e0aaa1a45eb0141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "21fb74d08fcd94ae2778ef01c6f57f5da01040fc49aa8f07620171ee2eaf01d6", - "index": 25 - }, - "coin": { - "version": 1, - "height": 300005, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "21fb74d08fcd94ae2778ef01c6f57f5da01040fc49aa8f07620171ee2eaf01d6", - "index": 25 - }, - "script": "483045022100cadc595dcb04580ddb447221b290cea5ff0ac80a1c1c4a3b2c22fa613f0bf4f702205773b16a58a5421f650e0c727d8aca15992df817b5e24ee3be9ef51305e311750141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ee2858fa984c228ed39b0458967fadd282667164270a1b3686017bf5394f0cf", - "index": 25 - }, - "coin": { - "version": 1, - "height": 300020, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "4ee2858fa984c228ed39b0458967fadd282667164270a1b3686017bf5394f0cf", - "index": 25 - }, - "script": "4830450220703984751b48d96dacadee5f6b362c5713f900d2cb91c031248b7d6f58b99ebd022100869dfe3cfaaadcdf9b2600ebe71884ec68f30585fe408b04d7df93042ddf07310141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b2ebb384228d5883392122a40054faeccd13271e8c8a696139612e0a561039a9", - "index": 24 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 13506100, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac", - "coinbase": false, - "hash": "b2ebb384228d5883392122a40054faeccd13271e8c8a696139612e0a561039a9", - "index": 24 - }, - "script": "483045022100d7f77bef455df0627de870ff6af3467ab5379fc4b239e67f5c14437c94866af802202b6d61c85d2205713a7e7d659ba505e74862c6e239375b54c0a5a8dd3df99d410141044d6f22fac6a43478855cded9db236461f10e8ce49714d5780b0341956eb440460720b642d81f5f9e9463f3f40ab69e9d7af3b48844d369858da759d8164e8fea", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 135000000, - "script": "76a914af0d87c74fa4eb8631a5f665d70324f4a87e918988ac" - }, - { - "value": 33800, - "script": "76a914d8797cd1fbef23e99e769f241d6ca7384d71e42b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "043d598972a6f2e553c8d7fd728640eef19f9fa78c3f3878cb44993f5f07ed06", - "witnessHash": "043d598972a6f2e553c8d7fd728640eef19f9fa78c3f3878cb44993f5f07ed06", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 428, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bf450acd7711860b911cdfe194acc7c22bd45b3d95459ad4a5e3b824627dd4c4", - "index": 5 - }, - "coin": { - "version": 1, - "height": 289837, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "bf450acd7711860b911cdfe194acc7c22bd45b3d95459ad4a5e3b824627dd4c4", - "index": 5 - }, - "script": "493046022100dacf74c696685af16090d489542889adf4590017cc9ed54698bd548dcc4f74db022100f11c3fb1e16224382890d73e6ab9cf84f12fca0fd110282ce567e5d2e6b47956014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c7ef413c22abedb6e123854d18d9c33d10928284735e69243a4026b2ef8d39e9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 289839, - "value": 2110000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "c7ef413c22abedb6e123854d18d9c33d10928284735e69243a4026b2ef8d39e9", - "index": 1 - }, - "script": "48304502207552fc5d946143e4e0959aaa0716e511a0ca3e6cba8f5ff274f4f77f0365b808022100991e53f50d9f857d7920ffb48248aaa6889a088d6eed3ddf55190556a4cc1e9f014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7e9b1423790d3d5631a69ec3ef1857908035a3007904c97bc74f16118358fd23", - "index": 4 - }, - "coin": { - "version": 1, - "height": 289897, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "7e9b1423790d3d5631a69ec3ef1857908035a3007904c97bc74f16118358fd23", - "index": 4 - }, - "script": "483045022061a99c2b08bc42a7351f7c909126372bae53eba2f12350131b6b55d9639d6040022100ec34f6a314db09df1e40d4298e13163846cd5b2fecc3822887919fc946d90747014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "98e3f1cbe7a10ffd7d3c2e58407bf520e34573347a366f8bc58139da39fc34ce", - "index": 2 - }, - "coin": { - "version": 1, - "height": 289965, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "98e3f1cbe7a10ffd7d3c2e58407bf520e34573347a366f8bc58139da39fc34ce", - "index": 2 - }, - "script": "483045022100c54425ccbf0118a25c1e5006911b057d38cb5c1f2ee2a717e9fe671aa656c5f1022002a250b3dd20b77da06bba924f2ef8e2728f1dfdc737572b0d74d48fec3ad614014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "425b8fbde30ccdeab9deff201c2fe450ab2093be0328b7e2581bcd189bea6df0", - "index": 2 - }, - "coin": { - "version": 1, - "height": 290031, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "425b8fbde30ccdeab9deff201c2fe450ab2093be0328b7e2581bcd189bea6df0", - "index": 2 - }, - "script": "48304502201d55243afca9bab88aa1ce2287c22beb1c50647bf6b66d05cd920bb0605a9d69022100a7929881b1c7a31d2905ab31e29548593168879aaf0edbecdd2a9af00178f59d014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "41cc6fc6cc26a9de6a77d7de373837d93d9356576b4639dff5a03c2e77a3379b", - "index": 52 - }, - "coin": { - "version": 1, - "height": 290095, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "41cc6fc6cc26a9de6a77d7de373837d93d9356576b4639dff5a03c2e77a3379b", - "index": 52 - }, - "script": "48304502203be09be29846f91ba8dd9b20a280c7bbfbe3da9b1b90c041a8b19e9617546f85022100f124284d1bb7872b014d728307176b226625a1ca43ddf2e2789449ab90a9c126014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dd1db4c90b6ebf1c519b525f14ca86ad55f6b40465bf81da4d59ce08037dd754", - "index": 1 - }, - "coin": { - "version": 1, - "height": 290161, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "dd1db4c90b6ebf1c519b525f14ca86ad55f6b40465bf81da4d59ce08037dd754", - "index": 1 - }, - "script": "48304502202c06587308815f4a5abb6b4301a72d1db42121993c1c59f0ce79bc48e5ab24e5022100e0212bc59f44de4273cf9202124081f49d84ecd0def6fdbde377f7217a53dd32014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fb223984f7ffb4652e858c058e299fede4dad46965ee39537e1a020b0960bb74", - "index": 3 - }, - "coin": { - "version": 1, - "height": 290230, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "fb223984f7ffb4652e858c058e299fede4dad46965ee39537e1a020b0960bb74", - "index": 3 - }, - "script": "4830450221008463a05a973c31257ccd44987177db25e7bb75a998d1c6a140e1d525cab583ba022075c24e4445948e17d9bb173cb95037228a914f807ccc281697992be27fad79b4014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "aa27428b0f0b70f24c1593e9f830ee8b918d1ab3317ff47c995162f625a5b0fc", - "index": 7 - }, - "coin": { - "version": 1, - "height": 290305, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "aa27428b0f0b70f24c1593e9f830ee8b918d1ab3317ff47c995162f625a5b0fc", - "index": 7 - }, - "script": "4830450220463b7fa883b1d12b7eb89ba2321cf203765df7041c6f617cc5f01aae425b1ef4022100db74f1e52aead56614f5838f1181b140247a18ab2be6ac7ff92f88fbb1b3b118014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cda5976b816be1e8353c927008f19586e004c6edcf2c8c8a69804955e946c320", - "index": 4 - }, - "coin": { - "version": 1, - "height": 290381, - "value": 2000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "cda5976b816be1e8353c927008f19586e004c6edcf2c8c8a69804955e946c320", - "index": 4 - }, - "script": "47304402200460576935aaf8eec98b8cbb57846174a95896c120596287486e78b02239863a0220571c99ec4dce29dfba91b131b4dccb8bbede04f37fa016b8c234cdb78f7ff423014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5936d46c77304fb0604f39a9f5beb8982d0c3c8121ea0a0849127c009ab5b29a", - "index": 8 - }, - "coin": { - "version": 1, - "height": 290407, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "5936d46c77304fb0604f39a9f5beb8982d0c3c8121ea0a0849127c009ab5b29a", - "index": 8 - }, - "script": "483045022076cd1dedbbd6bd31ca4d98da2ee4ba08dbbc4a209ddb6ea5e480329133e0bd5e022100c0622897bc613e406c8e06e41683ebe529e695170acd86a6d605620994d34fb0014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9b7a106602c2bd81fa637eb691db1740e452a17f95d420085ce5642fa85e7ca2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 290452, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "9b7a106602c2bd81fa637eb691db1740e452a17f95d420085ce5642fa85e7ca2", - "index": 1 - }, - "script": "473044022023f93c516c665b398f1341d2115b16cd2ca31ca91ad0f6f815a733125694e92702203f8fe24ebca023c62bd955f946a53c7e40baf2d4bce6945a5bd5ddbb4ad96eb7014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1019a323f28a5346d494dbcf8b461ec6afb7836ccc123095743f0bfb29539d2d", - "index": 6 - }, - "coin": { - "version": 1, - "height": 290481, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "1019a323f28a5346d494dbcf8b461ec6afb7836ccc123095743f0bfb29539d2d", - "index": 6 - }, - "script": "483045022061bba8c9758b4743a3f5c2f957d6ceaf3216769694cec2568c88905d71376ab8022100fb5d262e9a3090224b0908b6f617ad25bafd87d92399fc01d7ef22a07a76d851014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "797da555834f5b5df57629a93571bb539331367ca3217b5a437c927d625169df", - "index": 11 - }, - "coin": { - "version": 1, - "height": 290510, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "797da555834f5b5df57629a93571bb539331367ca3217b5a437c927d625169df", - "index": 11 - }, - "script": "47304402207d524858abdda27e2625b90318f4c1b310f358eb13c053ea8b242caa03a21ef702204f1bfa5ad23d603e1ea91d97e15b0fcbe23fcb0f6bb19f76e2c91a1d4ccd946e014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "91ff35d58640feeff4c7a3f5588e3bd96cfb05456af8b8f558bca8133ec48c8e", - "index": 2 - }, - "coin": { - "version": 1, - "height": 290535, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "91ff35d58640feeff4c7a3f5588e3bd96cfb05456af8b8f558bca8133ec48c8e", - "index": 2 - }, - "script": "493046022100df4b6a373bb187208d144216dbd540874425dc9286c53925731161e38b2132fd022100ad1d10337c28f3ff78a34b6695d48f2c9086b63598839bf0274737a02efa16d1014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4486cc069b63305310b0928a538a6066c5ca424f90701729cb1bade60add4963", - "index": 6 - }, - "coin": { - "version": 1, - "height": 290569, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "4486cc069b63305310b0928a538a6066c5ca424f90701729cb1bade60add4963", - "index": 6 - }, - "script": "483045022066e817deee3fd79785cdee4ed3adb2b77d28c0178c02bffb642410ed2c140e860221009f53767df707162b6a8698e4bc4d13373c139deff5b9c6732cf533a937899afd014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e27ad336ab02d37932ac1ccd04b9a7d0c45f2a38163104f768004be84ffb5ff5", - "index": 20 - }, - "coin": { - "version": 1, - "height": 290607, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "e27ad336ab02d37932ac1ccd04b9a7d0c45f2a38163104f768004be84ffb5ff5", - "index": 20 - }, - "script": "48304502204d884015a552a9c4c95d4d6f06f21c2e63b9e5cec4e6e55c474322164a5b997d022100b3714f717684eafc8bc2fdb00e1a5d48eeab165fabe95da674124c1848bc25af014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7735ec5db2a4e8c8ccc553b0b83eb504f137ce794a26581c8861326bfc503e50", - "index": 2 - }, - "coin": { - "version": 1, - "height": 290645, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "7735ec5db2a4e8c8ccc553b0b83eb504f137ce794a26581c8861326bfc503e50", - "index": 2 - }, - "script": "47304402206b57d52b1a6ecf5dae7e6ba0ecf19b61321ac2e784aa7f65bfc407a59c61681d02207ebd653b70393a49bfd4e39128314c734bd6682fe95599c0829fe82b0508929a014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "912ff3980dd0054e42e2ac11cb3a9fd8c5a62ce3b8c966d1b7af0f6eef1430cb", - "index": 12 - }, - "coin": { - "version": 1, - "height": 290692, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "912ff3980dd0054e42e2ac11cb3a9fd8c5a62ce3b8c966d1b7af0f6eef1430cb", - "index": 12 - }, - "script": "483045022100d14dfee8275abaff784096db13ea9de86c0fa547beee8b30c493b0559d38e0f802207207e06b406a72d486fb10b724f80fba0b803c60ebbb8fc5ea069e46d5383ca8014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fd3c467c8989b282954f048c0839b8fc99b3b0fdee98727c29a2d9a12aee1427", - "index": 2 - }, - "coin": { - "version": 1, - "height": 290721, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "fd3c467c8989b282954f048c0839b8fc99b3b0fdee98727c29a2d9a12aee1427", - "index": 2 - }, - "script": "48304502201f1ac10925bd5699577b51decfd91e1106cc8b021bd840e666d531afb7f32246022100fa0bbc6ccee7919bd2fc7fd2fda6fc693d27c3b4899ba0ff5516deed8ba70c49014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2364c9012898f02afdd2bf827e8300d01f484c500f053dd95b2849640ea6e72f", - "index": 26 - }, - "coin": { - "version": 1, - "height": 290763, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "2364c9012898f02afdd2bf827e8300d01f484c500f053dd95b2849640ea6e72f", - "index": 26 - }, - "script": "493046022100bdd2029d8ee2286544dc0aa9e2ca32adcca9fb95dfb49a13aea8e84dde4e7e75022100e71b18546b0ab047bf53245f5b86a7eb1ba95dc47c48059287f2efc3871150d3014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d3481757638137d821dceb184eff137065dcab2490a1077c32d3888b7b8d42db", - "index": 21 - }, - "coin": { - "version": 1, - "height": 290839, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "d3481757638137d821dceb184eff137065dcab2490a1077c32d3888b7b8d42db", - "index": 21 - }, - "script": "493046022100fb872ef623482a906e7de02217d7881e435b661c8b2d7b84b75511e59c0215e2022100c58d2c8dec0e051bb3751ad5897c7d91ef1f6bd818f009eddda000c09af30b69014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a199ba7c7f0377b118dbac451642e4a5e89dfb74c1267cb3edd52b3a9c82d297", - "index": 20 - }, - "coin": { - "version": 1, - "height": 290883, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "a199ba7c7f0377b118dbac451642e4a5e89dfb74c1267cb3edd52b3a9c82d297", - "index": 20 - }, - "script": "48304502207979d082603be5d5d89b442b39c087937bdb4c2457c4be549a8b2be4e0f6d886022100f918741d2f66e21d602414a2f1176a4fc2bbc99676bbb121d736d74eb5f9b658014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c0b333af1a8a94cec27fb95bee8e8d730f04d86626c0bfc6085c801ee8baa675", - "index": 36 - }, - "coin": { - "version": 1, - "height": 290937, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "c0b333af1a8a94cec27fb95bee8e8d730f04d86626c0bfc6085c801ee8baa675", - "index": 36 - }, - "script": "483045022100d26e02c77e5297c8c6a9bb08e91898c0fdea60e3000d466b2afae73c5e456f3d0220768e50d52e4b92f84159e597bc1f9f2d601ceabae7643af686f7ccdc46b84894014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "28879262b704c3930b0b811771d8adf72391cb637561f28e117b0f833ed619ca", - "index": 19 - }, - "coin": { - "version": 1, - "height": 290955, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "28879262b704c3930b0b811771d8adf72391cb637561f28e117b0f833ed619ca", - "index": 19 - }, - "script": "4730440220310235d049e6bba16a2bed5536ad9925e214c1a894aeaefd7d2ed700cea90dcb02206bf6f9305e9d93bf307feada531a790242ad195f968ddf4d498c84e53bc1d8de014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "05a086fe9b5e20ed7cc3ec10d7c51ad64b3ea609e647433a414e400be991c5a2", - "index": 41 - }, - "coin": { - "version": 1, - "height": 290969, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "05a086fe9b5e20ed7cc3ec10d7c51ad64b3ea609e647433a414e400be991c5a2", - "index": 41 - }, - "script": "47304402203613888eaed70500266a6a1f2ff4461f1bc74450b160d84d755f901eb4012d9b0220126b65b87af60966cc6a9426b965823d0a784334771b92ee511262eff656351d014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bc9cc9b271dff7d976086a37758c397c2cf8f71ec0b8b8b8a406d54e5451bc9b", - "index": 30 - }, - "coin": { - "version": 1, - "height": 291010, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "bc9cc9b271dff7d976086a37758c397c2cf8f71ec0b8b8b8a406d54e5451bc9b", - "index": 30 - }, - "script": "483045022100df19ff7fdbf265227e0449889c7bb8add858cd1d382a7c21f81ef453a5eeadf802200a48a16757b529c10759529046ff08b90ef64e37320ec9dbab5dc4d4285dc3a8014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "58d5ba7917a1510313f1d4a7f094a43c2ac2ae1c74269498d70f3d5120b10205", - "index": 41 - }, - "coin": { - "version": 1, - "height": 291034, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "58d5ba7917a1510313f1d4a7f094a43c2ac2ae1c74269498d70f3d5120b10205", - "index": 41 - }, - "script": "4930460221009625425ef9e9dd052dcf796d7ba76338d60ab57fb72bd6c473bf5c8c713871c8022100db8322b3e16f6e8907c0d9861d7924cb85f6f2536fe1dde08c0f080364ce6875014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "082de4440e569834c3445de7a9d377e598a2c27a5a0bb2a65151ca825f60da19", - "index": 61 - }, - "coin": { - "version": 1, - "height": 291063, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "082de4440e569834c3445de7a9d377e598a2c27a5a0bb2a65151ca825f60da19", - "index": 61 - }, - "script": "493046022100a76e2cef30bd1a7487e9c371c4cca8d254121f14ef86ad68298b21d29fde9157022100fce853fe4b2132f072b74c7cdeca4c7bac8e61a501cbff888830793acad55101014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "222976210ec32ca7b96e547f7b359ffb0bf1ab85dfcf822d9b2ab8978dcc62e2", - "index": 18 - }, - "coin": { - "version": 1, - "height": 291094, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "222976210ec32ca7b96e547f7b359ffb0bf1ab85dfcf822d9b2ab8978dcc62e2", - "index": 18 - }, - "script": "4830450221009bde11ea5eee70cd82dbed05ed0462140cc9a3016a896b94c5903d0d0e2ac08902207350c8b9d4f2193412b05174bd0df46e2bb102b10db03dede2d5b7dbaf9e8da1014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "34f8b917b2b47dddb289ecbfb6ccf14a233779bded99deb72cda2c180dd031e6", - "index": 24 - }, - "coin": { - "version": 1, - "height": 291136, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "34f8b917b2b47dddb289ecbfb6ccf14a233779bded99deb72cda2c180dd031e6", - "index": 24 - }, - "script": "48304502205e4f6ed9e634e4af19548b9b08752e1d081063d252a51518ea08499a34cbc4fb022100b41707ce99cf2ae037001f47faf44f05ee3954924a53384b8d332e23ffbdb919014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "839b8a86e07651c756259fdb044ff8d4620c13cf17a0e67447ba7502ba520bb6", - "index": 19 - }, - "coin": { - "version": 1, - "height": 291189, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "839b8a86e07651c756259fdb044ff8d4620c13cf17a0e67447ba7502ba520bb6", - "index": 19 - }, - "script": "48304502200d3335ec0398293a6750b7cfdbe8ffe819dccd910b905e5b33dbc212aea48b2f022100cff493800a69477684296d2399fdca1c82e72ea700c4e9a6de1fdc878928609d014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0676581a4b7bb6dd903cbf83d3e85b4b3542925655920b05d5ec86b2b13ac4c7", - "index": 42 - }, - "coin": { - "version": 1, - "height": 291253, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "0676581a4b7bb6dd903cbf83d3e85b4b3542925655920b05d5ec86b2b13ac4c7", - "index": 42 - }, - "script": "4830450220472162139401ed67c35e81c5244da998275f60f292f0bf975ef7b6d31bea8929022100fb552627ce7b46028b96589a0ab7176b6286a70cb4fb9e483f97048dc4984ff7014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "019de0dabc2a227e190458c83cec550fdddb00e16cd477dde9a617f2f2b93117", - "index": 21 - }, - "coin": { - "version": 1, - "height": 291301, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "019de0dabc2a227e190458c83cec550fdddb00e16cd477dde9a617f2f2b93117", - "index": 21 - }, - "script": "47304402201be86364523a589c6468b8d8df2754c89690ce1fec3f2bc66ebd081b2063aa5602200e24ddfb6cbc37f40a500c7d47c80c05a47f778e60738e7edcd310d73c2dcd0f014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c721c10e048a3af6249e595ad5ee7d872d7eafe50f66f8d112a5cc20bce004b0", - "index": 34 - }, - "coin": { - "version": 1, - "height": 291338, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "c721c10e048a3af6249e595ad5ee7d872d7eafe50f66f8d112a5cc20bce004b0", - "index": 34 - }, - "script": "483045022052b8a4a1d9d879ec29099d0fd96484725dbe85eb8d67788480a33dd60e765f8e022100d3c09519c357447df6a051b9e9e77081acd99455004da878db0d33a192e40390014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "71d7a4b5dc90fbdfb3e27071576f24ecd959860b586129634dd793771da06e01", - "index": 24 - }, - "coin": { - "version": 1, - "height": 291386, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "71d7a4b5dc90fbdfb3e27071576f24ecd959860b586129634dd793771da06e01", - "index": 24 - }, - "script": "493046022100f4b1814ac293cced26dd42111b4ea4deaed424a6a1540ab59fa3327e9a3f4172022100f271d081ca29b82cd08c28773cf301d876f97a1d956e920ed2e9800f83a1809f014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3ee138b338c3b8c8e45ff5c73993186b1f435e4048a01f414b1f30dd4c80ddfd", - "index": 35 - }, - "coin": { - "version": 1, - "height": 291417, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "3ee138b338c3b8c8e45ff5c73993186b1f435e4048a01f414b1f30dd4c80ddfd", - "index": 35 - }, - "script": "4830450220124d222819a74d806065c6a18f663911900ddd1955bbf15136da439f88756083022100fa9dc2a8e41465fde0b92aacefa7182981f7c11494f0b26457eb198bdc0c7b78014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2cb36395fd5bc72813af8a4c1c728f82ea09f0bfe2734cd425afefff362d5764", - "index": 39 - }, - "coin": { - "version": 1, - "height": 291441, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "2cb36395fd5bc72813af8a4c1c728f82ea09f0bfe2734cd425afefff362d5764", - "index": 39 - }, - "script": "483045022100dd8ef5fd40c2f6838300152590e83b7a1dc9a8734ce92025c1e786b477d9260302206662e78cc23a89e816bb4fb0051e5d8addf8e583336918f6206fccc6332f27f2014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0878e340c116c76b60f505cfbace9e4260d7a3b1c5b18028c643e4d8e862f117", - "index": 47 - }, - "coin": { - "version": 1, - "height": 291504, - "value": 1000000, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac", - "coinbase": false, - "hash": "0878e340c116c76b60f505cfbace9e4260d7a3b1c5b18028c643e4d8e862f117", - "index": 47 - }, - "script": "47304402206d66484461742b4d7301571c38757f1101da41542add98cb54f890b3f295152e022004b49b95b27847d974cc9ca59ea56891807767852bce2c25b7d5841f3e27cb77014104ef38079f2e78e45ba3ecb926ee3938a52d63224a0820e4bf863f13688c32c1b6d46489d4ebc180e48e8824137b7b14d7373935d30da0db1a7af699c7eb58c42f", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 47945300, - "script": "76a91481de0db3ec32b342d11099511bed22f5e6fd3bb188ac" - }, - { - "value": 1074700, - "script": "76a91479fa157cfb2f326fe01575ea7381b35abff7ae9d88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0c4195d68cafdda11b265e9d8bdd026a55088cf1245c73cf543c341f94b2049a", - "witnessHash": "0c4195d68cafdda11b265e9d8bdd026a55088cf1245c73cf543c341f94b2049a", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 429, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e7313a963e848ed4c579ff90a58d5d34cc42d0b060d076c80bb667b71ee5335e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299364, - "value": 58327933, - "script": "76a914ee5c2b4d40e430f799c7bee49084b858ca5f40bc88ac", - "coinbase": false, - "hash": "e7313a963e848ed4c579ff90a58d5d34cc42d0b060d076c80bb667b71ee5335e", - "index": 0 - }, - "script": "48304502203521dd086e832680c04eb57242e76920f1940f9c14b98731cb63f56419b72682022100d0e5bd331f735ceeea8edb647b2d4a3265f7515009e3b3e82319e1b5ff340a34014104ad5d8e98447acf93afaba5efd1689a333fbf01c4c0bbe665fb2b37014239d172693fbabfbf98f8b084030567489b3664bc055141ea551f5356ace28d456062b9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d3d84e0b71eb7807bd4683319726e09d43b11f75df47e47082d34f3074ceb43b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299538, - "value": 13362054, - "script": "76a914ee5c2b4d40e430f799c7bee49084b858ca5f40bc88ac", - "coinbase": false, - "hash": "d3d84e0b71eb7807bd4683319726e09d43b11f75df47e47082d34f3074ceb43b", - "index": 0 - }, - "script": "48304502204337df18cb0f640cdd7a8e8c7ad75656ed914ce112e72e9df7ec94ca9369374b022100935ae3aedefcde55a46400482aad2d2ebb1d3a9ea252eba80f62f022fbcf8309014104ad5d8e98447acf93afaba5efd1689a333fbf01c4c0bbe665fb2b37014239d172693fbabfbf98f8b084030567489b3664bc055141ea551f5356ace28d456062b9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4315bd763df04e2197d6d1136d41504d5deac4c6514353a9e78a1ca5080174ed", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299565, - "value": 14293882, - "script": "76a914ee5c2b4d40e430f799c7bee49084b858ca5f40bc88ac", - "coinbase": false, - "hash": "4315bd763df04e2197d6d1136d41504d5deac4c6514353a9e78a1ca5080174ed", - "index": 0 - }, - "script": "483045022100dba283ba026317aa9eae5ab2d7ba667861517e1af24adb096d890d0116c09a9f022065518797bdcf1ac0494463cf664ffd585954e902f88ecabe38429ce148cd5cd9014104ad5d8e98447acf93afaba5efd1689a333fbf01c4c0bbe665fb2b37014239d172693fbabfbf98f8b084030567489b3664bc055141ea551f5356ace28d456062b9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "11015097331b0caf7c61197f1be858f9db844026ca71368fbf579e997c0c4087", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299571, - "value": 79164028, - "script": "76a914ee5c2b4d40e430f799c7bee49084b858ca5f40bc88ac", - "coinbase": false, - "hash": "11015097331b0caf7c61197f1be858f9db844026ca71368fbf579e997c0c4087", - "index": 0 - }, - "script": "48304502200e84b7a98e568bc57fd568a5f1810a86dbab117ebc8a60ae86adb18bec0e4e0b0221009a64af14b1677a1643cc7fdf24be594f6f4526a4fe95c1938557439bdf139f6d014104ad5d8e98447acf93afaba5efd1689a333fbf01c4c0bbe665fb2b37014239d172693fbabfbf98f8b084030567489b3664bc055141ea551f5356ace28d456062b9", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 100000000, - "script": "76a914ae1cedc90b4a1eb610da3169ad6591fb4e36dca588ac" - }, - { - "value": 65137897, - "script": "76a914ee5c2b4d40e430f799c7bee49084b858ca5f40bc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "882913bdc8781d6b181825cc3d986315400201d02375c4015df948e20da4d96f", - "witnessHash": "882913bdc8781d6b181825cc3d986315400201d02375c4015df948e20da4d96f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 430, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "341aa4dfad4549d0285538c7faf115e939c7d62fa4162a4b28033e78b5d95860", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297751, - "value": 3334419, - "script": "76a914f5a41d860ea62a8d279a25d538f094d1202f245788ac", - "coinbase": false, - "hash": "341aa4dfad4549d0285538c7faf115e939c7d62fa4162a4b28033e78b5d95860", - "index": 1 - }, - "script": "483045022100a3cca1512d2d79e6b44e9662a13a55e04b0d85c0b17d0aec5d09bb8659beed4802204a6e5e0328d11d1b8a1020e81fce72d763a611f73879000b36a370226f389b40014104b43c0e7afa2084a29d9ac02bd7bb75478fa7902443a6d2e5f40e1ba43b5e306c169ed1a20832a9ff8940f20e37ac99952e7e6b0bed44a80d4a89b6f16b2ec949", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "450b6b36797fba72ab67e434efac309f62a24b20386787df76a34c4acb564b7d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298445, - "value": 1517203, - "script": "76a914f5a41d860ea62a8d279a25d538f094d1202f245788ac", - "coinbase": false, - "hash": "450b6b36797fba72ab67e434efac309f62a24b20386787df76a34c4acb564b7d", - "index": 1 - }, - "script": "483045022062aefc01cbb8a9d607c6e2915c44f1e3a0af7b053ba686e9c71bcad4a8d271dc022100937c830f6b82c308cea49fb75a8e619a51538a776751d1b5a340bc627c24da7f014104b43c0e7afa2084a29d9ac02bd7bb75478fa7902443a6d2e5f40e1ba43b5e306c169ed1a20832a9ff8940f20e37ac99952e7e6b0bed44a80d4a89b6f16b2ec949", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b7717281af221c5300c712968530a526c8af2cc80a255102763be8ce65644946", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298709, - "value": 5506024, - "script": "76a914f5a41d860ea62a8d279a25d538f094d1202f245788ac", - "coinbase": false, - "hash": "b7717281af221c5300c712968530a526c8af2cc80a255102763be8ce65644946", - "index": 0 - }, - "script": "483045022100cd4eaa45b2d519b8cb5cea50e7706a04418a774bf8ae59a374deac5b58629cb902204e953e2209a62718086f77e11cac3ef2881d8c48c976ba67d417b11676f1d463014104b43c0e7afa2084a29d9ac02bd7bb75478fa7902443a6d2e5f40e1ba43b5e306c169ed1a20832a9ff8940f20e37ac99952e7e6b0bed44a80d4a89b6f16b2ec949", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d701d9e17bc58c8eda1abfef062b6042646abf9f7deb8a818505383215c41a04", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299022, - "value": 9505966, - "script": "76a914f5a41d860ea62a8d279a25d538f094d1202f245788ac", - "coinbase": false, - "hash": "d701d9e17bc58c8eda1abfef062b6042646abf9f7deb8a818505383215c41a04", - "index": 0 - }, - "script": "483045022100ec2c1d71df68546d854825ef856aab3812ae678d8ca744ac902edcb02a6f0db3022013b787c68ac47bb71a88bec3ed51db7a80993f2a2d884f1c62081a6388db7aa5014104b43c0e7afa2084a29d9ac02bd7bb75478fa7902443a6d2e5f40e1ba43b5e306c169ed1a20832a9ff8940f20e37ac99952e7e6b0bed44a80d4a89b6f16b2ec949", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 14020000, - "script": "76a914256cd36d44d4188047ec91838a6d7dcda742d00888ac" - }, - { - "value": 5833612, - "script": "76a914f5a41d860ea62a8d279a25d538f094d1202f245788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "witnessHash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 431, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 48000, - "script": "76a914ee0e6d5d11038aaab9ac35809b4963aefd1ec51288ac", - "coinbase": false, - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 7 - }, - "script": "483045022013416fa9fc58a3c2df366839ece51fcaf7f0cbd29f2b4f2dd993caa7c3fda0b0022100e03896d17ca6fdf4ac46f8c3b849a79d8cc67e5dacbf09f897006be52fab653d012103faebb2f2632dce045e966799785845e652093a9825ad1654fc639085449e5ad6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1051110, - "script": "76a9149b876bee60b0a22127aa92766293c2c020693e8688ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 11 - }, - "script": "48304502200211dec14ab46336288e5bcce4920fcceba43d9da5bfb1128eea21f7abbb3a4d02210089435859d660dda2cdb5ce1f23f5babd7342a6064792fda93e9af67dd6d1e9bd01210200793dd6e17de5b153c79cfb0db9698e108dbacfbca5f04fb32e109c7e960aa2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 24 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1154953, - "script": "76a914c3e48ee1e2b01b5965f86915866f0f4cf3ba5bdd88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 24 - }, - "script": "483045022100b3bb8e86df47a2ef776e86c625e7a93717c13383a66edd17489f5e8f1c553f4d02203c6091dffea24aaa5d331b882d41bf844a2c5a3c7f908a9ca7a9703ee870de400121025f61a22d431a5dd1c1c1d2be16131857566dff2708784dc11b0db791836434bf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1061180, - "script": "76a91460963818d263eef7c39535ee486907725284e56b88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 9 - }, - "script": "493046022100bd241160e59979a1427123242edfac401d9f529fecccc25962ebaac893034cd2022100acdf00714bd327623162627116d24bc6d5a4eb691e63cffb5aa06f5ac2834e1f0141042012a1eff7027e5ec566a165f5c2961fe2a7eccdc363c54547b95b0d230959b12bd415ada9539ebb9521451b14ec4e73badaa23512a4c68f7944abea54b2d1d3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 4 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 9500000, - "script": "76a9147b4bc9e5dfa9f937d7fd61f2f7eb17c26673345b88ac", - "coinbase": false, - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 4 - }, - "script": "493046022100e3e3e54a3a120a776fba422984175982de9b72b0efdeeb536ac7d59c9cf44d93022100c93176ca94b2ec31c2a57d75237e91096c8faf0f931c71fa024779e069d0126c0121037525ec2fd520edf41cfb527a50bce59b051e37fb14b382c09cf09b478049184f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 29300, - "script": "76a914b296784c7aef7360ce1b3f710bac7e5f7bca9b8288ac", - "coinbase": false, - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 15 - }, - "script": "48304502207ceb47d5d45bd61596691f315da427f850f3fb2c3b7ca9fbb857833e19107ef1022100e4440c376c70b0a5acc34cf7d4e70e12df328b2a51635a7cb939b8d6be58440a012103a09c4fc4c94d013d2febfdfe3ade4bbfdde075fc674f40bb73ef781422fddfd1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 8560254, - "script": "76a914e10fa8db1c02c0973d4c2585bef6a8cdfd88235988ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 0 - }, - "script": "493046022100937a8d5d570bb0cef513642d4db1a014b4987a81eea21f16fe84c8356bd2230e022100ae231bb3118b2dd1b58586bddb9908721e52fcedbc085dc71c389fe4aa0c8e44014104af7419598cba95105d77987e95b58c80bf5114eac453404ded3687f4a27cd174cb3f4123ec58cf8c0653cbcd56df8bb2e77d5744636f92ee471fce43984a869e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 14400, - "script": "76a914d648c2447ce85c3be4ffbdc0860f97c9d73996b588ac", - "coinbase": false, - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 13 - }, - "script": "483045022026c18c5524bc14526c8e8720241d8604b8bfbcda53f53ddc120297caafa8732a02210093b3b143d164d4f8b1b919eadb94e7745bf20e98736186e6d14608f362b67e28014104e5894b00bcd6e4061b7f1cc9aca223f3cbf0ea2b698fb265ff81d531a64456547f8a5c5f1630a9fffcace1c55aac86bd697f0c2935c6c6036f647e48d8400d26", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 9572400, - "script": "76a9146758f159f35bfe097fd96e9e61ff2d2970e27c6588ac", - "coinbase": false, - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 17 - }, - "script": "48304502206f9a8902a23754508a0f6891d4d62b39b9b529d79115298730e6d8b5f667e047022100cf13e91329bbd82d4209e1df01b85622636418cb6c587498cdecd3ca05a1b2f8012103922bcc8c7d42bff473624f04f2dbcfec4eaecc492a7eb1c2b868d2677cd1388b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ccdef6ffe652f1a6e037242c2961cdcc189904c9ce61d9bd9b25582016f930a", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 286830, - "script": "76a914ab11498be0fc12ba8acef0cdccd9ea2cecc1273a88ac", - "coinbase": false, - "hash": "6ccdef6ffe652f1a6e037242c2961cdcc189904c9ce61d9bd9b25582016f930a", - "index": 12 - }, - "script": "49304602210089654919a2ec41d35ede85e6e74c6179403e9632c252453c0e3ab8691aacbd40022100bf5f81236fa630fe7a3ca3c77f16acf35a5e743ea7421d9f51d3589a5b9f04c2012103b6537d8b0858971574ef6714ea7ffd25310c37cc9dacd0cc63dc14a51c68a16c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1134504, - "script": "76a91455efe56cb551a42bee92a1a625e8b93c48db53ec88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 16 - }, - "script": "493046022100ced5238277f7f45f51d4c0879e3c1b99bae9f707b96a5fc7f3dd2d813da72916022100f1a5411196b8954d25aeb3c2aff8656af4288a28fab55f8e71648def74e282bf012103cb3d8bc7073157f7a69e2819495746c6570405f1157f841b5d52663fe074fa32", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8056d3a86a37e9dc7f0b18953137c1d562ddaa2d5aaf4b42434a8c4b2c1346b9", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 9550000, - "script": "76a914eecf53dec9d8c7f1afc89ac6a52ab1dc73fd215b88ac", - "coinbase": false, - "hash": "8056d3a86a37e9dc7f0b18953137c1d562ddaa2d5aaf4b42434a8c4b2c1346b9", - "index": 17 - }, - "script": "483045022004f07b1d684ca0d10d8f3863cf78bc835e42069a3e9b03d2dc931492b180021a022100b84a66c9afa211272c9f34c4af43a21d5b7eaf9155656376db05860163eddc13014104a39e08effe523afae413a3c522b0109683286e0dad04263cc909ea3132f24e8c9dc79e03ae4128b4bfba66b21c858a3065106364ab31115bf9488cc2d9820e7e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "09be2f4533dadca1810a9fc669660ab764b6534e8579c3055f01f589cad27fc8", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 9514242, - "script": "76a9144005db4e32e8e0ebe6bffa43c7fade2e2a6ef86888ac", - "coinbase": false, - "hash": "09be2f4533dadca1810a9fc669660ab764b6534e8579c3055f01f589cad27fc8", - "index": 13 - }, - "script": "483045022044bf3dbf8ee109bb5f7a07964ab30c7992785bdb501e8e228a76f7e05a1fc4e00221008bf183973623c86c8e59b27cf0fcb383d42e822b2ed6e507fa14062ff2d2ec7b014104cf11a3d1ce48697381f9e3350ed9445536c154434c214ba71f7884dd28eb46ba9cf93c090d66ca655719a84c7a1189f6027057079f6f1cee0c1061c11cd91405", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "51de59b21d498720af3dea2b4be148293a097ac722d5ac71449fccd74020d8c1", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 9570000, - "script": "76a91445e1692c1a967788443107f954f9863db3d314ab88ac", - "coinbase": false, - "hash": "51de59b21d498720af3dea2b4be148293a097ac722d5ac71449fccd74020d8c1", - "index": 8 - }, - "script": "483045022100a0ce935c5c12323389b345c632f629256b84555d525f9de1b6e1b9ac6c44d66a02200fb5b10938dba688f9d9eeb25059edc2cd45487ca6b316c48379f797bbc5510f014104948dab191448c499f08e0d1594cc3db208e8420e45619b83832daba9be6c01eee1cda7f1ce53a88ff912186d750a4d3295d0f4a6e1a8a74376db3453f1ebe54a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 9500000, - "script": "76a9149d36eec441f742a4f1d72b194c08c72a436084da88ac", - "coinbase": false, - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 2 - }, - "script": "4730440220726f55c66dbd738f7903697e4a1e49ca96770d2c09068678714d0fcd4f92fc9802202ead81528be4d583bbf1be95780cfaf04c40d089a57056e04fa9b5f802b44d0d0141048d8cc6fe4e5020f61b7f7843d649f3de86ba2f2f62abfe3f5557c637e8e0d50f0fad24e9b9f1dd1dd0a7f6168b5828908b2839029ffdfcc53205eb4f5037f1d9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 12 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 9500000, - "script": "76a914dae45f58490cd7f8cf1ac24831a2d5fc8a03572f88ac", - "coinbase": false, - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 12 - }, - "script": "48304502202cd0d0eecfa392c60d43c1b9478c9e380772fe18dc4ded49339b45d1754bb47f022100a0ebb0e96bbe628bd2e36f6ce2acd36bf1cd7624eb992f0b3a18bc12f1689e79012103ffdcad4947162e1f05ac7cd9850243f4cabcc3d1e47da6d3a79d37823d2d8804", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 29 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1081270, - "script": "76a914e2582a18222a746c1a01ff54da39b66370c7c7e488ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 29 - }, - "script": "4930460221009121b75159d788ceec1b45d61747417c0ff5c1d743618c6339fc23f01fee12ef022100a27a5bb0d7c01845c3c91d1ab648c7b15d068e007e11a6c48256da98a21094cf01410429d26c13ed6eb293203e6dcee47ecce26961b072040fcad602ae5b01ac8a270f0762475acc10150c4ec59a932362cc518203d5554af25ff439f805c6fc7ee3d3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4d301d92c7b7f47b1e2d8695fcd8c6751ad225166e71b4d96e7a0eef9bcca6b9", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6400, - "script": "76a914fba5c9f2914b8a1535d2e0ed357a82fea278e77388ac", - "coinbase": false, - "hash": "4d301d92c7b7f47b1e2d8695fcd8c6751ad225166e71b4d96e7a0eef9bcca6b9", - "index": 10 - }, - "script": "493046022100fd0abb43deb34a3219e9e9e23721e7fd183418857b4d7f341e0219820666b209022100ec90375daf50705d47d4bf99bd8e4160c4157bfec563f8c29e88bb04e474c7b4014104d3ac7b5fb4186208572d190fae26a1a08316d5ec70310ca15db6afd4f3ba137e174edba09a234da12f00a5373ea80fb17d0acd413831042c24af17fd2d532911", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1093937, - "script": "76a914fb75466d25a27c946c1c63a81321ab41a0fbebb588ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 0 - }, - "script": "4830450220746acf66a87d3f0387acc9dba10f46d37a16ea9e3f26961961cfb18654d03dae022100c4fcb832faa1c3523575a28772c31e0bdb2ab862dd78a4e124ac044fbf9bd22f012103b0133e2eb02562f64d5c00045bac5bfbe94a7ed97f3167817308eb230f836c4e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1039746, - "script": "76a9143800aa036fb904fa5f1266a8e92342b8c48d03af88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 15 - }, - "script": "47304402205a3bfbdbb6fb9b51c6f8caa8481350ac6d322f210fccd9c03478fbe153c0e81202204411cbc3dd3e6a13da1774c05f315a949aa781626f7632042f0c4c59a1aad1aa012103189bc1b81a543af314e0b6b3bb9fdc02f6ab60df35a10f6c50f7b5d89f705e85", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5196620, - "script": "76a914f2e2e2acbad94f0fc0c5c7eafe21ebe615fa1c2d88ac" - }, - { - "value": 4800000, - "script": "76a914880c2295cc27e8903ff122b51b5f43f88fd6dec288ac" - }, - { - "value": 4930000, - "script": "76a914a5e7f6af5e4cb40484f238b58a2ec18f4562bee988ac" - }, - { - "value": 4353400, - "script": "76a914521709913c73b6bfd4887b01e5b00819f52b8ed688ac" - }, - { - "value": 5215000, - "script": "76a9141e5d736be3911036ed0a6e1e6f90c3afc93a4cf888ac" - }, - { - "value": 1097127, - "script": "76a914eb0c5bf618f1bbadde639ac7db36a9ee33efa61d88ac" - }, - { - "value": 1059769, - "script": "76a9149fcfdd594fb86a45c6c98e9af9914e9e57a599ad88ac" - }, - { - "value": 5165860, - "script": "76a914fa3ee28d80d7695195dda8c31ccefc69562fe67588ac" - }, - { - "value": 4334500, - "script": "76a9143cc22dc842599bade858d0a8b4ee4b75b2c984c888ac" - }, - { - "value": 948633, - "script": "76a91494ff49bac8f59b14d8cbadc037f7d564808454b788ac" - }, - { - "value": 959530, - "script": "76a9147a49f1e8b2599cb3fc83d942cd9dc673f6d9eb4688ac" - }, - { - "value": 8542404, - "script": "76a914001eeca11b371d26b789df3ebef64774fba3912188ac" - }, - { - "value": 4616570, - "script": "76a914174773b9518fdc6d85fa8195511bb9fd844f000a88ac" - }, - { - "value": 5190000, - "script": "76a9146e228e35479a37584710b815a29a7c3d8feed8bc88ac" - }, - { - "value": 1022970, - "script": "76a9142b624997182ce88703d213fe10ed62f50d2f5aac88ac" - }, - { - "value": 4835100, - "script": "76a9141dffc6e7fda2bb72cbeafa91c87232c8e0496cb688ac" - }, - { - "value": 4384140, - "script": "76a91485b50b85693a167dc2564bec17554194d00e588388ac" - }, - { - "value": 4362280, - "script": "76a914daa78d9bf530ae829be23623bd2de5d6f31fc60b88ac" - }, - { - "value": 1735727, - "script": "76a9142c7fee6ddf2b32a45eb76b47c7108db89a1ba2c788ac" - }, - { - "value": 4714900, - "script": "76a9149bc19f38ea63fe855d63cd4ec26ef779c021737388ac" - }, - { - "value": 1007596, - "script": "76a9148636eae752697f53d80bd695fdaa0a6109a5fe9988ac" - }, - { - "value": 4746400, - "script": "76a9142f3f5b2a16292a6cb3fdd1d939cb35b603cfb7dc88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "40984b437ba75ad1f97c6bbf843559c5a9b1a865534f1055ea895e2b112918d6", - "witnessHash": "40984b437ba75ad1f97c6bbf843559c5a9b1a865534f1055ea895e2b112918d6", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 432, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 22 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1131338, - "script": "76a914388f8f48cea1a42e8ce5c6bd18d4aa60eb58d20388ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 22 - }, - "script": "4930460221009f422daf42f8af36376f0e5a2ff9cbf91e36c013a0efd2dfc96e3b9440d27740022100a1d3af2b168b6d2899d6477a14a44302e290641e9dacc4ff2ba73245b6494340014104bcf8140fb1aa02796013a4430974099911187ed03bf8fff50a3b97f9b926f60ce47f5c19685aff836da451cd1359cc6a147e8698a0c4f32ba5655a9d8375802a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e28ed39506ef83514255eb37a8b63bd7c4af849c375deaf30348bff733d35477", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a914fb1ed17dd5306aba7f23f9ed7930ea1f2cce457888ac", - "coinbase": false, - "hash": "e28ed39506ef83514255eb37a8b63bd7c4af849c375deaf30348bff733d35477", - "index": 10 - }, - "script": "483045022052bdda81403bd441bf577db9efe505ec58924234d9ca8e7d1961ffc26d7e1d3c02210086cb38761162152b0bc2e9b08d2bdbec1f3a81d4051b614574e658fdda16737b014104b61c37426f120558941fee0c1d0f01a1f4449163d3b82b9e9d418d2a07f4a1fa22888a4fb5cabacc62d6b20ea60111ac778a16f2027a95fbe7babef278e3e9ea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 30 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1185698, - "script": "76a914db5ca71d23d57e2cbc39bc3212835c613bdb0b7488ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 30 - }, - "script": "48304502203c1a7a0130c456d97dfa27eff571845a3aa1e1d338d73924052f038d03a7302702210097dbfd97f0caff96c53290be97958abe2009cf2296bae8bb70e64d71b632069a014104a71bee4a4cdf3346af78ffac8a851a3908a8efab3dd138d5928dcae7f6040c9ef02c277b88bbe7f5605fa7f06828fb2095d55313052d35fc832418795cd5e8c5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 25 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1062907, - "script": "76a91418d361d7c8ce9d2c8e986b44dce333253efbd83f88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 25 - }, - "script": "493046022100fea16f8b0baf57fce0a471e088150ab3a3b87c89b0b6e7ae52d02bbbfb5ad78b022100a2e1dbe800dbcc25b1a6913a8ec72309763327b43b09ac8d6d03d12892e7a9e8012103f5ddc1f0473a84dfaa753ed518071f0d078e15668ae5765523b18893520fac0c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1158761, - "script": "76a9147ccbd11e65558747ff3c29e18e98e2f6ed3ef96188ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 18 - }, - "script": "493046022100fec0abdd8f1793d3ba3eddab582bd677c3336aef86e3ba2b1d5ac005fb6c342e022100b3e27aa3423e3cae54aed6d310a3aee1a4349257040d496af2aabb48b26451900121034a273eeddf927c1a06a504e4c52236c6cbbb389db73c67e25c155824f5c248ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c585e0e388f7a5217f5e5c304cb1f4311b75c1fb936ff844686ac4fb18a8e2e0", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 9902720, - "script": "76a9143e11ec794f4d8804ad17892bc9460b092af94d9e88ac", - "coinbase": false, - "hash": "c585e0e388f7a5217f5e5c304cb1f4311b75c1fb936ff844686ac4fb18a8e2e0", - "index": 13 - }, - "script": "49304602210081edbd1c470d38147eb352d2218d6665ef98be701dda6b921f42a853e41fe2a70221009b5e395bfbd09e6d52a7523e6b9621d77dce9983eef5e7d01b68b602ae89dfa9012103b06bf59d38fad5c6d37bdc2b9093dc465f81ef62ad899121b091424de5a2ae10", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a914714b66260419fe61d97e6cb6ddc38f803eb9899588ac", - "coinbase": false, - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 4 - }, - "script": "493046022100f81a2121c70a85a54a4f7d8676813a693f3af5fb2f69d2c3d86dabb0355b60e2022100a6f1a958cb70630c33c4008260e8d2d4a4ed26421c9dadece6948b32f6747a18014104734702d645fa6f84194c6edfe1efc0914751c11007e80cec7b501bac45dd8943a0f53dd35e9b7431ffc53bfd1195eb3871b7fb5342281112bc5a6c9451022e46", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 19 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 942530, - "script": "76a914926241d1ee121150d7d71f2c3434348d8969764788ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 19 - }, - "script": "47304402201c070b6bb7a0c000fc6056de5d74fa43baa84bbe9bb2acc564925fc4bb162fff02202540f271bb7de2128374821f91c41247bdb77b37a5e369843037b3de40a72afe014104fe79c66b2b0d05f380efe6017515cd314e5e74b68c2ee012dc15455dbef8b1f50fc24f6f41ea4de459b17217db10d669cb5d34969c5668215bce1e6078806298", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1111186, - "script": "76a9143042caa17295ebb8047ddb51c080a67cb04cca5d88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 2 - }, - "script": "473044022028a63ee9c374dc570efc9d81e07818c7e0b4100884042a7ae267f4a516ebc4fc022065f60f898bc370d0c20de8c5bbcb371a5b4bf59cc675f43c3a6ef18966436d0701210272cac8b4be2bf9daf70d942d27808a3d7df73130045dd7cbda5dc24c531aab00", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 993850, - "script": "76a9147a0e98d4a5e81245e33a90c962420440f307d0b188ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 16 - }, - "script": "493046022100c87cfa2525991fbeef8f3d4838ee5576a288b0d4f660856635cb3f9550cac9f1022100f719f1d33d3dec02d1d36c5313c488900a87fda7e5d4500357479bb08139d990012102359a57b88b7e72baf9564158d183f370fb8a7b2cb9ca672c6089cf68a5989e78", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 967170, - "script": "76a9147c4d01993c1ee950a4ff1a03a3380972653e2ab988ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 18 - }, - "script": "4730440220432bd86967972d077e7d65a95a53f70582eeb234bbe2f8647e97c24572894479022022df6f98c0730446954af7fb860c7353f678eec961ed191f874555b695ee7746012102a7e7d735afda9077d791a2b990dafad9dd9a36b34408aa7a5f5ef9dc7ec2f6af", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1196936, - "script": "76a914a020e4d1ccbeec080f21ac8fc35ce6262fd2b8c788ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 15 - }, - "script": "483045022100b7210b2bb03018427e5cd828918a1ab7e03c1ee4362e6bdb7ec758f98a30d91e02207f32e9f33ee8abfae4c6513f244af40aa6dfa70ce5f9035878811d2163df8a8c014104283f30f1ad19de79f4a642d50a7221e83dd4492c304f4b05e915286da2a4ad54402e7fd4374d070df3979c0dbbf2d1c65588d3a8940d5ac5df24218b3ec80de7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8542404, - "script": "76a914001eeca11b371d26b789df3ebef64774fba3912188ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 11 - }, - "script": "493046022100ae33f34661b84e7c5af7765e1bac5e60e3175fb0f7d4e0a3f95164876ebf4fe2022100a3e73b8a75769bef7581f9b88827fc44f762581cb1900f5c0f50acbf4876dbbd01210308d465ec11d2f8647e11329e8cf75f447c6a90f19ce3673c852bbc4edc1ef0d3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 14 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 10000000, - "script": "76a91451dca4884161ba843e1b6d020f3c4ffbe4dbc0bc88ac", - "coinbase": false, - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 14 - }, - "script": "4830450220012ee08d4e5b7765d8440c16906ff1c91146d02b1333c964f139eb82cb1c468c022100c95b6fa8d4b4b9c3716e3e8d50e64476e2811de71f11c229a1e803a37524708f012102c5861e1992d9222869c50656e4e109d9bdba774fb5ae2fc337fd6cdebdc9ea47", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 21 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1188830, - "script": "76a914dd5c5d81c470bba4177ddc400f7d25fa40372f8688ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 21 - }, - "script": "47304402202ba9eb84973f08011fc8cbc7a5f9f1e9b573fad7514f4586836d64b5eeb0e288022054d4c8edb09ad0db69282862d6dc33328129a9d3cec53b175c908ca7645b25d001410495a8ec04c1a5cafd89d50c5f6a8ae19f70aaf4576cb5f7db06f5a91f280925436b81db67d1bb3f9a20b4b5c09667c5f82f33faa71ac5572d526f80f37e6f7ec5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 24 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 939937, - "script": "76a91457090fea0f1c33cfe548cb6d560b9499d945956388ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 24 - }, - "script": "48304502203bb14663c72874bb52472ca0f48489637cedf3f7d2542010738909592f1e730a022100e26d45b7b9974b5edb8b2fc632de9cb98a2bd8e9a915dce3af049b3c2d3e3ee5012103ec00b47f606abf45716646d803d1b0fdc1f71449eea25453cb355f444abed36a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1167247, - "script": "76a91416dc4e564b53557bda01931be67f259e83f9abf588ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 6 - }, - "script": "4730440220169cebf520ca3860b66cd291b4a4063dbe60cb9e9c3b7727e42ba4312269e3d9022048b580611883eedf0fa909de119f26eb1eb4880885f0a33afc590f0339cb11f0014104942e75fefbb00886172e9d4cd48a1b2895480e4c0d77e50d317a5f02fcebfb724f49aff635a79bfbe64d2ec0a12da66dc6db6704a92218278b9fafe45e7f6175", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 20 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1007596, - "script": "76a9148636eae752697f53d80bd695fdaa0a6109a5fe9988ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 20 - }, - "script": "48304502201b070254398a9ba8e5f3f4a23866b4aa7dbd8c124a61c761348dd347b3f48da9022100c09a1e9b665d5d657898ef1151cab3f2cc608aede1ce685fa917565c23994e7b01410447b5cc15b2dd5b5bcd788fbc35f4da75728a431b423818b9b5c3b33aec298eda1e70c1926361b838d5ae415089f11b829de637de7517561cb344fb697668aeca", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ef213e922ad1d05bead701c48b689730d7f78e39c8c801d2fe9eda4610fd42cd", - "index": 23 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 10106372, - "script": "76a91440682e61dcd36578c80e10beea532c6e3dce358688ac", - "coinbase": false, - "hash": "ef213e922ad1d05bead701c48b689730d7f78e39c8c801d2fe9eda4610fd42cd", - "index": 23 - }, - "script": "483045022100a56e04baa0e128a984579d4fc6aeb12ef39819624a6c22b41e05f850ed6cbaeb02205942e1fea60d0976a8992cf320c318edfbba9dd40a9593751b01a3b1fda4189e0141043ec5e3a3c72204ebccf60ae47f67e4b5433a5ca533602e12ea59b5f9b1587770b756550c73f670f239b7f6d23dc523a80d9f07b1bfbd11e5dc87282af04be67b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4f973e5994f73c02189b1f0f3e2179e7faa6ca6b213ed01377de1b959891a931", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 9700000, - "script": "76a91491cb473ab14d9b6464e7ae218786fff7c07a802e88ac", - "coinbase": false, - "hash": "4f973e5994f73c02189b1f0f3e2179e7faa6ca6b213ed01377de1b959891a931", - "index": 1 - }, - "script": "49304602210084ed90b6b05c70bb9ba2f105b4d4c6a462727738b93682a20c43edccc0e6068f022100ea62590b50f33b7ce93f1d597a948d03b21ec62ca72a1a1e5e69b08305e11edb0121025958b38d8cb91558d64080e4dd1948e8785a0675ba851171d4f468811c7ea66f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e28ed39506ef83514255eb37a8b63bd7c4af849c375deaf30348bff733d35477", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a91425597bf2e7e2f9d428d3547618b3db5113658f6188ac", - "coinbase": false, - "hash": "e28ed39506ef83514255eb37a8b63bd7c4af849c375deaf30348bff733d35477", - "index": 3 - }, - "script": "483045022100b73494eed9f9e232919a47939ded8f340a6bea099973740dda1dc099f8f282660220677f90843132c04dd46f13b2e31db400cb554b95a9dec2559ea30244d92c935301210252fbe4b31224f78387b26dc15a480448fb2b6afb480cd194ab2fd3b0a6d95778", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a3fda664ad3c43d74b16c77f9e43d542b7d97096192391be1b0765ce62e5ed38", - "index": 8 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 10000000, - "script": "76a9147fb1ea69db640a2016b9d07b744b1dc58b26dac488ac", - "coinbase": false, - "hash": "a3fda664ad3c43d74b16c77f9e43d542b7d97096192391be1b0765ce62e5ed38", - "index": 8 - }, - "script": "473044022078b46fd17d8ac340334829d4a745dd8068eefbd85887c37d21eb7a3fc245682f02202365d85e20fa8d46e60d61c82bbdcb3b158394afcad974bf9607d263879e72f40141047d22b58275b44fdba31172cde8884efc654e61449abcabb1292aac050c862687413d5cc40889f4a5af0914ee0146a88404b79f2b81bac7ae143b2889b9bb6816", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a9144cc1f278d7d6a5492d48a2284fe1ad63f8cc0cd888ac", - "coinbase": false, - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 8 - }, - "script": "493046022100e9690c516619867ade528e1e972a2ecdb2a1d228f0e9785dc29d3a184161e507022100f7b4108297d7ee3610414b26065987a145aed1518b84d26317c3142f4385884f01210379d390cc5d9329dd10807279e6efb9afc2e82da5a8ea813d71cb97726593cca9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 16 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 10000000, - "script": "76a91445e1692c1a967788443107f954f9863db3d314ab88ac", - "coinbase": false, - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 16 - }, - "script": "493046022100b4b48219328ad6abdf1e6f7d87294685e83930b11b955487b7a9eca782055e6c022100c3ca4c9d50a70cfbe41a3c9c80103c424361bcc2b08b5cb4d6c77bd066d6b953014104948dab191448c499f08e0d1594cc3db208e8420e45619b83832daba9be6c01eee1cda7f1ce53a88ff912186d750a4d3295d0f4a6e1a8a74376db3453f1ebe54a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9102df6151ab4f39b75a038a66c12f8f73d89d13d97a9dfc7d454d18a9eeb210", - "index": 15 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 10000000, - "script": "76a9147cac0158a9465e19d193aef906555c87413b144088ac", - "coinbase": false, - "hash": "9102df6151ab4f39b75a038a66c12f8f73d89d13d97a9dfc7d454d18a9eeb210", - "index": 15 - }, - "script": "483045022021dec1a5377f46f92e75f5f03d55c2afd34ab978a34eda76f7baa4dcbc2ef2cb022100c173da0ea68923457cf83c88a664a5f7f974643e68b18abfb16575c0a72b367b014104c21c35e823441370c01b346270af246f4991381767e8de501dea1e553611ed6db613b108f15000189ed83af82716247faaf3db329e9318705936d2a951017eaf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 11 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 10000000, - "script": "76a91448221c49f40c9548dd49601f7e257f4c73e62f9d88ac", - "coinbase": false, - "hash": "1770e25f69e7c0bc95b209a094c8f7783c4bdb4a32fa8edf19b8358daf838951", - "index": 11 - }, - "script": "483045022100d28035c7e25da835f1a786298843b85182bb1d3545153ea920ee6b010f0c700602204f89f9c7084d904861440af4b3adfd1d516561325666662e50b332435dd0ed3a01410495794fbaf5f05c14572e15abbabb373b4c85fb0dbf75972222041e2d299e8036704495628712f3ffa57bef3301e3d0f3055c9d2826e6c209578f2d4248704a11", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9700000, - "script": "76a914f199be8d88b959171903187f8d5f7481cabee37a88ac" - }, - { - "value": 10000000, - "script": "76a91406653377a0240c1057d8bdfa39680cef4e7dc53b88ac" - }, - { - "value": 9500000, - "script": "76a9146152525635ce5b4c7add61fe58b07a74010f463b88ac" - }, - { - "value": 9000000, - "script": "76a9142bb8506f2e4236d7c08ef0adb080fe995e38612688ac" - }, - { - "value": 200000, - "script": "76a914fd0734de6e5adddbacdc1feea2bb0440ee1aa06c88ac" - }, - { - "value": 10000000, - "script": "76a91433feee2c850a440d9224c1185de0188b45c8fcb588ac" - }, - { - "value": 10000000, - "script": "76a914234e6c49499dadfd4ffa90c348651f02444b226588ac" - }, - { - "value": 9900000, - "script": "76a914dd628aefde9a3b86714f4a0712ca05382ae3a35588ac" - }, - { - "value": 2345482, - "script": "76a9140d1cdf73f27d9167faeae8754ca22c3fd0581c9688ac" - }, - { - "value": 10100000, - "script": "76a914789b14a48d10c6ab22b9b0873c87a27883bd255b88ac" - }, - { - "value": 10000000, - "script": "76a9140df163d11ecce237042f438734d668f8ddca9dc588ac" - }, - { - "value": 600000, - "script": "76a914c517c7af71e20f37b39f90f17df0b9a778652ce888ac" - }, - { - "value": 10000000, - "script": "76a9143839e45fa2062b1c12b06b33a63241c3be621df988ac" - }, - { - "value": 10000000, - "script": "76a914e18b75edaf4199586cde868f6bd91e7083b96b1588ac" - }, - { - "value": 10000000, - "script": "76a91487f63cac71f664d0624a232091e4db93bcf8256988ac" - }, - { - "value": 10000000, - "script": "76a9146de67278829be2747d488e696da46994c72dfa7e88ac" - }, - { - "value": 500000, - "script": "76a9146dd3581a572a1150bda796136c41345da065108088ac" - }, - { - "value": 400000, - "script": "76a9148de2c86ed9dc08e56d37b444acdc00092a22ecfa88ac" - }, - { - "value": 10000000, - "script": "76a9141d638c2449e194915683de830a42abcb4f08b9b088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "witnessHash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 433, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "40984b437ba75ad1f97c6bbf843559c5a9b1a865534f1055ea895e2b112918d6", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9500000, - "script": "76a9146152525635ce5b4c7add61fe58b07a74010f463b88ac", - "coinbase": false, - "hash": "40984b437ba75ad1f97c6bbf843559c5a9b1a865534f1055ea895e2b112918d6", - "index": 2 - }, - "script": "483045022077db203f302c3ec007820189adaed2052a9302c777153d6d8ecf9253297143ae022100d5c2bcb49ade20bc02947a4f9853ddb786625d137c8f314591fa7b1296b0dd6e014104748c6fca99736c67901d2cafb439428b3c30aa7526936c6e782c3b9a0d27342c9e1b5e1dcdee207f00f48863b6e857cd4388a260a0320d185a67255a60393b47", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bf9d4553caf4a880e3bd72948613bd812b9e4d09eacb8b08f2992ca0d6e63ebc", - "index": 11 - }, - "coin": { - "version": 1, - "height": 299986, - "value": 10200000, - "script": "76a914c61d0ab218ad821dd41452dab5f799fe46f37d1888ac", - "coinbase": false, - "hash": "bf9d4553caf4a880e3bd72948613bd812b9e4d09eacb8b08f2992ca0d6e63ebc", - "index": 11 - }, - "script": "493046022100d2639f577e80d2cc8ecc0db0dc0d4d4783b3d19796ddef761d376d9ae48275d8022100e83ebab05d3ee59bfe8d858a13642ad36bd500cddd4bfe44dcbe1ce74f89ab380141041c98c19561ffeb1365af963eb17fe49b525b565aefc4a9045fa3da6b8c07f28c33ca8cb9fdc6a16aab4603475fa803538d4b3c25e16037a2f00c6c79a1fc1c4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 98000000, - "script": "76a91455329914c548c298fed50f2e8c6575b27b5e5dca88ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 3 - }, - "script": "483045022100d08107f8f9fa52f268ce0f23f7a606d25fa73cce7ee45bd1879d4b855ed3191102206f5405af1946e1751997ae7fcdfdc89fc90e59f706ad8a7b2051b3fc968b9f8e0141048bc6ae71d9b8fe323034f868f140537470e360ab96ec816303a7280fec6acbf6d06001cc035aa3d6b6d9574cb5af6358d84413aa3f2913bbb1046de503193d7b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1097127, - "script": "76a914eb0c5bf618f1bbadde639ac7db36a9ee33efa61d88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 5 - }, - "script": "47304402202176d3925f89e43e5aaedd961269bb86e2560335666f21453801d74889a83c70022044150937e005c7d1ea54420c65a1511480b8c2202c27e979b4d54633664bd06a014104b29beac7ce4916ab67062e872222de88150c2098b26123b112cf658b34d64003cbab2362189aa0649cebfe31522946422385a4223b633c06800b0053343f9b2c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1022970, - "script": "76a9142b624997182ce88703d213fe10ed62f50d2f5aac88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 14 - }, - "script": "483045022000f1d6b4677a346b4c2ece32d636f3b4c16d422b57e33a8bf1cf273b36d74099022100d26b65f055e61754eb3f34ece68fbed96fd8b78bd3a61bedc8df5b035b5b4a90014104cb431f9fa58ee6f0f90593409b32c4626ad6a10c8759a22a4b4ced8d14419e66d0b29c8312abea9db7f2d696b9e1792e32fde3548665c2ac288883ca33f561ca", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1059769, - "script": "76a9149fcfdd594fb86a45c6c98e9af9914e9e57a599ad88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 6 - }, - "script": "47304402202ea748793ffadd4f14ed2301de6f1cc1111c4f999f3c59c9eb5592d17a49d219022037ec360628c487a88b1f031c56217cbf06ff92c57d359afdc25641890d490baa0141041164b49b188899b726e845ec428107ef58da09901dddba921be91bc50f9d7f9f47ad8da9089f7135feaaa8fb567b6f750cb58e1c904baedc9d730802d426a3b3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "94a5241c4eeda717a58d557e456697419cfa77fed8cb9e507452d9229bfaab05", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 56860000, - "script": "76a91492d5b8d1ff5f99c7538c5c82bce9afbab1cec52788ac", - "coinbase": false, - "hash": "94a5241c4eeda717a58d557e456697419cfa77fed8cb9e507452d9229bfaab05", - "index": 3 - }, - "script": "4830450220152b6577a08ea113ce4dce488b55bb7fa587946b1cf1981bfd3385d600eee59b022100e9cbf8748f8c09ed9bfa20e0c80133c0f4fb13bc8ee085246097fd2f4a8a8a780141040fa477befc8a09f19fefdbc618a8d3743da8225814e7e0e5582b3b2ff7ad7829b69ce162075473f9c4e6d017f6a7987105924c1f12ea2b2dcc4f5e6e264d9f2f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 98900000, - "script": "76a9142fee3f92669369ab015437fcd3539073b041cfe688ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 7 - }, - "script": "483045022100d887688aa71bc13c70700a65ad850429060b662850f524c30ec2e0df020816cc02203a52121420d054ca1db90185458c48970aa4bb5812013d7e808a87acecdc37c50141040d8b51e51769702aede411365be328c1c798ec24036ac1e5f94091e866f5611fddf7b064d0e7a9484e996585e3ac87ac19873379e31c2fbd0d9cf633607f8cd4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 12576100, - "script": "76a914f2ddf172bc30e002a5499f69913322898944b8d088ac" - }, - { - "value": 13150000, - "script": "76a9148229e172293528e1c85bf1d1e8cd5025faf88f5e88ac" - }, - { - "value": 13520602, - "script": "76a91409a3d63b335f8b6da4eeb38ffe6a2ff9c9f794db88ac" - }, - { - "value": 14813900, - "script": "76a91424a6a200209812d8597755e6dd26a7bf398194e588ac" - }, - { - "value": 13870000, - "script": "76a9142bcf488000a9862285a333439f029cd952ae9e5388ac" - }, - { - "value": 10200000, - "script": "76a914c48f203c58b0360aed6feb0acb9621b0135a6ac788ac" - }, - { - "value": 14809430, - "script": "76a9148ec840592d4ff2fe9ec510402dc8424ac726729e88ac" - }, - { - "value": 41996000, - "script": "76a9148472ea8487b97be0e3f8a07bdbaeccd909a2735188ac" - }, - { - "value": 1360000, - "script": "76a914eba99baf55d8c5cacbe0c21b2a969086ec64905c88ac" - }, - { - "value": 13612500, - "script": "76a914406629bb14f36aad37d6bf04adf0d07c2c7d388a88ac" - }, - { - "value": 4506986, - "script": "76a914607ca1ab946870c050e676f3d7458a564cee663288ac" - }, - { - "value": 14380380, - "script": "76a914f29d588fbddbe138cfbc34f68a8f0742fee6899688ac" - }, - { - "value": 14673865, - "script": "76a914f43942fea5aec511fe2fa7a48253caf024f00ec488ac" - }, - { - "value": 750000, - "script": "76a9143c0ffe5c7187e3788a666bb266c31f3ee748057088ac" - }, - { - "value": 9450000, - "script": "76a914483ccf3945f7f04ef1d869ae835cf825c2d791b488ac" - }, - { - "value": 12334200, - "script": "76a9145f09849066e0e42ad756d9a7c858b9ed7814388888ac" - }, - { - "value": 13684000, - "script": "76a914eacbc34cce62c5da8df868d727a5631d02b072ec88ac" - }, - { - "value": 42000570, - "script": "76a91445154beba6aa2cad1100b69c9ed48c7acf44ba1d88ac" - }, - { - "value": 14921333, - "script": "76a91408cd0e293d35ef940a100ca2dc28e5c602baaa1488ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "witnessHash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 434, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 20 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4380000, - "script": "76a914a5a045c8bcf10deb53cb8da8a91e1a23333ab2b088ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 20 - }, - "script": "473044022019c0f8008698e353f410118e1cb5d4b1fba2d32d86be178ced22b0f1a17e2dc102201ca8c79044f0925dbd1019a64613ceaf401f57ff56148b7caa52aec26c3515920121035f1b07e7ceb92b5efaee4cf596c6499431781376a3dc55f75d70a0f66c7857a5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "aacdcdcf34187dee8221e814da6cf1cdc1c4e8ec694fa245338bd907d3b9d676", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 43695472, - "script": "76a9143cd17dfe97f403fd9e134fc398d6932623ce8b3a88ac", - "coinbase": false, - "hash": "aacdcdcf34187dee8221e814da6cf1cdc1c4e8ec694fa245338bd907d3b9d676", - "index": 8 - }, - "script": "4730440220018edb5dcb877f2999345aa5c077f0858055f681bc8632dc0ba03cc0c80d0cc8022063d6535f9f841f48c7d295321d6fce87a79efa84b622e207a2f187b754fc3d63014104aae431e7a5097064886497163809438773433962e860a1d7f2d0052521dc86c53aaf9d61336eb5138383ec89660a5fd347435bb13df0017515eb9eccf57b3c9f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4380000, - "script": "76a91455578a712d2a51ca2dbdcec0fa2f50a0e435613188ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 3 - }, - "script": "4930460221009c4a4c0638c930646035c2d6482acae1fc763fdcba88c52178b037d6cfb0a85802210082110366625c12ccef75b5ca30612ac084b9337adb50bf9125088fc34e0ef26d01210321c5c9bdc0240703b5ad98626930fa46ba17ea0ec13cc5f7f31e57169e48d220", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "69854a5034bfb423e7969fa3c9e8866e8481e3fbe047d33b72a10306176a5c5b", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 11679938, - "script": "76a914991b50db59a558c3c1c08d9a18492c0b10c6ac1e88ac", - "coinbase": false, - "hash": "69854a5034bfb423e7969fa3c9e8866e8481e3fbe047d33b72a10306176a5c5b", - "index": 13 - }, - "script": "48304502201f289f758bf7ee968cb75d2f17e548c4cb7293fca7269135431beafe75edfd44022100a8128412517d1f25a348ebc5adf1b2138b15c7248367dfd1a854800dcda06d72012102e39f59e4da9a7498150c28b2575827669ed99ab04bf2d8204bbfafe1b99ae2ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4384140, - "script": "76a91485b50b85693a167dc2564bec17554194d00e588388ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 16 - }, - "script": "493046022100e14934f0eb4796f6a8bee9ba0415b7edcc20fb57c41dbdf34781c3852194fc54022100cdbdcc3200bbc4c88e511ae9058a16577f64eb73095e04705f8fa8ad1aeb7c98012103ce3be22106a6f51708778ce5d165323a06d0089c187a6e5dfbd2df9d9e0e813c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5a157495174c5de62732d2da13f00e6090848d8e063b1e3aa57c4c6c5e1e343e", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 61258800, - "script": "76a9148edcd22861c315823d371ea1223a0ed4d6d789cf88ac", - "coinbase": false, - "hash": "5a157495174c5de62732d2da13f00e6090848d8e063b1e3aa57c4c6c5e1e343e", - "index": 9 - }, - "script": "483045022100d01edebc047703e170d86e70049bb64ac8549c10ab1140ac3c6d06c6c057134f0220194e83aeb1942a788eeab3945a1cb92dfa05a0564ab4498d09070e1452543b5b0141046312ecf59753d8e45755e142b153b5303bbde8c4885fd7a7562a4b9c29ebf8fd43c71626d9c1195517a9112c20fc3cd4e3a49eeb7d2e312a3c28df9de2c224fd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 13520602, - "script": "76a91409a3d63b335f8b6da4eeb38ffe6a2ff9c9f794db88ac", - "coinbase": false, - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 2 - }, - "script": "493046022100dbb9721592fd8ca0e944f6f8a868557426f8e0a25a28506952c417bb312479f80221009d11e07a88f91b1cdbc3a15b27a772f740f7e81832800bad722ebc82b022ac0301210359bb61e0aa2f8329a6236008e50ad3f78830fa6027a7177fda5ec0ddf4b5d9e9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 14921333, - "script": "76a91408cd0e293d35ef940a100ca2dc28e5c602baaa1488ac", - "coinbase": false, - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 18 - }, - "script": "493046022100bdffb50b2f5c49c9d880edac3ce54b8ccec830593d196b782e2a7638b2d74eff022100d4f43f04fcb868ed9a84b8a3520da34067f9a5900f470b54e9e4c82e28535c780121022b601c45d8350d582ce5e89250edc5cb3b804d8b780e1099ba4aabee414a16e6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 14673865, - "script": "76a914f43942fea5aec511fe2fa7a48253caf024f00ec488ac", - "coinbase": false, - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 12 - }, - "script": "483045022100c9415a7377167a6911225116d8276ab82f9ef457add2092a3832e33113cc91da02203d8602da642b56460e4b252481faaf127a8bb9adc248c1480242bc47236e267901210358f80d4684af10a51c8975f091006e5b9d3cbbb658c1c5f1dfe766833e8b516a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 12334200, - "script": "76a9145f09849066e0e42ad756d9a7c858b9ed7814388888ac", - "coinbase": false, - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 15 - }, - "script": "483045022100976f0e4fba52f9da61853f82ea98ad55bcb82ab4c709264b898793737b3292e202200c4ca2da6d13d60ee33c6489e8e0831d9b3ed2cd1e1256c43362223725af56a7012103eae6b859a7abf100e902b83947972714210af7b8a629a0141acc6314c0f5a76a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10100000, - "script": "76a9146f5a56888c88458676c44e2927b7ace838dedace88ac" - }, - { - "value": 10439199, - "script": "76a9142f0a76e1f401e40f95b502be64ac079688d29ae088ac" - }, - { - "value": 11400000, - "script": "76a914f27ccb83b55ba09eb1dbfa21aa28b721d63d3bcb88ac" - }, - { - "value": 8559151, - "script": "76a914bb5a3ec420c2cab2ef166f4c1fddeb5f6fd287db88ac" - }, - { - "value": 10964800, - "script": "76a9148c0c3813404eeae9c8a1c95d89a116bf72ca7f5c88ac" - }, - { - "value": 11254187, - "script": "76a91484c4ec66ae67d12fc5ea0f0124aee68918c35a9088ac" - }, - { - "value": 10880064, - "script": "76a9149c005f9af86b825da3123586bf2f6b3655295b1c88ac" - }, - { - "value": 11400000, - "script": "76a914e6c72c4916d5ac6888fe4826b54514f46374ab1b88ac" - }, - { - "value": 10240000, - "script": "76a9141794452fa336c5839c84ea853aaa669c06c4692288ac" - }, - { - "value": 11024296, - "script": "76a91491e89934e38a7024d0008b5e47c16eca319f96a388ac" - }, - { - "value": 10590000, - "script": "76a914bfa75e4422547ffe6a843997913694a705e64b9088ac" - }, - { - "value": 11435450, - "script": "76a914c60960a25c4a910cd6985bfd8299038b38ee11b288ac" - }, - { - "value": 11206000, - "script": "76a914f658e9d47d89a101f39e94b292b19afa496e1ef588ac" - }, - { - "value": 11900000, - "script": "76a914e4bd95277432996bcf7e38a722df7747291dbd7b88ac" - }, - { - "value": 23700, - "script": "76a91424d7cb73bb148f092f6cedb41aa23086ee8d269788ac" - }, - { - "value": 11565500, - "script": "76a9140288d331d41e854222285839ba78758cc12722b788ac" - }, - { - "value": 10806003, - "script": "76a9145daf9cd79143d602cf608958438683565c0582d088ac" - }, - { - "value": 10000, - "script": "76a91448ea1aa741150307e615b331ac25ff9dadddce2488ac" - }, - { - "value": 11400000, - "script": "76a914fd23398926fb4cda82895f9fa1180a42f735168f88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "dbb220ef8a2d9dded1ee8f75c31e6ae6e8b56b3f25f07ca7fc77e2dc823ba7b9", - "witnessHash": "dbb220ef8a2d9dded1ee8f75c31e6ae6e8b56b3f25f07ca7fc77e2dc823ba7b9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 435, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 27 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1203311, - "script": "76a914cd6bc256740207eee453fcd4858b9fb7602642ae88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 27 - }, - "script": "48304502206ab696c7aa388fbeb43e91fd11e57f6af863a648bdf6fc6657e6e97f696d3977022100ef69e8b4852f4b79853eaf9ed639d1c80c85f42b8d7926240a237ef9127175ba0141044b629175c71873c21a62c57144f1597766d676578ca824665249ca8e66d39ceb13e93a7bf77ef0fb897a7b91f417074e39169f73a14cf9aa63ec5bdba01620ac", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 33 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1252196, - "script": "76a914d8bcc2b801b1cc5bb27831a2547d9cd9efc445e688ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 33 - }, - "script": "493046022100ec66917b9f5923192d7d3f12f58ade329e9173116763b56f9d03e1970cd8d5e00221009b9a5f07e4a45be1fdceb78d3633384ce287a3b6367406aaaa9924ee9136d45a0121031cf65b42a77f37d5a98631ad49db9b9db200af5a9155d1f59193bea7ec785e2e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a914dd628aefde9a3b86714f4a0712ca05382ae3a35588ac", - "coinbase": false, - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 9 - }, - "script": "493046022100cf412f7cfa5acf82fccc6aff7dd74ec5576364747156be35b647c81aec27e5bc022100da11be053057b9bdbf7fd708371c9d37b4ada9ddcaaf06f01655e0741f28f04e012103d2b7ddf20106d7e9e0d52ac5e47789a6412a939337fbd7a1f11af5ceb42e17e4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1242478, - "script": "76a914720441e4cca49ec247e8ccf439dbf46e5a5b864888ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 5 - }, - "script": "483045022100d184d674ed111484110c4d88db3421fd1db965f7f670ab860554e2ac44c55dc1022057e9ca012886b6b5a288d5f1d98fadb969001d0e36fcab0065373621693d7ea5014104e3fd350afc0f3d31a0e34c59591817ce0ffb878e713c8d0f01750994d72f32f0fce45704cdfe9f29409c4379bc60fe34c1e5425fe56f4801c4824424ca642cce", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a91459c7ad64812c5190a9c97965c290cf0970bfa90f88ac", - "coinbase": false, - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 16 - }, - "script": "473044022078a0f994b62714e726c7be8f7a095b757baf712edd4592a02e19ddadc59e2692022065242446dab9caafb259560ae5861c0fcafa7bc9d9a7c94dabb68c0c7324c94a0121036bf3331bad17d297504a8b6d889cfe94f5eeefd3d76756b9a534d53d12167f22", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1218155, - "script": "76a914bff0833eefd926688258344a01707a3fac41edea88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 17 - }, - "script": "483045022017080cf4691c79030d8399c7f64406db002eb4b0c2366960bc87834f724b779b022100d66a4cb30b912ac1ebecb98947b6d44500d0feaf8bf35e908e41b9699b2966ba0141045f6adb0ba5d80cccf3985c7b2817ccc38720b13474223897c2503bb6cebff2ae942b26247288df30896644e4f2a9bf7a048c5acf9c9ab3c4d33255c88163912b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d2ad400ca26e3935af8826064bb7626816f061b8d6b968a00c11e3a59c153bd1", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 10000000, - "script": "76a914771a9974a8b5a2a009f397d0c644589aadf2aa9088ac", - "coinbase": false, - "hash": "d2ad400ca26e3935af8826064bb7626816f061b8d6b968a00c11e3a59c153bd1", - "index": 16 - }, - "script": "48304502204d49253d690cb01a40e9a7fd49aba8bda332b6bdb468afddab70f6a74af33b76022100db10f147541d6b3e02ade0283ffece290b5b1e06484c3f811c398fca7788ee03012102f38a81cd35602d08221dfb688235c7f1f31c698036b257daa12077e68e92d121", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "38c01c33e908b641bf8cd52513ded78471621ccdf594c1070bd35cba3ded691d", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299986, - "value": 10300000, - "script": "76a914b4fa91737abfc0e93c09ed2bda40679a56a2fa5388ac", - "coinbase": false, - "hash": "38c01c33e908b641bf8cd52513ded78471621ccdf594c1070bd35cba3ded691d", - "index": 2 - }, - "script": "493046022100ae666271098e41200d1f1eb7399e5a3c2494c9131b0e97a8d03b034e6b45e297022100ed0d6e001afeb5698eff28f4730ffc89e368425359da5cf84b8e7cadd105aaf10141045ec787dd7a5e608bed2819bf1280846ab4362b62e7e36d913c16c5b85f97d14b43ae01961e71ac926d0f2e33ffaa378c4a63c262d390929f69b2c4acc8daa757", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d2ad400ca26e3935af8826064bb7626816f061b8d6b968a00c11e3a59c153bd1", - "index": 24 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 10000000, - "script": "76a9142a8ffdcd190bd0a6bfbb5211c4c55c0a5ebdefc588ac", - "coinbase": false, - "hash": "d2ad400ca26e3935af8826064bb7626816f061b8d6b968a00c11e3a59c153bd1", - "index": 24 - }, - "script": "483045022100bd4cbece255f8896900fd4d759d9b2025bcc99ef33f7e2ab8f5b7bce6c12cd030220625178ada88f829ba251d9d0203d03ec2f820f82744c6b1d2b2868c0b1b4596b014104aa1bb93ebf506df3f3405bd979e12bef6960c376c674174663f5b511bfaae4c58ae94c3d50df75be5ec09a4947a9e1af49e31b33f0870ddf682b6b41c513afdb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d2ad400ca26e3935af8826064bb7626816f061b8d6b968a00c11e3a59c153bd1", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 10000000, - "script": "76a914abbb59fada0f502b5952ba276f4a48f64d8f6e5088ac", - "coinbase": false, - "hash": "d2ad400ca26e3935af8826064bb7626816f061b8d6b968a00c11e3a59c153bd1", - "index": 5 - }, - "script": "483045022100d80264a06b00b105dfea157dc3a7517e611fb418d29d68e358b11184102bc80502207c63be3a9ca9001904cc6eb13a196763f515187f2bd4062f24c9497f20520e68012103333053795a2a9a30e63f3efd6e01083df2a965b492cd6e5cdbd0610832dfd671", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a4e1eff4f0b59e1106878a918dc7954a3f254864e3fbf4065fc0437488747c4e", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300006, - "value": 10000000, - "script": "76a914fe3ccf799fc32e6d49e7ae3ad5dc199b6271cc3588ac", - "coinbase": false, - "hash": "a4e1eff4f0b59e1106878a918dc7954a3f254864e3fbf4065fc0437488747c4e", - "index": 10 - }, - "script": "47304402200df432dc28d84ac32c06f396c4dd282829dc25772d557e728cf53b002320fc2602201e2c8c74be4577a067b6ea242a2c7b6ec9dd34b6fe7fb22ce0fab16ace0211dc0141040ba8043318555f0a6c82f6d50e8a6eaa76625ec1f8e890de5c7caea489ae513330baa97231818b88bbacd8ef8fd41792ec6cf2f65cfac9603162f4a4da06b534", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4334500, - "script": "76a9143cc22dc842599bade858d0a8b4ee4b75b2c984c888ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 8 - }, - "script": "483045022100e9562b319ada72518d0894cc237db8b5572fefe1efd82d154fb5fe8e7ae1e45d02202576219848fc80d2fc77c8801f9f6340311f2fdb8b258589c56a35339fae934e014104459d40686128efc773e3c3873a4aaf59259bcbce2fcb8268d7451125e92916c5d595652a7c0063381c2b1f9666bade1fd4618861042c9bafe481df49e5749b9c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1735727, - "script": "76a9142c7fee6ddf2b32a45eb76b47c7108db89a1ba2c788ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 18 - }, - "script": "483045022035234d306c1d046b45dc93842982f3edc6d974a944559ad92db2eca3b5eeabcb02210090f84fa2e8bd957fff35ff97a6d61bea0c283546aaf38ea93cd89e5955d55aa8012102a489c6e5b12ced191b5e327b8f5dfddea3455c4dcc6338ba84e54ed2a986ec02", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 19 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1202586, - "script": "76a914d35ad3babb53cbf5d5249fc15e218e937bfd57ae88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 19 - }, - "script": "483045022100a2b86d91477de9b37a443078ffe85fd2fc1ae68e6f128e2203cb7208a9d6713b022011310d3a132d2d0f4ecad0cda47f1a11d37a8603b1cbde3b3a3455cb05c766ba014104a3dac426c72a73cf8509404da805fce315ad169c1847ba6172b0aa287ab43ba297eb4058cd9411a80cdf666e019e623037dbc96b95e496d57be35697bc4c8bab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1391955, - "script": "76a9143027ccf55b4cca6fdf49298735e0193e2e55c95788ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 4 - }, - "script": "48304502201d732c9d164d31cda6f36f736a1bcdc0828218d994aca8f68e61030d7537eae9022100972ee7c795b76c3bd18d3c4fb56cd15e6a22620bbd50a5acb36d0682bad2b7f401210325e13911e3b1cb95c7d3b1592c342527fd1ca0a007551da4c03d6da99051504e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 19 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10000000, - "script": "76a9141921ca63e4f52130e6127aae1142756de1b4a59888ac", - "coinbase": false, - "hash": "a312aa99d91650c63db43f3d059c9ab924f5c038d7ff510efc520fff4382ab57", - "index": 19 - }, - "script": "47304402201aed980aa069f56bdbd9153502ef669f220d3296b3bf0887690e7371aee6e554022007eb9868b27ec94b737218e6fdbef14791d58de3f5f69b9ea2bb2ad64fd6e922012102d6e5293b7ec160ab117aad0ba31bf2791556ef859e2aa147d1dcebe3129827d6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9102df6151ab4f39b75a038a66c12f8f73d89d13d97a9dfc7d454d18a9eeb210", - "index": 6 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 9700000, - "script": "76a91443200f7edfed659f8380325e8032ffc4e341238688ac", - "coinbase": false, - "hash": "9102df6151ab4f39b75a038a66c12f8f73d89d13d97a9dfc7d454d18a9eeb210", - "index": 6 - }, - "script": "493046022100d6e8e9b0789d02883567a0484bf7578a2a7a6d536dbbd94726bb8bba95dbdbc1022100ffe5a8204a64914dad09cfdddb98a95c010fabc6195016cd7c1ed4535c2a87f90121039ccbd06bd78450f2dd434a79187c2c89fb1a1a99e82df0971836a700aabc41cf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eed3d2e0aaaf1dc60a875da5f5216586464fa0b5eabdda4662cac73e66f29e18", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 10009266, - "script": "76a9146de67278829be2747d488e696da46994c72dfa7e88ac", - "coinbase": false, - "hash": "eed3d2e0aaaf1dc60a875da5f5216586464fa0b5eabdda4662cac73e66f29e18", - "index": 2 - }, - "script": "493046022100e09fb130296935932380697293d59c68e6234ebb0a70c620d4c0caa1fae84ae10221008bf2ee9f60ce4fd8559a47ab02678cb5c1e4238ed31de3918c2cf715f314bbc901210316bc163492bdfaf285d7788dc928dedfa97065483c61996acf76ff868f0d8b66", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "40984b437ba75ad1f97c6bbf843559c5a9b1a865534f1055ea895e2b112918d6", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2345482, - "script": "76a9140d1cdf73f27d9167faeae8754ca22c3fd0581c9688ac", - "coinbase": false, - "hash": "40984b437ba75ad1f97c6bbf843559c5a9b1a865534f1055ea895e2b112918d6", - "index": 8 - }, - "script": "47304402200319bf9b585b142dad4ed1d5fb772ed83d5e0cf16cddb0a5588158058861a0e402203e5c88af75b393fdb11dab0f809ff6cb942d9869bd9bd1cc7127e9eae7aa39840141044e9cfd169ec4031d0cf5bc89d7ab3cce5273a40d37bfc5f3c8355dc5ab1aa6f2ba7217dfc89301168bf595f74a9ee81c79cf3acb4287cc911dd16d28c60da025", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4353400, - "script": "76a914521709913c73b6bfd4887b01e5b00819f52b8ed688ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 3 - }, - "script": "483045022100a78ebe892c18c13c2f7bb754191545640890137252647f676c323dfdc1c6bdb1022000ef5ba6d004abd8f4b6bf9d060f88233dd4b6aa8659f342cb432bda5a429517012103b9e663eb3ddac6d7c0a75200c5bc6f6b50e0ced10131047aea3d39825649fdb8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300005, - "value": 10017330, - "script": "76a9146d3084a29be8e56ed65f828219ec0207172a8db888ac", - "coinbase": false, - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 5 - }, - "script": "4730440220643ee0bf7437027d5ca4db94b15eb6ff14fd349fbd3174a7131a308e3f4f03e702202b99fe81844683e17c6e80906a5909761a6e40745366b579ddfd58d06bccc5d00121021cbe3461085feda4a6ec70b27fbbcaf5ad2d1dc850ba475addc98df520e05430", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 10000000, - "script": "76a914fa4127f83b843a11d396eca4e9edfb61bf4666a688ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 1 - }, - "script": "483045022058025eae32684972d75b224bda6bf103fac557c5774be2392e56d02f0846a64e022100b0d5098b04eec9b9a9d093b2f5ea65cc83619fda8f9ba3ee9acca6250655833901210349255a852e2c2a5e5575fe1b7842f41bf8efc82894de65ebe10dc31fa55701fe", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4362280, - "script": "76a914daa78d9bf530ae829be23623bd2de5d6f31fc60b88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 17 - }, - "script": "493046022100e7d882ebe1b8aaab9ba8eae11a6afd9732d6bd8d3ddccf6a246e81b8509f41a4022100fe840985ec1a896edaffe1fa22f13c6e88beffc8dddd6f502cf0fa208464592b0141049d53483475d31e0626bf1ec883f4b2f219b1992734f64a60e41fb13cdbb0053747216b5f1d14c7df6458825fb17ab968f614a366d0e1ffb429ae161682deb0ad", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9450000, - "script": "76a914483ccf3945f7f04ef1d869ae835cf825c2d791b488ac", - "coinbase": false, - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 14 - }, - "script": "48304502207a2cca355c0d6adcd077ec2f0c9d32b620d6e4b347c0a4936f24f33e70656e8d022100d57ea64e1dade3e6eadb00035d73bf45196c02f70667df880e13508282bdf426012103d3b74d7dde36d51a5e88f793e2876fb4b149e97189bb66726a4c0957fa6ea3bf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 28 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1220780, - "script": "76a91418f98d8d2fc0611099bdb2fb9ee891579d9f01f588ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 28 - }, - "script": "48304502205ba37309c4ad9eb89bf88467259e16f47469567c7d33b0ea538bc398b0144ed1022100a27132b4517893f8ca2a83b3a48f9ae1332ce5adb9dfa88a79aae6a6351e7408014104b75022f3319e83071db6c6768f436d3a0e811804e54756c78e06b08bcf81c13d34fe8b011d967b12e4f5ee1210ce66a8446bd8c5e6d4d03c80937ced42c1ecb2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 600000, - "script": "76a914cca05eca1c99d07b14d26d416d6924b3cd41c84988ac" - }, - { - "value": 10000000, - "script": "76a914084a13f4e128b907f0bc3d61a389242a1f9aefff88ac" - }, - { - "value": 9700000, - "script": "76a91448ab77bb19f9c9b5c60e3616d758c9ae81c9116188ac" - }, - { - "value": 10300000, - "script": "76a9149b55586c19277afb65c6a274e2b3aaf1daa5f62388ac" - }, - { - "value": 10000000, - "script": "76a914a91a7271a766752750c3a6cf521d1823984d9cb788ac" - }, - { - "value": 10000000, - "script": "76a9146309b13c921f0c5dd4a1f907d7e4d2ade2f364f388ac" - }, - { - "value": 10000000, - "script": "76a9140d7b37f22218ead2740cc9394b44f8bdd0c8b00188ac" - }, - { - "value": 10300000, - "script": "76a914f0c4464ba7801cc203f43dcdbf7cccbe7ffffe9f88ac" - }, - { - "value": 10000000, - "script": "76a914f9b2bda34f7dcbeb08255dc3f28ef96b294f2f6788ac" - }, - { - "value": 10000000, - "script": "76a91421b2cb699eac6ca3c6f74ae8e7eaa009192bca9888ac" - }, - { - "value": 900000, - "script": "76a914f2f9c64c2d4f699442e8d150cf83fb9bb40db59588ac" - }, - { - "value": 10000000, - "script": "76a91412c9e33a5b33e18ed9391a599fb9cd3a69071b6c88ac" - }, - { - "value": 10000000, - "script": "76a9149fc31902aa5c2afef45d151dace129984e02742a88ac" - }, - { - "value": 4119446, - "script": "76a914964118b6d7e820db230ba5afa3ed9c153295c40788ac" - }, - { - "value": 300000, - "script": "76a914238208d2002cbf9c405a933f12e99dc3b07bbd2788ac" - }, - { - "value": 10000000, - "script": "76a9141ead0ea3737b8e7301363d59604a6984ed3b8bf888ac" - }, - { - "value": 10000000, - "script": "76a914f905c20d178e83b1dfaff260020b0a651137ce0588ac" - }, - { - "value": 9400000, - "script": "76a9141bf58146cc165b7ff31908fd30881e0b2ef3a46b88ac" - }, - { - "value": 9660000, - "script": "76a9148f8d0281dde07de3dd42cf0ada297ef8ec9ec10988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "witnessHash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 436, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "dbb220ef8a2d9dded1ee8f75c31e6ae6e8b56b3f25f07ca7fc77e2dc823ba7b9", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9400000, - "script": "76a9141bf58146cc165b7ff31908fd30881e0b2ef3a46b88ac", - "coinbase": false, - "hash": "dbb220ef8a2d9dded1ee8f75c31e6ae6e8b56b3f25f07ca7fc77e2dc823ba7b9", - "index": 17 - }, - "script": "47304402202e6c670674053f6530d0c49fc8e3778c91953aae7481adad460e4ca8f09036e002201031ca408567552bfe9f363c116da289a4f85c50cf910e3b3d09f173ccf2b31b012102c5adee6d17700f4b8a9c17eb691dc087a8c6fc87f05390ad9f5c6af37a2e1228", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c585e0e388f7a5217f5e5c304cb1f4311b75c1fb936ff844686ac4fb18a8e2e0", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 9978130, - "script": "76a914fbc1f7d886685345651ec838cab4280fa385028388ac", - "coinbase": false, - "hash": "c585e0e388f7a5217f5e5c304cb1f4311b75c1fb936ff844686ac4fb18a8e2e0", - "index": 6 - }, - "script": "4830450220460ddc10e79d60630cc21a582233297ba6e4b3184ea88abccb32695646ae5ffa0221009af46206b0208f9a981388d3e4e4b4b5109a433a4091cfb83a5cbebbb3dae2ec012102319b49423adcd6e6facf0abd971328554953a8c4617d3c6887575bb7d32816af", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "09be2f4533dadca1810a9fc669660ab764b6534e8579c3055f01f589cad27fc8", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 11920000, - "script": "76a91456a292b30a03bafd324f88596bee1e0d67492be588ac", - "coinbase": false, - "hash": "09be2f4533dadca1810a9fc669660ab764b6534e8579c3055f01f589cad27fc8", - "index": 9 - }, - "script": "493046022100bfea4cc38cbecfe63f8cc42e087aef219744cf9beb3073843b00961e2217d3190221008d25c01ce69baffe6407b44e6e7c1db430c9ce40b721c12c1556e4fb985763bd014104385e6f5bc97fe708f2eeebfa24533a59c3aa98e49d14107ac29e3d1b6d57e7b59d73e8992566fbc7f7ec562bfbd98b428e932dc952429d3257f76bce1db30b20", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11024296, - "script": "76a91491e89934e38a7024d0008b5e47c16eca319f96a388ac", - "coinbase": false, - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 9 - }, - "script": "4830450220592840dd46005186d59dc6d3986392c0b593a1bd491aa415d3be71aaa4c9a42f022100f8c66a7f83fdb18b5e1a65310542f25507021caae0c6fd8dd2433c894b4ecca3014104c38a96fadd93ee92dde50045b8b081f3bc1e742307d4dbd0809fa2014bf9b108f770ffec64d2f967fbc4fa334a768c39a8548ad57504d3b333261aeee32fde3a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4506986, - "script": "76a914607ca1ab946870c050e676f3d7458a564cee663288ac", - "coinbase": false, - "hash": "3839ea1c80f531500111b2af5d1de10f69e4933a0bd901b78c92d5b0337ff343", - "index": 10 - }, - "script": "48304502200af955b4ef24a252f8a2e70d85e9949a12509d0c605eb2d2f84d16bd630996c3022100df67dffbad8038905741d0ed445a66fd5af9940db9885c072fc28ad740ea91c50121028ed9495ee023a9e0f53fb631e191b68ebcd8cea8d8a7385f9360cf5843a25e4e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4520000, - "script": "76a914eeef3f8a586a44e1528355ed6239e231cb4d3eec88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 12 - }, - "script": "48304502205c1b0bbf88817e514868c79c2cb609b7d9b626349f57898de93d6e3daf3316e002210091ea84b89007124573f623dcbd89a0a23788f6a92aa45254c9740a1db509fb64014104f8331544b4df93a5d0d894daa10e550ad1d4ee702bc0488a2bd28eb4a6f5bed34ac7a8524241ce7e69437418acaf184692280d86ad27ac66828750e94ec2d7d7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 43432000, - "script": "76a9146a833885d8020dd73fa17b58f68e66f90ab7bbc788ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 4 - }, - "script": "493046022100c962a12232caf0365355ed20abecfbafcd03e88d4d14a03b37b8d5c8980edb6502210086e7ba338c8139c92d8553719e8cc7fae5278bb122dc8ef019524b87271049ff0121021727077bced85694f731eddea69809d4da46a3b2ffdb4d9cafbf4a6c9f8dd521", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 20 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4520000, - "script": "76a9149d1e31b6a3aec46ed2b4f9259100b47fde80796688ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 20 - }, - "script": "47304402207ddf0520b7b5e448427f526c39ec7a07511ae0903546bac1947191679bdd16300220019c72be4c5c9d8ff13bb8a0b06b40dce23f4e49e26f075d3551027484b0563f0121025ca5e3890bdafc0fc3ead5636d027953e6d0f7d3396a36d44c3fbf0dc843c295", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11254187, - "script": "76a91484c4ec66ae67d12fc5ea0f0124aee68918c35a9088ac", - "coinbase": false, - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 5 - }, - "script": "47304402206a37a66f588a17ff34ec8316df851e7bca605909d98e9030d9e1525fd6d2538a0220782e82d8a312708b96f7bb4dfae487fa9e261b45f84055a34f112da8896fd18301410429dc17ebfb08182a6803f4fecb6f5d089f53d66457d5a072a6439b028c36b11d998b04d930186412523d885dc2a29ac54b1ec5c0bc9fd233af1f7c198002c188", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10806003, - "script": "76a9145daf9cd79143d602cf608958438683565c0582d088ac", - "coinbase": false, - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 16 - }, - "script": "48304502205bb2be57c0450632b89a0de38fb21b2e749589f0f692fd3731aad4e05bc8066e022100bb8bce0727df09cc0fc08f7c420d562b8d9391ac7216a9d37950d75ae260003e014104744913ba05930e636a67a7a599ed7772e9dafbffa7f9caa49e0c9a863d0d3ac27b62d5371a4fab81789c196f4ea2f86199bfb7381268677ba18158d377391cb8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4600000, - "script": "76a914a40b4727754801733a9161c3db55d956fb1f0dbd88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 11 - }, - "script": "48304502206523a4ddd2b60ae958c212a93e82bbdb76f8584d69027d4dcacc28c075cb752d022100a4824d63cc8883f6f22c91fa804e5bc7bc6a398a1d92aebdb3dffbd49519c8f201210390d63bc7cd113b822f34a84eb22cc1953d59feb8d8aaee3a7298ed9b47516eba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 27 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4600000, - "script": "76a91487985422a514da921120c4ccb9ef4e03fb47116188ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 27 - }, - "script": "48304502203a376165aa98f04bc1ffd6d0815696440e75a512c95347d97905af10c8d29509022100c0f976ad1c1ac0f6df394e28cbd99896a958de04cf0ce89e6e90a7f23ff7c8ad014104e074a70288ddf37bca335a76bec3310e5c5a481d5baaa11a32b146e182fc46ac5fd890541ea78b90a0fd7c10b9ebc9a36fcd2025c364f11d53db791ab7da5810", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10880064, - "script": "76a9149c005f9af86b825da3123586bf2f6b3655295b1c88ac", - "coinbase": false, - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 6 - }, - "script": "4930460221008f96f6167ac8aca35fb99a6ad7ad866e090ff45cdcbd5ca6999884a62f348141022100e5d77feaf62814ab649184fb2feb1f76df6188b100f36bc8dd8ea7773a422427014104c7fb9f5ec2c861f2f9d464fe37647ec647a67572bc93de56116134add860ea1f21d3976eaf7d197603a12c7a76cd0f6f18d292dd741eb1efd140ae9ccefc6a85", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4600000, - "script": "76a9148dbab30a385350b4ee015e4c78fe020437d51c9288ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 10 - }, - "script": "48304502207d4ba2a83cf472d74934625b33e6371c6285e97e9d9c44a065119cea2e6abfa9022100b459175818e48b95e4e8be8b09b594f40a319c08df7255410eca9dcd09e1fb72014104b669fddb79332d0a2c78b9641790eebfdba1f777aa5fde442abb5610cd8674837001e4697e29e8de0b516d84d394a45be53d70735911e5e51d40e5ddf616ad36", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 9977790, - "script": "76a9142c7fee6ddf2b32a45eb76b47c7108db89a1ba2c788ac", - "coinbase": false, - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 10 - }, - "script": "493046022100a4cb704842b6a9f6a6da36ababe93b684fd49a479e3bd2de07063d215b09ab15022100a1e7386b7e756b0b0fcd7a8b6a492a2d0721821b33335046119b79fac8ab0ea0012102a489c6e5b12ced191b5e327b8f5dfddea3455c4dcc6338ba84e54ed2a986ec02", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11435450, - "script": "76a914c60960a25c4a910cd6985bfd8299038b38ee11b288ac", - "coinbase": false, - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 11 - }, - "script": "493046022100b881babbd05964119574e9b145a0f366d56d782e17e24065ca41fb6441ecc4fe022100b5cb40beed72dfb1dddf27dad87adcff5c1a66bc717643ed418f7dcacefff4100141049f3b1db7ba5adfc4ef08462429162858e4f6b8497c312a38044c8660a023299fcccb492a2dbbb1454e834b55dc69a9c523fb9fbb2efc92eab08ed76d718daf69", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ecad6874192f21c68e36e3092e9c6da40ddbd95f7af8be2fc8a0bfdb100cb365", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300002, - "value": 11685512, - "script": "76a9145289ee4cf745edc1302d5eaeb1ff86016c20994788ac", - "coinbase": false, - "hash": "ecad6874192f21c68e36e3092e9c6da40ddbd95f7af8be2fc8a0bfdb100cb365", - "index": 14 - }, - "script": "47304402200815cd1d7878d31f2c4b4ef25f770adecc8f727103f45615a2ee24bf8e902e1402206932db8764d8822f0484fa37ae831c7e264fa7ebf48f6269ca0635c67e183a820121022624d0ce42c30a47150f94624d1f6c66472f6755092286c2d3f2883e8ad90a90", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 26 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4600000, - "script": "76a914127026b9c6e664944e087c4b01b64923937e9de388ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 26 - }, - "script": "4730440220684116b7d5546c58a0bf30c742d30ed2f404a01ca6ab8fb83469d8bd854ba787022024c697b3e4bbb954783727faa286c95f2c46130b73f280961eb5044c12ac85e6014104df723bf8d26ad9252c8e577b177e56c5361ebaa2c6114de3bf87ed3a066ab8e48d66aa8eb8fdd819129809d003afaa0bfa3b859562f65f7ad5fa7d4ee7bdd0ee", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 43670000, - "script": "76a91432fd49eeef7e4dbcad7d9b629612d0279d60c45088ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 0 - }, - "script": "483045022032e0195b1d5f46522a19c12becb498a2c3204bc4d4643cfd025e5a7e7f0b1650022100d7e7860bd7c6a958dbcd6317c258822eb25e6096f43625ce916176d1987590d40141040519235bd320295c2b68ef46af2757995d20017a230d3578a8ba2964582a959f43a7e8eb54f22474ee52677aff7e905112b6a04a272b09f5ae72964dd7440744", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 14138580, - "script": "76a914dfa46e9d50a68a26ad8efc5db744cec96288cbef88ac" - }, - { - "value": 650000, - "script": "76a914fc8f77547ba041fc81f6f4bf33748efd4745e0f388ac" - }, - { - "value": 4137232, - "script": "76a91457b5ce3ee016834cb3d12de6241383d6be1ea53488ac" - }, - { - "value": 12811000, - "script": "76a914d94a57b33bf83651d4ecd8518a87715469bbdee588ac" - }, - { - "value": 12759000, - "script": "76a9142868f8a566c7457f7c18d4d827a976ed4fc32f6088ac" - }, - { - "value": 14667530, - "script": "76a914f2671e0316f834a1fa6f454e27dab1f9aa7b720b88ac" - }, - { - "value": 13785000, - "script": "76a914f8a0ca6340c51f87261ae3d95965cddbbc26839288ac" - }, - { - "value": 13912176, - "script": "76a9147e42faaaa2dc73084e62cca5e3872d6700edf88b88ac" - }, - { - "value": 4590000, - "script": "76a914a03a8006661021677f9380110e41dec2e147b48588ac" - }, - { - "value": 14188900, - "script": "76a914d31c51fb822a6d882d5dc8e5e8516d9787ffe30788ac" - }, - { - "value": 9350000, - "script": "76a914f26546ab755deeec0d77ea56a958c5ed5a79c65888ac" - }, - { - "value": 15020931, - "script": "76a91412e8cc8f05958492f2e047b6ce9c1d204751e39788ac" - }, - { - "value": 12991298, - "script": "76a9143daa3803657e6063eb20f3a87adbb3da756491a388ac" - }, - { - "value": 8665800, - "script": "76a914fe0f4a1bf09cabbbe8b67e3ce3e5216a799a680888ac" - }, - { - "value": 14330000, - "script": "76a91457349ef88d4c1ebc9d38dde09d354dfeea6d7f7588ac" - }, - { - "value": 13148871, - "script": "76a9144dff1411b5a26215f237c613b29bba0f77c4613888ac" - }, - { - "value": 10000000, - "script": "76a91426204b4000509c1547c0a130c03c54cbdc7ecc1088ac" - }, - { - "value": 13034100, - "script": "76a914f905d48f5c588241b76e83c947340e91e4b0bdce88ac" - }, - { - "value": 15180000, - "script": "76a914dd34e623434d9746243c67ff734acb4b9383ca9f88ac" - }, - { - "value": 10000000, - "script": "76a914bdd467aceba3ef37021c41f120df3c516fa2265b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "witnessHash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 437, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 42300000, - "script": "76a91485b1485fa600afa0c03c1ac00949f36ab1d4467588ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 5 - }, - "script": "493046022100ef24d3e0ec2af7da5eb28393c1e924e205a520775470c5fefb7ffb30be68ed37022100b569af06e7fe5088999dcb44b50fd18eb380928483bcdf503596d8978a5b0f3b01210299d34f1e445eed0d00f125e07d9b46c95ac489ad8207bd5a6200cb24c825d6ef", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "50ba98402dfa8bb27917bbc36f69c6c5c5f3eb74bd479bfad762825527327380", - "index": 21 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 11806000, - "script": "76a914a420614786113ef5eef9495c4745d061af82cfc588ac", - "coinbase": false, - "hash": "50ba98402dfa8bb27917bbc36f69c6c5c5f3eb74bd479bfad762825527327380", - "index": 21 - }, - "script": "48304502203134b76cdcd691806c89432e881cd6585e15b8a56b5887b8d066bcf1d9e0ee310221008a025bb4dece2eda35d05dd1f108a83dce473adbcca32ca5b552f701bb5610cf014104c6f43a85db0bf88404b178b1f228e9d99411808e05fb909c52ac998c90ca98a43ea31e4a394beda17a751b42de72895d1095bde30b7745d46f3a26973ceff02b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 13148871, - "script": "76a9144dff1411b5a26215f237c613b29bba0f77c4613888ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 15 - }, - "script": "483045022100b0b51b949af6836e3c10cf8540953fd0719b619fb4732489d44514d4cff2389402203b2fa0041e36284fe841bf8d75603d2a8110a7a3fa0b1a24884a2b0ff32e7b61014104e5e17a85c5c4f644a78b400e79bd7ada36d573ca5723ef4da7d0f8009f3ecd2228d315314135f2402bfb31358dc3cc8355c1420c44b4ba5d2c5fca76e3f1e2fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4930000, - "script": "76a914a5e7f6af5e4cb40484f238b58a2ec18f4562bee988ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 2 - }, - "script": "483045022100e131c7fce0bda6b4aab0b19e9957f8faa585b4e72b9ddf86fe7ae9f78878c87b022056fd9f9881d296e43ee545820fd948e2c49e09512943adb8f07b525e10c6adfa014104e5670130da433a8a1de205640ef70343657ca0c00a9bcb0d42e92fa37d9bf3253345b1b0e7c5e5f102952dacab780d65b6881386b48bd9a4143ac404f0fa4697", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 15020931, - "script": "76a91412e8cc8f05958492f2e047b6ce9c1d204751e39788ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 11 - }, - "script": "48304502205d6071bb094ab20cc7b6297275ca0fdfa1cfa9502d45eb7777727693f6011342022100c8b03dba10612a743ee9053cf2b90eb3669f2f93badef0711f7cc716e512f96701410415ab729af380add375c505c08ced3fb1542d8f0ecf936b601ae73cb54403add51e1df81008226c8e12769a1a88dd3a4fa964c33af28941aa810c24604fa6cab1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 14188900, - "script": "76a914d31c51fb822a6d882d5dc8e5e8516d9787ffe30788ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 9 - }, - "script": "483045022100e30705523ded4b2854b17c0b72aebb160f761dc2e755b0f86b07197169113328022058572494502c5e154cbb5c3947e41be02c274cb323d8fb8c79fd3c63912ff1da012103b4caf1d1955f4f5c1249c3ecde5734e5f329c5050b2a3200bb70d71e74272a8b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 12991298, - "script": "76a9143daa3803657e6063eb20f3a87adbb3da756491a388ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 12 - }, - "script": "483045022100806041ca0bb18f43c8cb085ab06896e57102c8faa08825269ae1124c6f903ae402201bcada8bbc7f8a992f9c089cdf6c2e3f6fb2178fd1d9bf75dc2a65cc5c141f9c014104e8d97eac23329f9e02e180c3ac3e529993c47b417e611638512588d0c94234f6523b8481b23ef37057b1e3350b921b1b8abdb64f2e8dc48fe41e266e45040a1a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 23 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4844000, - "script": "76a914e4c174b13ac640ec54556fda1f827947184067e188ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 23 - }, - "script": "483045022100b93e253113a0873ac2a2c45cc127b5ad01e2cfcfc871f471d2d802d1507e787d02206e60cd1800b8995d3420b2c9b748f61a328ca63d98d1920ff6a8bc14df0f71ef0141049513211554b9d9c8c0577e935d77a53320383a02f38fdd1b42fd70af9dcbb44111c912b95ca63e716a34f93f932da9ef05a5b2d81df4b6640ef1bd91bd795192", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "79459bc59f2868e089b1d20b01ba3197d99ba9bbc16ea2318830331775183ae5", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 12989658, - "script": "76a914d723ff83743557352001a2119ed1923a9ec3328188ac", - "coinbase": false, - "hash": "79459bc59f2868e089b1d20b01ba3197d99ba9bbc16ea2318830331775183ae5", - "index": 5 - }, - "script": "49304602210097c936174b06cba7b028d523274e66800b314353f11193e69dd7842b1d93b410022100b7afa13fced6e6b7eb56bbe172051b825ff333e73dd5ae78b0144bcd5d0138a7012102c1ee0262da95bff94c871d885dee93d9017419fb799eef958219a432910575d9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d47b3890f00d45df78e4b7243f42ba05e5de3329d235379712d93fb8a6588b7d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 43395683, - "script": "76a914da03375246c61576c3e87d4e93c6d5e47282819688ac", - "coinbase": false, - "hash": "d47b3890f00d45df78e4b7243f42ba05e5de3329d235379712d93fb8a6588b7d", - "index": 1 - }, - "script": "493046022100a97a8855e6bf3b56ea87f0a12adab1ed62cf36c05d3bf5fb6b3593327def613d022100a050fb43a9ac6291c53991657ac670701b3479dfaf57e51fc17c3830b479eddd014104f6b72c23dd3a9ba9ed7802f2f6ca305992bee7986877fe04e6a44552337575294c7d2d7b3d98dde164e96efc7f2d57fa7a2a4ffa815e8782e60977915f3e3b29", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 10160000, - "script": "76a914a2e507baa931ee065bf93d9675b244dcfeb1a93d88ac" - }, - { - "value": 11100000, - "script": "76a91405f649ea5a29a9f70215519549ecb9d10bbc841688ac" - }, - { - "value": 11500000, - "script": "76a9147ebcc8a5e225c70931307e0e3fb4db3aa78868f688ac" - }, - { - "value": 10600000, - "script": "76a914bac12ead918508f226ae799e144154d59bdff03988ac" - }, - { - "value": 11026100, - "script": "76a914111985a61b2c2efd2aaa1e0a3d014816806cd98f88ac" - }, - { - "value": 11800000, - "script": "76a9144564fdd685cd60b725d06b2f2936d56294e02aa788ac" - }, - { - "value": 11800000, - "script": "76a914dd34e623434d9746243c67ff734acb4b9383ca9f88ac" - }, - { - "value": 10800000, - "script": "76a9143406a0c7b5321cf3ba50ed2dd35a56152c0862d088ac" - }, - { - "value": 100000, - "script": "76a914f3ed99f5ea0e2b3c648878cc214925c7b861f38488ac" - }, - { - "value": 11045589, - "script": "76a91483e2338bc9021bdfa6b17d3d426db3df897c78f988ac" - }, - { - "value": 10961504, - "script": "76a914302ebe66f0bbb66855163dfcff6b1020cb43f67488ac" - }, - { - "value": 9685341, - "script": "76a9144cf9c3cfd24fcf0579039df4dfa9929b76a0a82988ac" - }, - { - "value": 11138925, - "script": "76a914e7dc89fa8f91c31ee4e6e3137367a76395268c8588ac" - }, - { - "value": 13900, - "script": "76a914771a9974a8b5a2a009f397d0c644589aadf2aa9088ac" - }, - { - "value": 10000000, - "script": "76a914dd26076ecc49c0b44476aa08b8f49a4d4d009e6c88ac" - }, - { - "value": 11087501, - "script": "76a914eda8a507f022ac4f1927f9c0b7d1f41324358cc188ac" - }, - { - "value": 11700000, - "script": "76a914880c2295cc27e8903ff122b51b5f43f88fd6dec288ac" - }, - { - "value": 11066481, - "script": "76a9143b1a2b8ceb576afe043a83c297b8aad873e69a6388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "witnessHash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 438, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 26 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4705700, - "script": "76a914b72636a5dfb06a7b12c50e7d4e73b28a52d1c4a588ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 26 - }, - "script": "493046022100f63dc83c9c32fbb186defcc1ee29078f520e4cb28e3baf38ead9c78a9d5e28ea022100d9f0e2ed6b8efb2c327e2f31755b44f99bade783017f138db3413f3aad6c9f53012103f57f54974b2a66c16f3e1471aa1c09484176552adbe47660194116e9c2f470aa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4835100, - "script": "76a9141dffc6e7fda2bb72cbeafa91c87232c8e0496cb688ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 15 - }, - "script": "48304502205cc03d696668c6b459dfd037e858d3da70c56abd1c6c106c758c94cb760c6ac0022100aa368d609f08bbcaf16bc0b98d75f74b7d0cb3b301878ea8e37b535347a17bdc014104a2a99a940f255341024ff11402edec43d299e52023a438746cd70b46fe528e779a4d2722846f4d9449e43cb1d15d9e8ef4cd63b8f06276293a21fd522718a334", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ef213e922ad1d05bead701c48b689730d7f78e39c8c801d2fe9eda4610fd42cd", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 10028467, - "script": "76a914e86eb11e4677a2f6f55da333893ee05e75d9d0a688ac", - "coinbase": false, - "hash": "ef213e922ad1d05bead701c48b689730d7f78e39c8c801d2fe9eda4610fd42cd", - "index": 16 - }, - "script": "473044022025be47f1dfbb0e2010a2f6978e2c019c0a4b4189ee51dcc8d107e72bb7beef32022043b2606fbb062929834b99bf34150ee81ed2c8bea2e7c61b234741b86368cce0012102b3ff9b591ae128f0d94ae3c1a0aca78ac10a2d275629d65cef7de55bfbf8ba86", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "50ba98402dfa8bb27917bbc36f69c6c5c5f3eb74bd479bfad762825527327380", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 9929245, - "script": "76a914ef751e014c376d2c6e505b04698a521c9a8b5f3388ac", - "coinbase": false, - "hash": "50ba98402dfa8bb27917bbc36f69c6c5c5f3eb74bd479bfad762825527327380", - "index": 14 - }, - "script": "483045022100ae124d9915afa98ffcf0eb13c36230a46dd5f017a522ed80e1ced1901b657b1d02206c78b330941ced1cd96711b6b65fce58d5ac684eb5f0a3136bde119ba585557201410486252cc8587ddf11e96c5629b335bd6253d275afd88a041ada8576c4e0344a77be085a24a29be22b54203f0fcf645a5dfe27bfc9b0fa81e3ce903c2c6ff6acd9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9350000, - "script": "76a914f26546ab755deeec0d77ea56a958c5ed5a79c65888ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 10 - }, - "script": "4730440220381163072e0711d1a95cddb79de809a99f9d83bc3ffcd361ee6da19558e94b010220028b3d2a0459ec2df4562d019d07cdbf31ee37ccede596608261986d1c1a42d40141040d7e51b2cb3f0b1c0a349c645fd1fbb488a5bc81e30200bf7b25afd8574d631a6f116284ffe2f051ed637f31d7ee59af35348700709ca1dea6f434e8b2a9a15c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4705700, - "script": "76a91494ff49bac8f59b14d8cbadc037f7d564808454b788ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 10 - }, - "script": "483045022100b10f5b55ef25f6dfb56f29fed6cb9e00efad054a5ad3af9e7bb777909112e3ec022015df5e3259a9569db92510705143031130bf1189fc1dc35ee66ba22de93b3135014104b2ef7a418a523480040b239e4706c6b6ad0207622ba7e48654330e1b44ee260bce1534f7d31ca7a426aa0976768bf64ebbf5eeb8466cb98ceb8c4dbb489d9a23", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5f915b3fd8036ee5059ede534d2cde7204dfccb18f1b488a908ed4353fafb130", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 9939050, - "script": "76a9141864db69a8ed6cc818f654f2ce4d1724534d27f288ac", - "coinbase": false, - "hash": "5f915b3fd8036ee5059ede534d2cde7204dfccb18f1b488a908ed4353fafb130", - "index": 6 - }, - "script": "483045022100b6d653f6cf3091d0b52090fec0c0bf6085f8c6a35c3c33247ffe35e3cc6c93ad022010e0cfab24b9cb778a73a8380a27fa56c3a3635a9fdadadce33d1a7a4c24110e0141040170c2d7b1c0ded4e3b86e668a14c7d214098d40d6b5b116d311fd3ec84665c5bd32e4f9ffea48663dfba11cc191256c089b4bdfb85fb565f1a0502ed1c1e65e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f52d87bad93ed54fa161519d4c5d834653f73d6c1e496a9227826f79ba10bf24", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 8921190, - "script": "76a914cb0ef4d0e9c1668b83ef5b7ef48f4597f534b3a088ac", - "coinbase": false, - "hash": "f52d87bad93ed54fa161519d4c5d834653f73d6c1e496a9227826f79ba10bf24", - "index": 16 - }, - "script": "483045022100b0cfed6639f62b65d4e7dcb33500ecc43aabf0df49e1273f6280a8af4eda7a5302205fb18afba989c489d6b18a891af948254c29d80d35b61e2c052bc6df0e07308301210319cadf2bf4f264976821d9d9a5960e720d5742f38d1bfc27e3234fdbe0fce9ff", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "83b9b2043b0e122e4f877d74e50c5ddd3b5f523c53ffff1685ba6084505462e1", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 9500000, - "script": "76a914ec331d278c73a62d415baf4e3030f00a9b199bca88ac", - "coinbase": false, - "hash": "83b9b2043b0e122e4f877d74e50c5ddd3b5f523c53ffff1685ba6084505462e1", - "index": 5 - }, - "script": "48304502205424ce060a742c99fbe6f9aa97d441b076cd4edb66642b0a99f5562f015ab681022100cb6bdb2acd5e340a5ee0ec411efbe2c472402cfd117e29b8b0a3228d97a693e90121021faed8d196b775c9bc36a56cd862c9c9927d89990a898c27a517134fc72358fd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4701200, - "script": "76a91442be5b5999fe4bcd73f12011057a13c4068b1be688ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 13 - }, - "script": "483045022100c686b0d70ea583ba3724d2311c8c8514c9066b1ea0aed145c047506a8246a2b80220048dd0da13efd456ea7038d1775543c2f6dbc435daf5018a73f88badfb35f6b40121039be6157a6bbbd15d99ac927d830fdebce5e68700a408ec28d2ad153c9e015330", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c585e0e388f7a5217f5e5c304cb1f4311b75c1fb936ff844686ac4fb18a8e2e0", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 9930000, - "script": "76a914dc26a966b2d83d283efac4807764e5786dc9fa6a88ac", - "coinbase": false, - "hash": "c585e0e388f7a5217f5e5c304cb1f4311b75c1fb936ff844686ac4fb18a8e2e0", - "index": 7 - }, - "script": "4730440220360e553b4ef3c127cb380229a35285132369cadc9bc44e90a7d793b7829b86cb02206bdc0d4c670b273de7b13b875d9aa1d4e063bdbcd6a4470e8fcea7066cb0fe00012102351c319c7e557cc11a26893ff7528a905699e9c8c16f021575014354c67f7526", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4800000, - "script": "76a914880c2295cc27e8903ff122b51b5f43f88fd6dec288ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 1 - }, - "script": "493046022100a1302f02da35951c49af9fc310d2aed438f59417f6723f15ffe77f052b8f7c870221009f62ba81f4f0fc6549a41dbd81f8bc0c75c66301d6bf54d7f292d063ebb25d250121036876049ac521786285c519fb6fc3860d1bea0f782785c666a47183314671853e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300005, - "value": 10066900, - "script": "76a914fd55e1eb749e6b74f3942ea2a8b5a3a588b7c7b588ac", - "coinbase": false, - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 17 - }, - "script": "473044022047947681431e36144066d2ef313ad0457c408df2bd336596435c0876571c127b0220430628fb25cafa57c4566928930bf2b7a97510401507ff0ab1709a8e162ce762014104c4e0f161838e2d9ca478ea36d9a6f7b018d0c9cb6673c04176222ef29985fd79a0948218fb48624851cf07e9771eacb8098846fffb1b302fe1687cc268bc59ab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "804dc24267cc863314a070d8eb87a1249edc5465df65fc39ab180376830510d8", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300011, - "value": 10032626, - "script": "76a9142f71a76d1f11a1eeb3f77f124a41a99d7e8d088888ac", - "coinbase": false, - "hash": "804dc24267cc863314a070d8eb87a1249edc5465df65fc39ab180376830510d8", - "index": 9 - }, - "script": "483045022100bb359cbaba89911b77d2513ee90645a61e217bbfd11159f4a7d3ec9d5f40204d02204efeed80078b970894b20e0e17c020074a9db22aa4e501ef5eed143830b5631d0121027c02f9463ca5f9b53a605838af5a5ff1834e3a0768239d4583df46ea6701d3ba", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4701200, - "script": "76a9144f6ce855fffe7249b6cd527719fe31260fcaccbf88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 7 - }, - "script": "483045022062c56765923d456c399e3b8de60cc1d9be51bac6b94f800ad75a041562668d41022100f4d05855c569db2e37bd095d1b419fcc15c0ba568eb1fd880096b500570eb0ec014104f815930e63e74f5fcba7395b91af844731f06de77ce83f73876341baf03df03ab48f882425cc8a2004a7c38add42653bc6d702595de57d70c3a57711f3ad9da0", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 21 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4746400, - "script": "76a9142f3f5b2a16292a6cb3fdd1d939cb35b603cfb7dc88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 21 - }, - "script": "4830450220081d65ec6ffd80a8bcf97b29627ff1f8ddfc69c6b0f55386136122f6ba70fc5e022100af3ad93072b3d234732b4032c30b3f504cb92d870ee6e8002488f92331d906320141048a99956e93448cfabf4f375c0d8550fdbad54cd78047d8a6543a70dec9e3da3c504934fde4251e22e22fc63a9a4b4fcfb1de3091b809d7372479bd1d9027acfc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 19 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4714900, - "script": "76a9149bc19f38ea63fe855d63cd4ec26ef779c021737388ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 19 - }, - "script": "48304502210083dba9830ac317c444188b00fa77c03916f659651913105d140ee99a8f4b6ad9022035b7459937cc60b17a8b4cdb0c7c9b56292678a778df5889c5ec18aa906c3f550141045731cf52a701d720e781579e95b4127c4d7f1fe94861ffa3312c10c45782d1e0bd966b9b95f673ef017ff066671e0cadea0cee3486c200882ddcd7f17345f9cb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 35 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4647000, - "script": "76a9141a1117c6baee5d2704fa155b8d22f689a144957b88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 35 - }, - "script": "483045022032d9f1d4e6c1a25b2d6b448e163b6a0a98d05981075061971a40c7b2214ae1a5022100aff9ad47a3d48b450e2757a86f79d92af5299b667911604986fa7c0d9b709dc2012103772df1e493cb56fe6454ace3e4f023362e9c80c203ddd0c71fb1d4dde7eab657", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4760000, - "script": "76a91488dab47ea396e1206da0c0f8cb1081f8700ff4c788ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 5 - }, - "script": "493046022100d2ccc6fbeac9cae058cf5859c844e80b443563181154bbf0e5d659d53529d513022100852763515faf5ecad171563b6ffc8151a9d60ee95cd141f552cb1f85c10f47d30121021f6730141e49ae382a89c908773807769316d38d3f76b529112981b30a735b35", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4616570, - "script": "76a914174773b9518fdc6d85fa8195511bb9fd844f000a88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 12 - }, - "script": "493046022100b6dc7b58e13d5d65bc3bec26869908c503de0e4be376af2804b1e807660c14e3022100e41d0c18a31181425c98a16888bf15acff11a712fbdc526e9432189c42eb5e3d014104ee9f4b9e9597103ec40259fa6a800e6d5d32872cc6d7f9842da6d92f90426c6aa7c101a578e8e93f5fe7339548f4edd29a25b695ef4100759fc5fcfcc352d236", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dbb220ef8a2d9dded1ee8f75c31e6ae6e8b56b3f25f07ca7fc77e2dc823ba7b9", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4119446, - "script": "76a914964118b6d7e820db230ba5afa3ed9c153295c40788ac", - "coinbase": false, - "hash": "dbb220ef8a2d9dded1ee8f75c31e6ae6e8b56b3f25f07ca7fc77e2dc823ba7b9", - "index": 13 - }, - "script": "483045022066e8bddc5181f75a9df7ba380eb1596aae6454eebffd13cbe3d8a1dac1297aaa022100e720d4b25915230c4f6c4200055af9d0aa2b77ab3c01a50bb7bfc9829d78f4fe014104395ace0ec5f0997ad7eec81469c0ce5237de774d99e18f17b35c8a43196686a0480b669ee0401a50f4fdf19456acd062fe2a3e231f11f0ea7fa89b6cf6fdec92", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4840000, - "script": "76a914df55056be381fbb2131ebb07cede0bc0c0874ab888ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 7 - }, - "script": "47304402206b9c4117fa92a4d1b2bbca02542d5ecd7a5eea895c43f200a0aef8cb6fbc170c02201806fea6f741fcd955077e6ac99c43288c1de46146a8147a2c1a0ea3c09f19280141044d415d96b482661059a3901481ca537f13d10c4889e04358f07ed7153e53584d6a8b4379cf547784be6c4ee2f6c2f78dc77ffc4a2d24245f464e76ef4356e4df", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4760000, - "script": "76a914b3e1a38bfe7dc4088a0b2765adcdea80213dd86b88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 9 - }, - "script": "493046022100c45a4cbc570161d77096cffa253369b58232536634481bfcc252074d08b57bc9022100b5bce3b53f0fdc541c8cf6af4e493de5c1ee14aa8d07f1e52f967fd79c761463012103970fa8a5dbad8463871661a4cca2b3a5b8c32e1a31090771add890845f0bb81b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "589905e1dfbc57726aea8a801cfb17ccfa96232b3b43e2829aaba94e7e116582", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 10060089, - "script": "76a914906de1873338762f8dc277cb3c4a2c27040a6cfc88ac", - "coinbase": false, - "hash": "589905e1dfbc57726aea8a801cfb17ccfa96232b3b43e2829aaba94e7e116582", - "index": 4 - }, - "script": "483045022100ba00a2cfdc26661a361fcacd22c324f70462d94fecfd35ba96899ca6168c26b40220215d583166d854cf6c5bc103364524c4a67e8c5731ffc91d09e824a43f83f4d80121034acc934f414d1bab97c69f8d095873af87d95e32e4b298d884cc0399a024a524", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0cbb4000fb92b9fb2488f77c0c24c2bc35e21dba7f11afb246168a8b992f41d2", - "index": 3 - }, - "coin": { - "version": 1, - "height": 299986, - "value": 10110000, - "script": "76a914e5f44c687dd14319cd6f6e1f7af8d4a87146034d88ac", - "coinbase": false, - "hash": "0cbb4000fb92b9fb2488f77c0c24c2bc35e21dba7f11afb246168a8b992f41d2", - "index": 3 - }, - "script": "4630430220700713f06ee6d28515f8d5243c9a64bb0125fdbf4da917e758d572eb95c8c413021f2641d715dd876703d3061f0eb255bca8222322f1ffe4845a679f949d8dfa9f01210251dd25d8ea938b8024d54a551b54256f0a096216107fb850daae071c1d0f0f1d", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9300000, - "script": "76a9143c95b0971196db8b0bd7b3921d527f66008e074a88ac" - }, - { - "value": 8700000, - "script": "76a9146d3084a29be8e56ed65f828219ec0207172a8db888ac" - }, - { - "value": 700000, - "script": "76a914d433f8431306995fb7ea45213390d3bd5205620088ac" - }, - { - "value": 9200000, - "script": "76a914d346fe022a95903737f64256487d960f1bcd2d0c88ac" - }, - { - "value": 10000000, - "script": "76a9145833a6016eb94b63b3dbbec846106cb505b03b3688ac" - }, - { - "value": 10000000, - "script": "76a914138ea57912804b0416bdf48e926ff525717d9b6888ac" - }, - { - "value": 10000000, - "script": "76a914daa78d9bf530ae829be23623bd2de5d6f31fc60b88ac" - }, - { - "value": 200000, - "script": "76a914f29a1fa96e61603e9ddf46cee7e3d853cf80c4b588ac" - }, - { - "value": 9000000, - "script": "76a914103fdd1b43a0d00e858c392ea70f283ebd4ea2a288ac" - }, - { - "value": 800000, - "script": "76a914880c2295cc27e8903ff122b51b5f43f88fd6dec288ac" - }, - { - "value": 9244000, - "script": "76a914977ebf8e9f9a6f764eead20e1e7b1aae7cf45be288ac" - }, - { - "value": 10000000, - "script": "76a9148022d8f58ea0a35a77b5e500bd5d55fac180d7bd88ac" - }, - { - "value": 10312583, - "script": "76a914fc90f2aa3f5bc939d2956b83316f3362a7d108c288ac" - }, - { - "value": 10100000, - "script": "76a9140afa35251c078859bce7edddf85ba8138058e24188ac" - }, - { - "value": 8904200, - "script": "76a914254c7a2b7ccf21a1d695d24559e4e10c8e78817a88ac" - }, - { - "value": 10000000, - "script": "76a914f491f20630785f977ed204bd53970dfb47f1256a88ac" - }, - { - "value": 9000000, - "script": "76a914cd6078fb948388a2f78045ee0826a4828db7f5fb88ac" - }, - { - "value": 9500000, - "script": "76a9146425030240caae1e6bf20c3e061bf611de7cc7e388ac" - }, - { - "value": 10000000, - "script": "76a9144e926e2c60311b7babad34cb36cfa57aedf8835e88ac" - }, - { - "value": 8500000, - "script": "76a9147c5d112d87d2349a795733b2986d9878767d485588ac" - }, - { - "value": 10000000, - "script": "76a914f2ddf172bc30e002a5499f69913322898944b8d088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "fdd7833c139a12cbb6be3fbdf8ebe694441698ddadd52a8a3b52372e3911398d", - "witnessHash": "fdd7833c139a12cbb6be3fbdf8ebe694441698ddadd52a8a3b52372e3911398d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 439, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f90d9845eea45e16d0caecd70a4057d97974c4e22e647fe9ebefac2d7d9fb03e", - "index": 12 - }, - "coin": { - "version": 1, - "height": 291353, - "value": 5685, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "f90d9845eea45e16d0caecd70a4057d97974c4e22e647fe9ebefac2d7d9fb03e", - "index": 12 - }, - "script": "48304502207a940f703f52ad43067e54b8132eb14f845f206c6eb22227b6a2eb5a595c59a7022100adb3f660de6720761a199b9bc394383f89f4cb9a98a366bb29bbc08702f67a4c01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c7532adc1bf08469158391d20427f0cb796053fa37ccd50851fb65451c7d599a", - "index": 8 - }, - "coin": { - "version": 1, - "height": 292216, - "value": 13929, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "c7532adc1bf08469158391d20427f0cb796053fa37ccd50851fb65451c7d599a", - "index": 8 - }, - "script": "473044022008983e89e9e530b7a8e5bb2afeb2f30d25c2583c5e47a5dbb9fe9d9a6effada102205f35fc09874cfe01e9c7c15ba1f65ee56a55a36be594d3ed991f4bcdce5809b001410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c5f9d5f71b526dfc8a7581acf51f2ba4f945dd9c176834e8b73250b2c8ddccbd", - "index": 12 - }, - "coin": { - "version": 1, - "height": 292316, - "value": 5714, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "c5f9d5f71b526dfc8a7581acf51f2ba4f945dd9c176834e8b73250b2c8ddccbd", - "index": 12 - }, - "script": "483045022025fa2656c02b80d47f4e61961b393c4a21d7277b5b1ab2f748e3cef919ffc86c022100b17c816d819fc94844abb203150fe1e556c1c8e1e4266fb70d32bbbe0eb75c4e01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "765e892edae0b77e13ffb1b5a9fe3e0a7502078ff662081280e3bcf479c09c7b", - "index": 16 - }, - "coin": { - "version": 1, - "height": 292572, - "value": 6876, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "765e892edae0b77e13ffb1b5a9fe3e0a7502078ff662081280e3bcf479c09c7b", - "index": 16 - }, - "script": "473044022015748599eb3a2069048cd662efe864c5bb0251bc59a082f0c2d3665796480c4702202942906ed0635e2385cb37f1e995ae2b76f6e2f8884207538d68f37d338f120901410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b7d2018c916df7470a95407c27656354d572663d1e20a0c659cd5370642ecad3", - "index": 24 - }, - "coin": { - "version": 1, - "height": 292635, - "value": 6725, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "b7d2018c916df7470a95407c27656354d572663d1e20a0c659cd5370642ecad3", - "index": 24 - }, - "script": "47304402200a053dac249c7541929967bbc7c2ce52735e3ffd3640ea2f5438ba793cf63971022033ca43ae0df50d88378c87cbbba4f7ae75e839a19336e3daabf1796af333a88101410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a3d15b6cfa2b7d851ea341564992757322fbc0ab2b0ac5adb0e7874032224ece", - "index": 16 - }, - "coin": { - "version": 1, - "height": 292984, - "value": 5866, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "a3d15b6cfa2b7d851ea341564992757322fbc0ab2b0ac5adb0e7874032224ece", - "index": 16 - }, - "script": "493046022100caf797361688ce54db00f0f883c12b68ee0caa19b6c36eede87e63a425a9d95f022100e56eefefede835a025ff483179d48f943e04381766aa6cd4add322aa5fe710c601410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "08c2da2a2930f931e702f06d9170a9d3719f18b48f2946475c1b41421bd922eb", - "index": 20 - }, - "coin": { - "version": 1, - "height": 293133, - "value": 6860, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "08c2da2a2930f931e702f06d9170a9d3719f18b48f2946475c1b41421bd922eb", - "index": 20 - }, - "script": "483045022100d06c557b819221e56961dcd867ac82ca2ce7524085e94e9d32ad8f05ce99853f022075c72973ae998d5d5c1f93ed798046bf1186faf9d1bab926e30a88c36c78844a01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1f6b5913a62f6cede775a74bda3d1e38a2687ae71df56f555d7f73bec426ed5a", - "index": 15 - }, - "coin": { - "version": 1, - "height": 293247, - "value": 37398, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "1f6b5913a62f6cede775a74bda3d1e38a2687ae71df56f555d7f73bec426ed5a", - "index": 15 - }, - "script": "47304402204b982f51deb3fad08fc11d9597dc9c1d5721d26a4760151227945a54b41b6cec022061966667006c8bef5234f1dd00201fd3dc80cdccaeb51c405d7c2d9c02b57e7d01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "01e72c6a1b0db439f1ddc3684e55f14564ada42b9ef7e20c7e3af841e2862c3b", - "index": 12 - }, - "coin": { - "version": 1, - "height": 293757, - "value": 5650, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "01e72c6a1b0db439f1ddc3684e55f14564ada42b9ef7e20c7e3af841e2862c3b", - "index": 12 - }, - "script": "493046022100c0888ba3fd1b8b5901c4dd23ab8e6b71f9678864e838643aaf9a22d207ea5a27022100d44db9711714066e41ad2e660577f74ac9275675ac864ab12d8fdd3910de60f401410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d4ad7072d474c813001c3afacd05c030fadf46a0b77f10bb04c611236cd2672c", - "index": 9 - }, - "coin": { - "version": 1, - "height": 293773, - "value": 7329, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "d4ad7072d474c813001c3afacd05c030fadf46a0b77f10bb04c611236cd2672c", - "index": 9 - }, - "script": "493046022100a5d989d28802727d0c500cda655a103c6044f1b9e654c29478f4e294d6cd8a90022100c58c9d2e589a0a775224fa8e12d3b370b7faf1fd36a918dc7c230ea55d69d16101410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ebcbcd894587fbc8279ef4397b6ee94831f2e475e6f9a9bf16f9853aa5965e14", - "index": 9 - }, - "coin": { - "version": 1, - "height": 294519, - "value": 57166, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "ebcbcd894587fbc8279ef4397b6ee94831f2e475e6f9a9bf16f9853aa5965e14", - "index": 9 - }, - "script": "483045022100c67f3f789a7bd48ffc82e8913a508d32b670a0d4275346add6beb2714e3ae4f6022075d75941295d55580e83368e648510480c0c508ab0c568014119dfaba4e5c9dc01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "20353f9575f60e55af01acd2018fd3f89aa5bb6f91008ae0466c9038495c7739", - "index": 11 - }, - "coin": { - "version": 1, - "height": 294662, - "value": 5671, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "20353f9575f60e55af01acd2018fd3f89aa5bb6f91008ae0466c9038495c7739", - "index": 11 - }, - "script": "4830450220222435c19c29b55820982ada86c202e03f6481cea78af97a5dc42708b1490c51022100b3e0952b5c52f497d587d51b488649fbae5a119426e77cb114e060a4004e7ba101410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d4fe3371197cfd3085cd13d218da76650d6e035ec3a51c221ccd9d764f4e0c9d", - "index": 14 - }, - "coin": { - "version": 1, - "height": 294679, - "value": 101408, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "d4fe3371197cfd3085cd13d218da76650d6e035ec3a51c221ccd9d764f4e0c9d", - "index": 14 - }, - "script": "4830450221009cda8f069362742a1a428f93885914a86260379be7b05cb79d87237463ec374e02207e44a6d9807676409f9f1c0a78d0a2b0f20a4950dfc617e8b7579d4b24f7875301410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "89127ddb215dd80fcc352f6348e9eea92919bcf18796da688458a7753eaad64d", - "index": 22 - }, - "coin": { - "version": 1, - "height": 294789, - "value": 6810, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "89127ddb215dd80fcc352f6348e9eea92919bcf18796da688458a7753eaad64d", - "index": 22 - }, - "script": "4930460221009ac7a20365e0c615377d93d1e815d47537dcc5e533572e91b6723d0381587d16022100b2b8cd64f1dfe49dc028b7a3e902333b04960f93c1d51ff6cb050969bd33eefc01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1db0a30bbaf279d3f281f0f44a65be0246051df724e1dcbb809f649a5db2f5d", - "index": 170 - }, - "coin": { - "version": 1, - "height": 294929, - "value": 10690, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "a1db0a30bbaf279d3f281f0f44a65be0246051df724e1dcbb809f649a5db2f5d", - "index": 170 - }, - "script": "473044022023d88676e91c845033a84517901a496975d5192819c18ba25ff6ef1db734f5eb02206e638cb9d8e00cf35cadd4aa758ed2d2b9e905e360bb12546a1f4f6c65030c9501410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "db4b16e1d81af96825255bec7efdbec710d063ac599142dbac5ff2357148243c", - "index": 19 - }, - "coin": { - "version": 1, - "height": 294961, - "value": 8330, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "db4b16e1d81af96825255bec7efdbec710d063ac599142dbac5ff2357148243c", - "index": 19 - }, - "script": "49304602210089e28d686d11a810b462099b7265783f75800717bbd714e2de1acc763409ed750221009cf2a37e9d83edd255ca84d500bfeda9ffabf39c70c8947d31241beadc28d08501410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4f15d0c9999e758decc927df55f27953ad026fcac60b1c5ffff50ac4072341d4", - "index": 15 - }, - "coin": { - "version": 1, - "height": 294995, - "value": 5860, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "4f15d0c9999e758decc927df55f27953ad026fcac60b1c5ffff50ac4072341d4", - "index": 15 - }, - "script": "483045022100e2aa57fafe6c7fa0379ef436447c4e30b7d8083fc11b7130e5ec1890df38a7bd02200798fc260bad420988ce948b32d6b092414c0278f7b842f416b9049b54c49cc101410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2da092c3446c873f25384b17b0f964575c2346dd94ece9a70b762cc85fa468c5", - "index": 17 - }, - "coin": { - "version": 1, - "height": 295498, - "value": 7848, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "2da092c3446c873f25384b17b0f964575c2346dd94ece9a70b762cc85fa468c5", - "index": 17 - }, - "script": "47304402200440ab0404258aba2b4ba9f9e3ad826e2c72acd6aa8e1ab5d15a382cf25f2bf10220722a75c221cb5578cbf1067df34932b65d2b7b2cb8d66be34004c59e7cbf815801410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8b7d39af80794ea5833995901bc75b12d94da6c7542c117c0f57e6d8dae3d309", - "index": 858 - }, - "coin": { - "version": 1, - "height": 295594, - "value": 7900, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "8b7d39af80794ea5833995901bc75b12d94da6c7542c117c0f57e6d8dae3d309", - "index": 858 - }, - "script": "47304402207d4e01f172bcaff9b99004baeafc75e865a727654f75ebd74cf967510675ae13022040478d6a0a0b39bed0459c81741ade4e7f6e6d95c2f14585fc624043d535984001410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6bc93ad442ba3103382a6375c566a0b58e31236e3c3efdaf88fc428ddc364c4a", - "index": 9 - }, - "coin": { - "version": 1, - "height": 295619, - "value": 6889, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "6bc93ad442ba3103382a6375c566a0b58e31236e3c3efdaf88fc428ddc364c4a", - "index": 9 - }, - "script": "483045022059d4b97b99e3e7f73abd5f29ab11fcc5fc3cd6ec814272ba5acd25d4f176e882022100b2ffd00c03038d0b2755ea36961ca342a1731ca5e109e434d3552048e76628f301410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bbd1fbde3060b43ee4790473bfb6bdff1044c0314edf9618c1e0d1ea9ae9c406", - "index": 9 - }, - "coin": { - "version": 1, - "height": 295636, - "value": 60663, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "bbd1fbde3060b43ee4790473bfb6bdff1044c0314edf9618c1e0d1ea9ae9c406", - "index": 9 - }, - "script": "48304502200e91e98b61bf71fadec78baf26d3ffcc8b925ebc20f8f75dc01959b9997e3d57022100ec595467f3bc8bda71d969564a814ef2392bf3e788421f0761d88063600f4ef101410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "07d259ccc6d7437399b6a0f32a640bb0d70e01167c66d6799331ce092983956e", - "index": 17 - }, - "coin": { - "version": 1, - "height": 295684, - "value": 6680, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "07d259ccc6d7437399b6a0f32a640bb0d70e01167c66d6799331ce092983956e", - "index": 17 - }, - "script": "48304502205a346b68fc6e1dd49d51358b0c0b620829843f768cbdfe77ba5bd7ee017a2981022100fd4b55c1ba431b16ca66e01b8ab816f0ddab103931e99e51d6c19aaa303e817d01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "33c794811df9669b5b8fecca14f60d09520680722eacc708f7ae89da9bfb4699", - "index": 18 - }, - "coin": { - "version": 1, - "height": 295808, - "value": 6050, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "33c794811df9669b5b8fecca14f60d09520680722eacc708f7ae89da9bfb4699", - "index": 18 - }, - "script": "48304502206de9b12c66be1cc163d74897741bf71beed13038f05f5c21804b6b53542284b5022100c4a0ffcefbaeb04f9f066e8ee6534e3ac92c515c7a659bad4f1e135a33eae8cc01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7d558ec8daa244d463cdc974ddedfca4ff70f1b6e50d4c0f0239fe456af85f1b", - "index": 14 - }, - "coin": { - "version": 1, - "height": 296379, - "value": 6840, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "7d558ec8daa244d463cdc974ddedfca4ff70f1b6e50d4c0f0239fe456af85f1b", - "index": 14 - }, - "script": "48304502203e0fc23468a781cecb1ce8f6db4265ce6acdaa77e95e2efd298db9334777519c022100c747fe7dc35c77a8f29b39d455f93afcb3e98180a941cc8b221b1ff6982dc8f901410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "04b311779256d1165249e822924c4fec7262f9a6a4e00068d3f848dcd25d181c", - "index": 15 - }, - "coin": { - "version": 1, - "height": 296390, - "value": 11566, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "04b311779256d1165249e822924c4fec7262f9a6a4e00068d3f848dcd25d181c", - "index": 15 - }, - "script": "47304402204471ccb277ee11fe643ac47024f8e6d63a35f05172c231b3f8e8421fd046707102200b6faec412e632e88981d04f6073b5ef4121e1a02faa3c07b81440c3cf5f6b4601410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d83439c6a25c4450849b3862bdb457049eab1cf6998057d9eace70a4bdb9df3b", - "index": 92 - }, - "coin": { - "version": 1, - "height": 296801, - "value": 6200, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "d83439c6a25c4450849b3862bdb457049eab1cf6998057d9eace70a4bdb9df3b", - "index": 92 - }, - "script": "493046022100f5398ebe120d8b2c60a54062da23c568014b4533bce2cefeeb83907ab034019d022100e5895fbd92ac9a077b2dbff73c68747ac22938d923be068c0394152be7275e1401410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a0ba8426f1e5f04e2723d853cb000f1be8502036dc8f05bd068197b32aff53b9", - "index": 9 - }, - "coin": { - "version": 1, - "height": 296828, - "value": 53064, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "a0ba8426f1e5f04e2723d853cb000f1be8502036dc8f05bd068197b32aff53b9", - "index": 9 - }, - "script": "473044022000882bedde743c7525b8bcd83a120f6bd9bc86aff06838dd268e7d8800914fe602204a79ee3fcb25c5b6c34b6485e4d33c6740966cb3324d0acda0d83cea7a594e1201410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b9cc078c1caecf19046255ad5f9bbbfc4629e455b010487139db9c9e7a5a2c1a", - "index": 21 - }, - "coin": { - "version": 1, - "height": 297365, - "value": 5910, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "b9cc078c1caecf19046255ad5f9bbbfc4629e455b010487139db9c9e7a5a2c1a", - "index": 21 - }, - "script": "483045022065b46a316e4d8196b6d69a30ec2d01d084c9ae2ab0240c83fe6867284539b4320221009b73d587956a0d12320b3de93e5c2963d505ef1fd08e142c1ddad2cb30451dd201410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2f8a9cfa212db9034a0162b391ad72dc5e3f224e112a9afedf689801e6aac948", - "index": 16 - }, - "coin": { - "version": 1, - "height": 297377, - "value": 7428, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "2f8a9cfa212db9034a0162b391ad72dc5e3f224e112a9afedf689801e6aac948", - "index": 16 - }, - "script": "483045022004094448fc5fa3b3e7e228b4ad994fa108ef851c8a29e1bd7c6989b5471589710221008082f511b98826f2b0efb8b53e841f1bc2791a6025a9edcf9ce8886a4f5b48f901410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f8a7ac434fa70311df25bf29d5722d41353141aee0af9e8725dfb90dddaa9368", - "index": 149 - }, - "coin": { - "version": 1, - "height": 297483, - "value": 10779, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "f8a7ac434fa70311df25bf29d5722d41353141aee0af9e8725dfb90dddaa9368", - "index": 149 - }, - "script": "483045022100befe01bba644a3307ff72c66b6143989306620754a2bd4d6f0126cc5d8099d2f0220687e5365336887998f4d48eb94b02402230640c7224451cb1d71106f1819258a01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1e7da75dd32cf7fd9930d924afcc2fca426919627c8a742092eb59b5d06164d5", - "index": 14 - }, - "coin": { - "version": 1, - "height": 297529, - "value": 6695, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "1e7da75dd32cf7fd9930d924afcc2fca426919627c8a742092eb59b5d06164d5", - "index": 14 - }, - "script": "4830450220519d832d4185599d8849e20087b513ccc8d407c089b069ac7a79612ea0df4a740221009af954c04afa4aba3eb955ba38b30f0fe0899cbefc77cceb7c8edfa4e109e94601410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4f2dd80e17e3d33aa475b17483d0a8bffbfda16465d80811a450a4969732578", - "index": 11 - }, - "coin": { - "version": 1, - "height": 297637, - "value": 7499, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "b4f2dd80e17e3d33aa475b17483d0a8bffbfda16465d80811a450a4969732578", - "index": 11 - }, - "script": "483045022100a2d81cf09b64370c8ebc044d45e787ef853f126b1e1e925ffcbd7338c39e733102200bc53a5fa3692c2dc7cb8aff7e26c83cf3d37ba39df97a8e38c4af25ec7be77301410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9873d0244d71b3358a04675e033d3405e48bfcfe7b65166c34f2942b1ca0e41f", - "index": 1234 - }, - "coin": { - "version": 1, - "height": 297959, - "value": 11350, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "9873d0244d71b3358a04675e033d3405e48bfcfe7b65166c34f2942b1ca0e41f", - "index": 1234 - }, - "script": "473044021f0ab98e1e964eca7ce21a903db7fc3c2a032114357d9f1c3a9d7edfce4ae6b402210099d28730ef5842ffc7e911a65f61b5b765dad593d9fb237c6b62598bf36f830a01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b779ae5fe2946f40610352676c2543453a8bac6b076c850768bb3f30c0b4540c", - "index": 8 - }, - "coin": { - "version": 1, - "height": 297985, - "value": 82596, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "b779ae5fe2946f40610352676c2543453a8bac6b076c850768bb3f30c0b4540c", - "index": 8 - }, - "script": "493046022100ef1f017fdde653e4701e2b48f7fc15b8ad2c6f9ac62fd5784229ec23ce626ed2022100893963dca002c807d1f902c549ce6b239a61cfbae6bb385ac457a21eaa86aa3501410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eeeb41677fb28f20099a4ed477ef202572e32598a40e7c8a14f667331a24b15e", - "index": 20 - }, - "coin": { - "version": 1, - "height": 297985, - "value": 11499, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "eeeb41677fb28f20099a4ed477ef202572e32598a40e7c8a14f667331a24b15e", - "index": 20 - }, - "script": "48304502200dc35a0a66a75e061c5407095e66b6115469d5d1e445c144b1c572919aab0c1102210093a3767aab9a04ddb59ab92c709b00871f48b84ee45f7d583507d87a2b9b648801410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "42faa43855498196514d8c79b9808028f6f21bb01700c530284007e48ed68209", - "index": 18 - }, - "coin": { - "version": 1, - "height": 298033, - "value": 7860, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "42faa43855498196514d8c79b9808028f6f21bb01700c530284007e48ed68209", - "index": 18 - }, - "script": "48304502206f8ab3ef1b006053593e12e14aa6818addcd15c74610ee9cfc894f7d25e970fe022100bfc58cc7abe607524ee220c1b25fcf26eb94bcba7a1228102cb2be6778ab20ee01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "de8e07a92328e01df5ba02085ef325741ff5caa927d24869d9bd978e82ce9414", - "index": 15 - }, - "coin": { - "version": 1, - "height": 298152, - "value": 6412, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "de8e07a92328e01df5ba02085ef325741ff5caa927d24869d9bd978e82ce9414", - "index": 15 - }, - "script": "48304502202a926c9fe07a13b690027d0b1b3d4145aaccc2ebce48dd2895937d9ab19ac64e022100f207e67f039a7accb8780c51ec78e30f0c3ac87a8bea37e414756d1b9d68933f01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3d360942f01d811842c9d66cbc27189f11f32f41a1f84ed783720b1fe5d11227", - "index": 17 - }, - "coin": { - "version": 1, - "height": 298183, - "value": 107067, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "3d360942f01d811842c9d66cbc27189f11f32f41a1f84ed783720b1fe5d11227", - "index": 17 - }, - "script": "493046022100bcd2e23546a1d24c9884ed2d85f3afb77f2f2d432888db15ce83e77b15b9b6a0022100fd73bfc2e0d7184d462ad8b634ff41ae157e065d86dc68ac2dcabf05755a7b0601410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dcc0c847e0472e572209569637760722a7fb2fb8e7bf5e9a93857d4f4c639ceb", - "index": 13 - }, - "coin": { - "version": 1, - "height": 298305, - "value": 6080, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "dcc0c847e0472e572209569637760722a7fb2fb8e7bf5e9a93857d4f4c639ceb", - "index": 13 - }, - "script": "483045022100b505cceae6f1094ab6638f221749d6ce28860ba1ad812d860a46f83a4002929c02201b59e7f25a4482951088cb91b6df98e63b2557347730f6d3c84305bef9eadb6d01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6f32077996a9d4a8c08e49e2363032d4ab94485431077ce777644319bbc4ac53", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298655, - "value": 100000, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "6f32077996a9d4a8c08e49e2363032d4ab94485431077ce777644319bbc4ac53", - "index": 0 - }, - "script": "493046022100a79297d48388235e53473f8cc908aabb09f3d750a894a9b2b0e121887603416202210086b86f1a9b40b2322ada9f2496545996aa8b4917b579066e68d9213a7421318e01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "afa2a24a5e8ad470cb723b9944916ac88c7d4052b7abf73f93f6b422f7c8246e", - "index": 16 - }, - "coin": { - "version": 1, - "height": 298783, - "value": 6790, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "afa2a24a5e8ad470cb723b9944916ac88c7d4052b7abf73f93f6b422f7c8246e", - "index": 16 - }, - "script": "473044022044e4ab5784419ded573943909ec80902d7210fe0340155385ac03ec2d72b5c6e02202bbf0c5bfdcba545c35b86570232bf8a5591331326b11400fa9306bcd1fb181c01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "10b819476423749ac6e06491ed7e0f6c8cab79dbd3a0d712275d15f12b82006d", - "index": 13 - }, - "coin": { - "version": 1, - "height": 298813, - "value": 18193, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "10b819476423749ac6e06491ed7e0f6c8cab79dbd3a0d712275d15f12b82006d", - "index": 13 - }, - "script": "4730440220610bcca1163f3e855f252eb1a22250be1ce337c4e9ae241fecf7c75a5d458e680220746a372f0039fecb6dbc6a981a26e2f8a1b9b18a947b8a99b28788ae21c2fc1e01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c7e8ff3f8d102e4e6243dc1db7fd14b008712176ba1d230db6c66d8ced444818", - "index": 119 - }, - "coin": { - "version": 1, - "height": 299049, - "value": 10062, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "c7e8ff3f8d102e4e6243dc1db7fd14b008712176ba1d230db6c66d8ced444818", - "index": 119 - }, - "script": "473044022040ea4dd6412d6337ba803e593847ed1097a0bc9f783f22d1d6477316b0f5241b02203df042470ed376fb3ea33211297704dcaa7b2f503dc73db07dc112311d9e3ed701410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1f2924246fc1bd3ac314df9e7039190539e12819aab109c0a22adf4b9cd3d5f3", - "index": 1631 - }, - "coin": { - "version": 1, - "height": 299054, - "value": 10350, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "1f2924246fc1bd3ac314df9e7039190539e12819aab109c0a22adf4b9cd3d5f3", - "index": 1631 - }, - "script": "47304402203a926070611c9144f71ae4da8cb666fc6307e4e8f7ef3fa1a6517a2efd79cd61022048bc7ef9522d35807a6e54a74d1ac06b2dcf23b503a6475b00224c47e5a85f9b01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "78e4b002837b4e0adc2ab9023fd4ccaa2bcaccbe77ba1ae3e3fce5fd0ba962b0", - "index": 12 - }, - "coin": { - "version": 1, - "height": 299087, - "value": 48156, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "78e4b002837b4e0adc2ab9023fd4ccaa2bcaccbe77ba1ae3e3fce5fd0ba962b0", - "index": 12 - }, - "script": "483045022100f8a1c532a5d7d17207a84e05ba71e0612ba3db155ef90b4d5d44c61d1395ddd3022073aa221dd370ba8a5a2d841cd497f860ebf9120980b237b1b2eb5c7d1bca226d01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fce65501cc18afb66e79ce906fbc9046cd3a09a3ac7ae36bc11430048e146fc9", - "index": 13 - }, - "coin": { - "version": 1, - "height": 299130, - "value": 7041, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "fce65501cc18afb66e79ce906fbc9046cd3a09a3ac7ae36bc11430048e146fc9", - "index": 13 - }, - "script": "4830450220406f52dc83f2d1bfaabc3c8a7995a7904c5e58af8fb16a9331f8dfe24a4e5cf102210081bb6bf95b9f111f3b32ebb570298a2d1c3a51ff8107949b9eb4c6f69dccf24701410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ec6a6f1a194fdeb1b30afcd4a1ebca391418f1ed565866a12bff7ae6a2f1a2f3", - "index": 16 - }, - "coin": { - "version": 1, - "height": 299141, - "value": 10237, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "ec6a6f1a194fdeb1b30afcd4a1ebca391418f1ed565866a12bff7ae6a2f1a2f3", - "index": 16 - }, - "script": "4730440220665158886936d00a874bc5642a331d44c7e77bff856228ac1989443507827c4a02204f604a4d7bddc894c639909a129b4a70de1f3f78a710a163835ecf22ad99e50d01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "14a630790b7334cd433caa7ec869e434cb2f44f088e834ddc2dd211aa6d3158f", - "index": 19 - }, - "coin": { - "version": 1, - "height": 299219, - "value": 7852, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "14a630790b7334cd433caa7ec869e434cb2f44f088e834ddc2dd211aa6d3158f", - "index": 19 - }, - "script": "483045022100f3ab996b9afd3c90e82b68c7ee8b755d4a900d29e46a1ab5e33ac1e9939c8a4d0220105b829de4c265f529d3dc24784fb41a482e228e9f7208d34e740aac00e5bedb01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ee30e777913216bfa33862da6c9cebb99a6ab85e83d19fef2598becdc5d04449", - "index": 15 - }, - "coin": { - "version": 1, - "height": 299254, - "value": 6370, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "ee30e777913216bfa33862da6c9cebb99a6ab85e83d19fef2598becdc5d04449", - "index": 15 - }, - "script": "483045022017003b7265366c9ca3bbef2f4ee7cf994ab3a7f255fac3440cb46ab2502e657c022100a5e491ee20027ace84feb6e8bf2ea89d790f56689be95339b5d7b2c481851a1301410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f74ab3401def47841b6f82b2e7840e3faa64935735b1803de6bf68af2c59c102", - "index": 12 - }, - "coin": { - "version": 1, - "height": 299398, - "value": 9463, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "f74ab3401def47841b6f82b2e7840e3faa64935735b1803de6bf68af2c59c102", - "index": 12 - }, - "script": "473044022019a0925a2792b9cc8972e6466fffb3c1c4b49e9809b968650ae9d283b4bd006402204c39ed14a3026c57b2e67b478d693984e33f0658035a2ed1ac7d3c458bc6e59701410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6c524f67cdcadb0c93a6210bc5ac01cc4498f3d942b6018c45f0617646d7ff86", - "index": 13 - }, - "coin": { - "version": 1, - "height": 299511, - "value": 5671, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "6c524f67cdcadb0c93a6210bc5ac01cc4498f3d942b6018c45f0617646d7ff86", - "index": 13 - }, - "script": "4930460221009e525f3d5faaa70f4babecd05a9a71d7f31e0a70ef4a4667f0db1ec15e307ab8022100a45fb51d24ad4f34e4bb8a08491a1fe70f1a1cc1a598321a494beb4cb424129401410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6c52623522adf2bab496dc7c47210d7a3df441c674a78c14c2cb17259051a3fd", - "index": 19 - }, - "coin": { - "version": 1, - "height": 299559, - "value": 8820, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "6c52623522adf2bab496dc7c47210d7a3df441c674a78c14c2cb17259051a3fd", - "index": 19 - }, - "script": "4930460221008f638ef49261f4c942bed0aaec972e36f564daef1517e2f938b3d68786556c73022100f87ac03d5513e1e5d1f12a6406e92925e188fa76e55d4ec42511a8cfa3adc12401410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d6ef237163bd73f339952a89c59a7a42d242c0be08d5e22c78ff35b40cc7b40e", - "index": 20 - }, - "coin": { - "version": 1, - "height": 299616, - "value": 7491, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "d6ef237163bd73f339952a89c59a7a42d242c0be08d5e22c78ff35b40cc7b40e", - "index": 20 - }, - "script": "483045022100814ad27fa188025c6bac910e0cd42f2459c6f7223d614c804be79d3c80a4ac4a0220690b4025a62ee886cb029d28c479f1f6c29ebf3bc22bbcd017ce03c3cfbc9e2201410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2a42773f46a7bf6da91414090f4f6bf0e4f837bb199c7c67ccbac207d4f5ed8c", - "index": 16 - }, - "coin": { - "version": 1, - "height": 299768, - "value": 6660, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "2a42773f46a7bf6da91414090f4f6bf0e4f837bb199c7c67ccbac207d4f5ed8c", - "index": 16 - }, - "script": "473044022063cb0264db4041c8870cf6558e86ef080611e678e1e5fb873a85f1af4cb6018a022022134c5e475d07a839ebd9e8e8fafda80e71a6309f6eddb7e5381a83d0a3e21001410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ace9fd72e9270492f0d91dc7dca83d806b95947f025f1f2620cd2748a98e02b", - "index": 20 - }, - "coin": { - "version": 1, - "height": 299780, - "value": 8904, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "4ace9fd72e9270492f0d91dc7dca83d806b95947f025f1f2620cd2748a98e02b", - "index": 20 - }, - "script": "483045022100ae2ee2acb915211dd2ecca92220c4e04457adeabb2161e2fead80ce34ed7a06b02202ba4f68c7614a7ca7aa92ab7a3ddc25bbfe5a4d7af1e86b28d6354b8502dd3ed01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "17e24b2aacc568ebc167e3bd8a03d0263e5d158e833968606bdf68bc71c85663", - "index": 15 - }, - "coin": { - "version": 1, - "height": 299878, - "value": 105464, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac", - "coinbase": false, - "hash": "17e24b2aacc568ebc167e3bd8a03d0263e5d158e833968606bdf68bc71c85663", - "index": 15 - }, - "script": "493046022100c8d1d175749a8728c8cc0f0118a308b67231d466f831026ecc5228e68e81a7e4022100d051ff269757627a7e23134203608d16bdd284939bdff024d3d18b535208c9ee01410418bc18922af607462bced2b58dc2e2905444a7f0695c29f8de5abb5d3140858e6293e6dd7afce000678f63c2ef51e3828350246b4dea1d2353bb9026c197d961", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1000000, - "script": "76a91490b9ab91dec16f1e609378a8ddf4c0ba2a7c6dd788ac" - }, - { - "value": 366, - "script": "76a914d39910c26b3d55ba72cfe928fc9b4f4edec4a11388ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "0679a554a45213e3a57f0c6af98c781f11c6943221be5909a7c5c158307a1e49", - "witnessHash": "0679a554a45213e3a57f0c6af98c781f11c6943221be5909a7c5c158307a1e49", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 440, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "6f9511cbec63e6fe8bf0877572d0230c809d03fbff74f1038c7c7494c25d1776", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 400000, - "script": "76a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac", - "coinbase": false, - "hash": "6f9511cbec63e6fe8bf0877572d0230c809d03fbff74f1038c7c7494c25d1776", - "index": 0 - }, - "script": "483045022100fbfb89605b8c1ef17f446e37003172ff4bc1d2f864c0fdda8807b2719a4eae6602200e066fe171839171d612cf56182a1349ab48662f05927f412e46a079f027c120014104ccc493c773ed7b190fd3fec0fde94df66605923b5ba6781968921e3f7c86060f62799e085a6873cc5dc1592e99a9090951cad28102cb920da361944d1a827916", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "046e04c9f1c9fd45581cca2d3c4e508e634e79dec24ef04045befc2bcb1eec2e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "046e04c9f1c9fd45581cca2d3c4e508e634e79dec24ef04045befc2bcb1eec2e", - "index": 0 - }, - "script": "483045022100fdbbcf04703315713dd10d28023525077e50df3db7be027184c5d618599634060220280f08cd4347470c5f5662c2075c2b61384d8cd543d0c68f3e04a33f050098310121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0fad5a15d5a1db7eb028d0772f7bf48eaeaa51664354fe576eec0f2f59ad604e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "0fad5a15d5a1db7eb028d0772f7bf48eaeaa51664354fe576eec0f2f59ad604e", - "index": 1 - }, - "script": "47304402200df63c9fc6cd54cf060fa51cf81bdc4dc705d0282c14b502ce1952ac74d66cdf02200dd1c6ac07136b579fe3e444e74df92143b30b8e81cfb79316e9f8446aed81980121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "38b33ba4fdda75c73edcb208569271d5f6e6293f4e8cd7e6e42f0b410c49d405", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "38b33ba4fdda75c73edcb208569271d5f6e6293f4e8cd7e6e42f0b410c49d405", - "index": 1 - }, - "script": "47304402204f29fa8b075284ba1f8f6709d233d553dda8ba475b768e7f2184d93cf3b2ea7b02206ebc9407398aadd430c0c4b0ab37d259acd4824a45599a0b4e3c9d583f3d09a40121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "678708145e5623b3fa9fdca67dcdf51899a0de15193d23a2b6632bc4f51f3981", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299991, - "value": 50000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac", - "coinbase": false, - "hash": "678708145e5623b3fa9fdca67dcdf51899a0de15193d23a2b6632bc4f51f3981", - "index": 0 - }, - "script": "47304402201ff07d61a467dea644dc9b05ea1ca9bf3e70d3d517e18a0dbf8147a53c57bae602202933c1d829ac09208dc0e2e3a7f240abbb9cbaad14e314b85207082446257e560121028d15246e451c1b64b013ad3e83b10cca9805aa0f1aec81149b2e02d71b77bf4b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 550000, - "script": "76a9146e24f8d88925eeb0457df7cfb968118cc31e1c2788ac" - }, - { - "value": 40000, - "script": "76a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "3785b50533231fd9740088551a86b6b8aa4c8351a0e6eb5225fea9324c18075d", - "witnessHash": "3785b50533231fd9740088551a86b6b8aa4c8351a0e6eb5225fea9324c18075d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 441, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "98f426b4c68b6342d62141f8ceab608aefce48ae5cf8c200e32c998dc26cb3f8", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297088, - "value": 463497441, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "98f426b4c68b6342d62141f8ceab608aefce48ae5cf8c200e32c998dc26cb3f8", - "index": 1 - }, - "script": "473044022005e683086e7f53c1f15c8a4fb75b80ae69334533989367df77ada851f2cce98f0220070c5ae8e2770e8a0de035b6bd21747060d29863b68a21714f0d1cb7cc48dda5014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4ac6ecd6a4d988731b303e3e491de5f5c48ca1288a428b601492940524f76537", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297119, - "value": 480466710, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "4ac6ecd6a4d988731b303e3e491de5f5c48ca1288a428b601492940524f76537", - "index": 0 - }, - "script": "4930460221009f8a921c18dc00f3b71f87780e32b62ea8ca03000e71422395ceaa172574ca54022100977f77747b106c00b99cb8fdd2483a4e0af7a08c9078c8d962569eddd63acc9c014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "106a67fdc64fdca183905fa0af4cc97033309289fbe7ef8c67e4611adbd6e996", - "index": 4 - }, - "coin": { - "version": 1, - "height": 297143, - "value": 253123190, - "script": "76a914c408a189519929f46bc5d9c2d613e3e1daa8e13588ac", - "coinbase": false, - "hash": "106a67fdc64fdca183905fa0af4cc97033309289fbe7ef8c67e4611adbd6e996", - "index": 4 - }, - "script": "483045022100830b999f57f64d13373c0be66c3370c6c206d5079159a4060e1b55e6c719badb0220754457665588c208d91f7ca21ff45edbef6c5be3f61ddfa3f4cf56618c3a80010141048906101d3a76ae33b24064e6d5b7fc9fb8c4c8c0fc412598b2b5873950de62a4d747295ac7a927a653ef2144c7ab14368e7affe7938d23272d8e5994f402caf0", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f205105c650b4c08922977d29235d09bd1b7e16781c9fa161ac847d4549f665f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297408, - "value": 132740389, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "f205105c650b4c08922977d29235d09bd1b7e16781c9fa161ac847d4549f665f", - "index": 1 - }, - "script": "493046022100e337eae07f6386d9e638e4306c6da14ffb324b763ec062465f0871e6646d04f8022100b1416f092d633e9b0d2b2d6f1ac01d91ee6aca2e217ad1f6a351ba7ec616c8ed014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0ec707a6cb42853b6ec2cbfb267494ce7d69aa24a6f32416b010efe2c3832b50", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297514, - "value": 79315697, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "0ec707a6cb42853b6ec2cbfb267494ce7d69aa24a6f32416b010efe2c3832b50", - "index": 1 - }, - "script": "4730440220135f5e868d7ffe74a3c83a99054266f1044ed6f101d357554c90ac0c506a0dff0220635fff8688f2e09d6a54fe3f17f80cc5c2a3d7ca559114b1202b9df09afb51fb014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5fbe0f05d61bc0050b5b11a06d04a9483e016619b46a051bd202a00914d9c2e9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297536, - "value": 84524184, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "5fbe0f05d61bc0050b5b11a06d04a9483e016619b46a051bd202a00914d9c2e9", - "index": 0 - }, - "script": "483045022100d3351d0311b6b5843e775d20311cae62aaf19b1e30969c3cc350d7949f1569e30220145283275958ff5a028ca26ec5c655f75617730650b80847b5f1faee3cbdc0d9014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "af322799adaf76d6c13fe32a33fee923ea6fa89f225661bafd57366d968df235", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297561, - "value": 227374223, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "af322799adaf76d6c13fe32a33fee923ea6fa89f225661bafd57366d968df235", - "index": 0 - }, - "script": "483045022100cd9b4c62a4f5cd6025c4afa9e37b6cb143b28066b403e6483f801a8b4528a0d602206546b1f071d07ac1aa52a3a46e74517fbc3f69c04c08ca2a66a0b409de79eeb1014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "500850a5d45e93d9adb1efa6401f9a23b2188c1c8d525d080e044faf9dff33f0", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297621, - "value": 2000000000, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "500850a5d45e93d9adb1efa6401f9a23b2188c1c8d525d080e044faf9dff33f0", - "index": 0 - }, - "script": "48304502207feacfc1fb3e631bdee404accaadf5c004303a553342d2eaf341416395a99cad022100a9e2008556d4291c4af88a629e03d18a74d441f71d9add70d72c967f59cd8a35014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "98435be4a87e081c52633a41f76c2536b8a9f649706def11f97ff69543a820eb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297621, - "value": 1988291, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "98435be4a87e081c52633a41f76c2536b8a9f649706def11f97ff69543a820eb", - "index": 0 - }, - "script": "493046022100867f8c6786a111db8432f1c0c3e552da30422f6cb8eb21e625f4d3aabb1c4d90022100b139d80ebb0cc4875f43165bc1ada97248ae33ffe712bdcd260d15ef71af016d014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8ca8da04b6c67206ff328d7c0656a5ace682d1a29f787426f811f2dafcebb2c1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297702, - "value": 113527647, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "8ca8da04b6c67206ff328d7c0656a5ace682d1a29f787426f811f2dafcebb2c1", - "index": 1 - }, - "script": "493046022100e17942e70ee5ceb7e44d44399b4c2bc4c034dd98f03859644ede786fb53813d1022100801eeb0042a0461fdcadda094bae85448054c54781aa0b3574d28a40b29b9ca6014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6c4f61eb0d1da6dcdb9b6f34416e168948f005ccb80b7f0317c1852dc9a0485d", - "index": 3 - }, - "coin": { - "version": 1, - "height": 297904, - "value": 1223862610, - "script": "76a914fe83b18c951ca18d29e8c1cf1d15c8a24efc5a0c88ac", - "coinbase": false, - "hash": "6c4f61eb0d1da6dcdb9b6f34416e168948f005ccb80b7f0317c1852dc9a0485d", - "index": 3 - }, - "script": "493046022100924edde7979cfb7f6446ed27f14f660cd6eecda965da5e842312ef216a68ebe902210084652dce0048e0b2053dec0b96f8ede2eba093d82ae608e6de46660e1e46866501410415a474768b6f7fd59860f36234c7d951c8d3c966c1d7ae7e5e887cdc21cf46b7197e2282ed0261649853022e9486a4675a4bc2704858b74defeeb2cf7c1edc2c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3b97dc259f40d36fe135790e4d1a606d08ef6da76713a17093a605d812b4bdf1", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297907, - "value": 144747339, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "3b97dc259f40d36fe135790e4d1a606d08ef6da76713a17093a605d812b4bdf1", - "index": 1 - }, - "script": "48304502205e640b4d16890b8c77e1f5fdbd243670375185181d39174e1e70b31026e0d136022100e7630baed230f08e3ffe203c1d7a79abdc4e8a9d7d529a5ede40e13e9810ac9b014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "127b35543f0dd0ef24c967a2743724058bf82e7f50bf639f47c38f5385aee129", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298196, - "value": 567550428, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "127b35543f0dd0ef24c967a2743724058bf82e7f50bf639f47c38f5385aee129", - "index": 0 - }, - "script": "48304502204efbd81dd361538e98ea0495c2dca3b06377546dca7b323f36d73a8bcebe801202210085a658496d97baea2899af712fee9003f9f4f621a7fbd340d4ed894f43e3bf3a014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "192174ebe6cb74f8a00a03085c12a900f7d01f3f0cf0e936dad602f11724889e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298221, - "value": 206599189, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "192174ebe6cb74f8a00a03085c12a900f7d01f3f0cf0e936dad602f11724889e", - "index": 0 - }, - "script": "473044022052ebc675524ab5b059c9992532e44a38361596dda763d5a61beefbd930dc234202207f780f134e8b006bbe159c6acd81d7c90810cc8430b40d4c6f17c190a31a0a96014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a9f4fcc0d00e9c3a46d188f58e540c9ff3f6e5a3cc87e08a30ba93e0170ac362", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298432, - "value": 180866209, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "a9f4fcc0d00e9c3a46d188f58e540c9ff3f6e5a3cc87e08a30ba93e0170ac362", - "index": 1 - }, - "script": "47304402200e63c9a6f03dc753a65210aac47dfb224997d43dddc840fa6f715a5771832bfc02205ce72beb769fa3710a2c3eadcb9750ae89d0a5446f312f290bd367a3eed53f1d014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "62dbc4bcd3f6ee7f9696db298b2c3f8bd9f9358942d1c71d5f291a714c0e6348", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298550, - "value": 440871448, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "62dbc4bcd3f6ee7f9696db298b2c3f8bd9f9358942d1c71d5f291a714c0e6348", - "index": 1 - }, - "script": "4730440220786d770042c4058f15f00e6b7fa5077a09d6ffc507a183ea607db8b23265093b02200a8f1b08806095d4acb164477bdcebb2ae48cc2df99c3f02e5a7dda5bd7cce6a014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "344bfcb2ab34ba234574ba3c7d91c25e5e5fb1e29d4644b9dac96283cdf4930e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298713, - "value": 133612566, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "344bfcb2ab34ba234574ba3c7d91c25e5e5fb1e29d4644b9dac96283cdf4930e", - "index": 1 - }, - "script": "4730440220612aef10eb09988e8113cede7c67ca7b203f0129d02fa0c4d273e5690b022d010220786b87b480dac4670342ddd59ba72db9bdc58fcbc33d40873510169a41ccf919014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d13527eb7608f5056a6fb4a8312cb67f6588bf915b9a6dc58677a72f65384249", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298868, - "value": 382238619, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "d13527eb7608f5056a6fb4a8312cb67f6588bf915b9a6dc58677a72f65384249", - "index": 0 - }, - "script": "483045022046cbe0a6afb189e09264be9a16d3a3fc4df53e74ace325264b886a2da3877c5d022100aadd516bdc3e03e87fa42b37145f2ea5bced139248db11286f96a708a06b444c014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7c9c217440c05110cd8c403e7483b6c163869a50c8daabc27390452e09f69f8e", - "index": 7 - }, - "coin": { - "version": 1, - "height": 299114, - "value": 282187022, - "script": "76a91400ab32bb73b0aaeb7bf62d626333d977dc4d1e3e88ac", - "coinbase": false, - "hash": "7c9c217440c05110cd8c403e7483b6c163869a50c8daabc27390452e09f69f8e", - "index": 7 - }, - "script": "483045022021ec1e9f50d7adb599bbe3b71194635da18f5c48fe4f0fb2418f6cc935cf403d0221009c3726fbcfc7578a934c8d3e5e3dad358c0e8a9ecc109552f83de3143a5f76b70141047ca850cf141d31ae4d80ef85cf8a33d013c806e22d494c56901fda54db057c44210937a620fa6cbbedd8659ab097c8a08e49248d0f418c67d6dd615903fa90be", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9bc39ff51932917e6e8350eebd60cb960a41731c4c90778291935a1e4097869f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299198, - "value": 133539814, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "9bc39ff51932917e6e8350eebd60cb960a41731c4c90778291935a1e4097869f", - "index": 1 - }, - "script": "483045022033fdce892a0b0910dff678cc30f45e85dee0d885d8a876fbf1ab7dba0cd56536022100aab2e045f69100ec0f3632ca7f8058637c31235dbe566912d58cfb6455b0b029014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6d7137491a45f02fc0e08355dc61605cbfaf46eb9b11c18b17db3f6fafaf2ad2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299459, - "value": 93790747, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "6d7137491a45f02fc0e08355dc61605cbfaf46eb9b11c18b17db3f6fafaf2ad2", - "index": 0 - }, - "script": "483045022100e5a2cd807096958805c917bb1783c2e10761e5aa46f807806af16fd52a895051022044175e6008bd1643c51ae69f979562a44cf6c28987e12d4a3c3a7c16465540ca014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1c5f3801000f4432a4d3f9bfa8a833faa8ecda5369088f0ad1c3cddec478e1b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299675, - "value": 178811909, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "a1c5f3801000f4432a4d3f9bfa8a833faa8ecda5369088f0ad1c3cddec478e1b", - "index": 1 - }, - "script": "493046022100a339f09def2eea5056fabfd11d146a39fd13a54e9247cf8fdf4f97622032cbdb022100ef16c4f383e0c8e72c7ff7369e9ece9a570d21e77ba4cea44da0289615f2629e014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7c6669598d2af96007b177adf2ed7133bea496eacf784a8750906dd485823a2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299759, - "value": 129951085, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "e7c6669598d2af96007b177adf2ed7133bea496eacf784a8750906dd485823a2", - "index": 0 - }, - "script": "48304502204a0aa430845261f512db34b70b7ffc25ad864b2b86d6dfac742a88f5ce95d581022100a99d16d0fe9457d64b643403ab6e0fda26364e4e8a5267ae7ec47a1953fee927014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e1ecb5f74c69877da47b1c599b25d96189b17e9c8eb8c21319086e6379fa544b", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299801, - "value": 112698103, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac", - "coinbase": false, - "hash": "e1ecb5f74c69877da47b1c599b25d96189b17e9c8eb8c21319086e6379fa544b", - "index": 0 - }, - "script": "4730440220111d6f96eabd7c424f63fcf34ba242ec278478c1602f3ce97af41ac6ffe2184e02206126a1bca5ebe4d75bc25158d719a2e220d214582d7e1829fd717c04c5577554014104baf317c6487dee87d0177633ae6e47dba9125906daa24af18882ed61d7dd929ee7a6a8ec873715a7de5595feb029ac3b06d319904ac884dcf05f22a86124437a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8000000000, - "script": "76a914fe2f60172dcc99dca17952be8f15d1bfed8df45488ac" - }, - { - "value": 47834860, - "script": "76a914ec9eff26684bded7a63cb910fdff6eed0cc1856288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "5469193cb638b67cd9702be924157ad669ac3e60a68fa65b033850919637e20f", - "witnessHash": "5469193cb638b67cd9702be924157ad669ac3e60a68fa65b033850919637e20f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 442, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "19c5eba84f2c1f0e4c5443fb30343817e7ec7bbef2a77fbc186ed2eab48ec124", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 1952633, - "script": "76a91449e319d40023bc23319a7ca433cd1f9b070e88d488ac", - "coinbase": false, - "hash": "19c5eba84f2c1f0e4c5443fb30343817e7ec7bbef2a77fbc186ed2eab48ec124", - "index": 0 - }, - "script": "483045022100cab011bdbf911f34a13bbd969481efa4a9e6ba33786eb65cb31379f904a441e002203980cf1f2619ff37fb683a76a2b572ce2e55b4d515780b1a50fd83f1c9442c43012103e31343e20c0e6a21a0a6d19b6808b11fde445af45822573e2d08f03e265bf1d1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "94a5241c4eeda717a58d557e456697419cfa77fed8cb9e507452d9229bfaab05", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 16141000, - "script": "76a914d4cb9399a4ccda525b78e2737809d4c107dfacd588ac", - "coinbase": false, - "hash": "94a5241c4eeda717a58d557e456697419cfa77fed8cb9e507452d9229bfaab05", - "index": 2 - }, - "script": "47304402202ba7636e0baf6085ab1bd82dd5bd78d8a9d06fe2c737391d09c5a242dd69294c022052102c1e0281d2baaddd3b82f267ad2b0138445ef223f2539785f91d7ac79b7f0121033bc82fcc24aa427c86dbcd6ce86753c918cb198ad9c140457e62d7f0855a3ad3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "49f5bad9af06bf2ecf6e27a9377576e38e6698d32af50c0540f14cb5e5f7220d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1399413, - "script": "76a914953c3a706df9cf0e3da14f161ca1e62be04f14d788ac", - "coinbase": false, - "hash": "49f5bad9af06bf2ecf6e27a9377576e38e6698d32af50c0540f14cb5e5f7220d", - "index": 1 - }, - "script": "47304402200de6cb3c1b4f4137de53f39422ec95927283807a5b64174bfffc4df9ae68a3bc02200fb98a84fc0cabe176cef4bfa7a52cbd20dc837c062cdeb90c04c60409d21257012103e2bf9ccf0e8dae6d92892ae2db08dc90f054fa94b72ffa1751e3b739e1610f53", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5aa0aeee8b0951a1712eefcc77cdbbd8db32fb9a057840f830af8e9da698400e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 306185, - "script": "76a914d52da0931bd2b3ecfbf60d49e68ee57bfa9a6f6888ac", - "coinbase": false, - "hash": "5aa0aeee8b0951a1712eefcc77cdbbd8db32fb9a057840f830af8e9da698400e", - "index": 0 - }, - "script": "47304402204fc6a9ba5dd12b0f7018f4c625d8b352592e5a6f5246853e2361a86b0dc7ff1002207f4caf5eb8c5cf2d9b063408d560032c7580fa03c1761f6ef6a7ae07befbb521012103f5e7ce1fc1d15991be0e78865de160dd6e4e2025e532bfa765923c7adb8a817a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cd9a44239739fa547a3c766aa92957451d1b68ba8f425486cd7e9c1207a0da18", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 15700000, - "script": "76a9140fb122964e215e057a644cadfe09843de43ba43a88ac", - "coinbase": false, - "hash": "cd9a44239739fa547a3c766aa92957451d1b68ba8f425486cd7e9c1207a0da18", - "index": 1 - }, - "script": "4730440220659598854bf50fdfde8e84dfd26da703e4134ebbc9820275bd7c81bac3ed358b02206a12ae1c0797c0b01e09f20bb81dd782dfba2dd5b38a8f4c6baa8bfdfd6f207c012102129c71374181619aa50989ec0795e04fe5e10ea75997dac099a6e758bd0c2045", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1233231, - "script": "76a9148e858fa524ab281dfcd08566217b8146101c534f88ac" - }, - { - "value": 30356000, - "script": "76a914d7294f993c327ccc7d308eddf212f777c84bc37388ac" - }, - { - "value": 400000, - "script": "76a914fbe6e9e96ef861f3f93c34848a4cb554c749310488ac" - }, - { - "value": 3500000, - "script": "76a914bf39bd8813c2c7c61ecc5ccd2dea11be552d880b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "witnessHash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 443, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11066481, - "script": "76a9143b1a2b8ceb576afe043a83c297b8aad873e69a6388ac", - "coinbase": false, - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 17 - }, - "script": "493046022100931f7e872c578a4b2a46a1d0ccd4e613892600cd8ac45260441871f327c3c9c2022100d21c95ec927bbfb1807db6f3a84fcf9c34b0fca96ad8eaa55ea63b52b39c7d7a012102f9c772e02ce3f025e7d9822d9e52b7558a1b286ee61ba69e575d307acdebd21a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 42154000, - "script": "76a9142e31b05444c40204279469c336b5fb9a4d2c5aff88ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 11 - }, - "script": "493046022100ca3dceb2cd4cf307f5b32633d383d7981a14ef140f32cb02c548293f710654d7022100ef9ef7a184c912f6367439c3a2c41bc5f04b5839918a6df885946351e7a7d02001410497a0cc9a79e2936acde45c42b046a70745e1b10b510d5cdb5f088be37f4e22cae3ee15567b65f12fa6c893bc2bf9d13305b5800307ec64e5789d53e2af3abf40", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11045589, - "script": "76a91483e2338bc9021bdfa6b17d3d426db3df897c78f988ac", - "coinbase": false, - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 9 - }, - "script": "48304502204aedff19a2e6151131b76993fdfe66ec1d490c197e7ad58fbf80de5f010c9193022100fa4e370854dbe8283b91ff639cae81b39c850651d205a8734ecb4be870301af60121035f716bdd6cce94526ccd86eaf8821ab3e6a6b856c06b056cd4e0e85a7f3ac150", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4137232, - "script": "76a91457b5ce3ee016834cb3d12de6241383d6be1ea53488ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 2 - }, - "script": "4830450221009ccbb0441ea1f45c02b8210468f90926f6e5b2467c6210f54aea1cb929b3c3fb0220461eff837596c5821a97a007428c553480b363ad6b99c95fcad8d5edbced14e40141044124b020350b947d32a8b4fc9d075078f5f79da8223ef051b31dd5925179b736768a0e8f098bcbda554f5f0d9ed40f4b77363f0fd4c78459f4267ae836277fcd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11138925, - "script": "76a914e7dc89fa8f91c31ee4e6e3137367a76395268c8588ac", - "coinbase": false, - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 12 - }, - "script": "4730440220217b8db5f1da58657ddb3964cde70cdfbafd00c1b55ca5418778061515cb735702204f551e3e0bada339de78885aebc822875571f0561ef638416ecc9941f22f8a5f012103fe4240944ade9611163465d2b099e55f16dca23b731cce4352bd57037627c080", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 4590000, - "script": "76a914a03a8006661021677f9380110e41dec2e147b48588ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 8 - }, - "script": "4730440220081e5c5e4c224d0f7557c3dbfcded633ed32b6b5562d27f291a652d7cbdf047f022075bbe36e49206c5a5f2e28903d1fadbb8389fb1940f3c4f686285fe63cb36891014104874a6e75eb9c7ffd81238f8b4cfa097398c37f597cd8f593614a83296662163a9ab5a9eb88fc9eee57c014d7c78319753cbd36c93c414a6193eee1c9bfce6a1e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11087501, - "script": "76a914eda8a507f022ac4f1927f9c0b7d1f41324358cc188ac", - "coinbase": false, - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 15 - }, - "script": "483045022100e5d6a284ecd217f6402b4f1fdac0a6373cc77191e9625ab19ec575e5c87baad702203cdd600cb86a0f0bfb9faccd0d7d10a45c7f53f6dde41b30b1eeffe6a9e492660141046d31736ad711edc5aaf096144e283ca95e6e7c941c183fbdf109e4f6f4e6aaae4dff4ea9d072e2e6bc92f9ffad95da6f72f6b14289825520bc54e241accc4020", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 13594753, - "script": "76a9143a8bf4a40d03f3f9399d9ec413f189e66ad6a72b88ac", - "coinbase": false, - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 14 - }, - "script": "493046022100fade7562fb0a27700ad4d6e355ffb319aa5a67b3711833043f4abf23cb551cc5022100e68c0db0b94e01c42c8dbffb47b2cae9e69b8ce282f678a53862d9c6138b6a80014104c4b5ddaa591e76265bfb573269ce161db8c7e874e3fe54ac822c3058c35f275b489e6766093d4dbd26337697ffbc3c5965dd8113c0eeef0f0d2059430243039f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10961504, - "script": "76a914302ebe66f0bbb66855163dfcff6b1020cb43f67488ac", - "coinbase": false, - "hash": "889b49c8d4f45b5c623e9d6e617fd7b40a0e81805f644f1faf8b15a5b1424f9d", - "index": 10 - }, - "script": "4830450221009659784322797bbab9d42e06c12f44adb9c0d28b3bb1a100135cd0c3bab8f0ce022004be36d04698aa53ee267d6bc87fcd049c6a18a024533cd58f8c9b4ed004b6c90141049542be4dbd34b6b456bd34f27c900184293eee82dc98ad328b0e43f14a6c40532140a93972aff97a1ad13698314dac8b84b60b41a82528c6846b0bc98f8113f2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 13096840, - "script": "76a914dd73cc468f0801b3ce2fdbbb6f3b21ac1791c22f88ac", - "coinbase": false, - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 6 - }, - "script": "48304502205506d9d894f2ca2268477270fd822e337d7b158f920f94db48ac2e4cab8f34ab022100c4ac12657f93dd4ae07b3741f7bb443365fbf1baed40587cc58a4972ec086e9701410434972926229a3c80761979cd698529e3a52dcd78aedc53ec297d50f03a0eff063923b5e5d9bed5a80b34f71800cfc0447e6106a6aa4cdb551a9eb4cee1267a77", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4940000, - "script": "76a914352e65b9f2283b81121197fcc9c815279cebd54d88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 8 - }, - "script": "483045022100ded996ad710189d239581bb4b665c350bbba9c82a80d6ea43cbff8d9a065cce70220172e41cc3ade205c6cad89321962a2459a41f7c2b82db4726641e3e84172b4d801410456ecc7e89049e2394f1cf8eead146850bcf1d5ae3b4407d62e0bc3dd2bdc0bab1b762a674ee93d77bf1a17e5b623d2d5ba42016a4e46823b806aeb0c2b8c2c94", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 41661600, - "script": "76a9141d638c2449e194915683de830a42abcb4f08b9b088ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 2 - }, - "script": "473044022079eefab17d29ad56c3c79abda20b575f42a46401c799a194c9a21e94c33ce04e02201c93ed8780e0bd6e7bc13ee20803ba191fabe0ea99edd546cd622d8841344d750141041173757c715915636fb05f8d71083f6acae0d8436fc907313e4fc6440279063e82923d84b0d1227f076876e44a381108138021c7cc28da4fac777d280654a3c8", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11742000, - "script": "76a9142528e993f3a316f8778b616963ee9126a788834e88ac" - }, - { - "value": 11247910, - "script": "76a9140fcaf50be55c2c1c390ea5221434bdab127a2c0b88ac" - }, - { - "value": 11370000, - "script": "76a914eb91f720db4310ce927b44364bcf12f58de63a5988ac" - }, - { - "value": 11107167, - "script": "76a914335b8214f721a8aaa4c47515dfc833ba437986a088ac" - }, - { - "value": 11048000, - "script": "76a9146b7dd0802ed28d5468326dbbfff7f5c139073aa488ac" - }, - { - "value": 10360000, - "script": "76a9141fdbcd20a42abcaa788810d7126a92a14b1095a188ac" - }, - { - "value": 10323590, - "script": "76a91453713c196f325d0254813bdd56be57962ba11bd888ac" - }, - { - "value": 2186495, - "script": "76a914c01a9108e2aa45d2e3e2f28559a7cb62aaf3e91788ac" - }, - { - "value": 11501430, - "script": "76a9142c9b234bc44b6d4d8e6404fad46d2ea2a02bb0a688ac" - }, - { - "value": 10996051, - "script": "76a9149adfc78a4fca4549d8080bf54a98d874a161fb2488ac" - }, - { - "value": 11262000, - "script": "76a9144e926e2c60311b7babad34cb36cfa57aedf8835e88ac" - }, - { - "value": 11912836, - "script": "76a914543283e0b5fb2fa1779d82a64ced6200cbf8f65888ac" - }, - { - "value": 10649954, - "script": "76a914d2e17bd37919ed7a035ce27f987aab49ee750d0f88ac" - }, - { - "value": 11450000, - "script": "76a91477e19fd03a84753b781a444078bae53ef628cfce88ac" - }, - { - "value": 10583992, - "script": "76a914695e9c53d55152e7ff9253b3de6cac6398ba4f9888ac" - }, - { - "value": 10320000, - "script": "76a9147ebcc8a5e225c70931307e0e3fb4db3aa78868f688ac" - }, - { - "value": 11383000, - "script": "76a9143b58574b10dde8f5f66d5a9ace91616528c0c5ca88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "witnessHash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 444, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4984000, - "script": "76a914c748ea665d09abc0458ccda4f3dc4e88c24e8c5788ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 14 - }, - "script": "483045022100b7199a4788423250bc9d3f5a34e78f31abce38512e9ec9b27ab0ea23ebee26e802206da7ef1783213129750d50f5320f525d8302ce99f7fe99e765b1d4cc7aaed7c8014104182b11b84a02f26825c25b75e1a742fa1d532cd0d3531ff5dec88f135c36afd0508581e5ee1fd124394718740ac0bb5dc5b00a7a2d5c943ce31ab680ba8ec74a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 13907595, - "script": "76a914fc8f77547ba041fc81f6f4bf33748efd4745e0f388ac", - "coinbase": false, - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 0 - }, - "script": "493046022100872908aba07db2de96ac233333616dc2d763c2f8196f9e29c767a4775ffb9a3a02210081b4daece7dbe15da53722c48b2b68c1b61fa43f04ae003e0b729052a64b56b001210235af079cd997dabdfc1cf9ed9570b9fa99be3bb77d4b99e20926c8ce6d914e4b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f16b182df687ef2959714c4abcf3224db293aac8cf107bc7cd9a0c5e31a75974", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 13640086, - "script": "76a9148cb793e4ea2a2f1d19fb1b21f9e8982093abf33188ac", - "coinbase": false, - "hash": "f16b182df687ef2959714c4abcf3224db293aac8cf107bc7cd9a0c5e31a75974", - "index": 11 - }, - "script": "483045022100f111867944479defee8f7c50103ba21a4c03a40540629134f81eef4938ac28d302207785d67e063bbd9092ce9460ee5453896c76a6cc9e1fcee11cb404efbbf2fc87012103f4101662dfd294a711ee73f3f62e3d3f5a1eaeabee48680f975fa4652a87760d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11107167, - "script": "76a914335b8214f721a8aaa4c47515dfc833ba437986a088ac", - "coinbase": false, - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 3 - }, - "script": "4730440220284f0133c109b0700aace33665c252eb2823802140b2aa953484d5cbb7278d66022051e7ebe0162a80636b58ee8b80aaed596065817cea346c40648428f2f0e1ab6e01410401d76eedf174a47e79ffc58c359a622b18413a46307fb0dabed549ee78a081482438387b06fa85299a79fa890182efb2a71de586a758b1a23a960c3027c15b21", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10649954, - "script": "76a914d2e17bd37919ed7a035ce27f987aab49ee750d0f88ac", - "coinbase": false, - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 12 - }, - "script": "493046022100f9c01290c7676e4dc1af36a57d75153667517bb3a5713f6a88cc092119d86d1c022100945389b4d9d42b9a7bb896e4a5e8f09c75f186a1b73638a602d9074120a22e0f012103507abcd45ffda69b75a15511e38e79170412bc412a0374f76bfea39cb55a810f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10996051, - "script": "76a9149adfc78a4fca4549d8080bf54a98d874a161fb2488ac", - "coinbase": false, - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 9 - }, - "script": "483045022100e6f682ec88ee3e50b1300be9c9dce844dc25b904e94fad7d87f7f7987c612d2602203cadc753d0a017d6c22c304f4b35be78d0edd230688b08fdafda35e64391c21d014104cd2a0d22a3593aeb321b891211e973b4124d0fd72fc1908e75e540ae858b0df3826f76f3395ed910b90c7b4bc08bfe7e5e8f08b56a689137d6b9aa23feba2b3e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10583992, - "script": "76a914695e9c53d55152e7ff9253b3de6cac6398ba4f9888ac", - "coinbase": false, - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 14 - }, - "script": "483045022100ad2fd25a126339d640f86568c6879abe11205dcaa110752f611f8ed8b5339c78022057272f300e69ffe679d547214e1c31935b57a315e6912641ae63d09fb8d7c0e3014104400af9a3e117f0075a33be59d17efae728ec7f9c7b8498eb2489cdef787beebace94ab016fabf08151a16d3a826d2950e2552d1853e2bf97140b74c6b60d03b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11912836, - "script": "76a914543283e0b5fb2fa1779d82a64ced6200cbf8f65888ac", - "coinbase": false, - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 11 - }, - "script": "47304402206cc30d616c11805a6091e80c3eb0ab903ea513e02a3d39e65c447f7b5d6b613102207b45303feee723427d885d4463a4252070c44ce36eb4b33a8eaf8802127d80ec012103130a75409583720d1e13110128807f6392ef73efcf6b0666ba6aea0e9ce2ecef", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 41400000, - "script": "76a91412e3e9e7b78ea45fd801505e851ba8e4baf6cee088ac", - "coinbase": false, - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 2 - }, - "script": "47304402201fa4e07e485abcd4cc2587f26a652050dfb138a602c7d4e8863ff47a3bd57b8a02200f92c8994ba13969391844b37d076721d13851d3592c400221da97a4c57986500121030c582a034197cc5b3072cc08871bfcdaf3daeaacb628a98a1051b84442c813e4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 41556200, - "script": "76a914a6f77617c7717061dd7d0c4588ec69486ba5cb3488ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 7 - }, - "script": "47304402205ddbe24465887bdf67eb2b52a3b1653fdc34c015174f04045d97d450af21f13a02207102f92c6a3cc68bde4e27525a8d69728f91b89a97929b785a65197da1a016150141040b2c58f2d88f2e62aaf2c286d855890ca98c5ccdf8839c485ee199be70fe3271556ca28822f158013d4ada393b3b287bdfaef02c25c7104e258729e007a9dc97", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4950000, - "script": "76a9146df51cb8cf8272f91ffc18542b001144e57c275488ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 12 - }, - "script": "4930460221008c2d3674fb5c3c368ce2b9d5f01b9084962cfa8a62aad72ea0ac73105ef6da67022100ece5aa47d29c307aacc9ae4d6ba8b123c4d895e8dbbd6d67d39afd5c69aacd00014104e6d69d04b2ec43d99149096509de2727b20e8f375a5fb61b1baaed431208da88c7a5fd05760669facc5d6398e31012a0337dccc95615b5ef8c96b64a9dfbbf00", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 4984000, - "script": "76a9144cf9c3cfd24fcf0579039df4dfa9929b76a0a82988ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 1 - }, - "script": "493046022100a431fb01a3c09aec3a783e0eb3664f52acd149e429ff0b390b334d7d40fb013002210089d6c0af1b5f9af3ca5a127fa1d03bfe379205b7df3a161c224337c1d99d90340121023de42f4e88dde077249f5d90971e64d8b71bd03eaa78f6069f9aacea155bc011", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 11300000, - "script": "76a91413ddee46b4bcf2b95f811ee06274a3a18cd9f59b88ac" - }, - { - "value": 10600000, - "script": "76a914f2f9c64c2d4f699442e8d150cf83fb9bb40db59588ac" - }, - { - "value": 11413400, - "script": "76a914bed4064cb17295c9eea4c8027f15a38768552f9b88ac" - }, - { - "value": 10176700, - "script": "76a914cca05eca1c99d07b14d26d416d6924b3cd41c84988ac" - }, - { - "value": 11005223, - "script": "76a914987ce8d24d24b224b7a149be5047b4355aaadee888ac" - }, - { - "value": 90100, - "script": "76a9149d1e31b6a3aec46ed2b4f9259100b47fde80796688ac" - }, - { - "value": 10538000, - "script": "76a914ccb1af4d10e4ee89327e0a65cabf670f912857f788ac" - }, - { - "value": 11164447, - "script": "76a91463b15467b5895814bf63f7b9fd7261076b65aa7788ac" - }, - { - "value": 3336982, - "script": "76a9148c23a3da7806dd4a437bc81ca26ca4a02465075288ac" - }, - { - "value": 10950472, - "script": "76a9140b1e69789efc252fb4d0fa66b4faeb44199f800288ac" - }, - { - "value": 10692300, - "script": "76a914bab66bc8cb589aa583c1a4d38a1501248ed0465588ac" - }, - { - "value": 11252848, - "script": "76a9144e14c7cc91a10829a3a0f1ec46389fdc4936987d88ac" - }, - { - "value": 11800000, - "script": "76a91474e2031838cf0f1e8d2c424cd7b08bfa0d9d8e2688ac" - }, - { - "value": 10965800, - "script": "76a914cadb9b27dc46f7ab14f00123c2082a61e5177e0388ac" - }, - { - "value": 11902000, - "script": "76a914b0a30758078ddd645a83fa98fb065781937e61c088ac" - }, - { - "value": 11100000, - "script": "76a914ff55c43493ad03e521b688cd2ace638662ed1ffb88ac" - }, - { - "value": 10827010, - "script": "76a914a0ce43fa069b51e5a90e2664134b3e2d1c6c649188ac" - }, - { - "value": 11526599, - "script": "76a914f9f101307d188013a3533e3eda15e4188909a94288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "witnessHash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 445, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11005223, - "script": "76a914987ce8d24d24b224b7a149be5047b4355aaadee888ac", - "coinbase": false, - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 4 - }, - "script": "47304402207c926e8a7f84b6dca347b22903e175c8f041f006fd5a5eb76a96c4958786bb1602203bd2991d0d5eab251414a19163818dfb6b252bcb47f7fa1dfb3d6d6ee10171e5012102fcd89fc4526c3d940b058b08da66c1e88f3036d37be3711340295f248390306f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ecad6874192f21c68e36e3092e9c6da40ddbd95f7af8be2fc8a0bfdb100cb365", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300002, - "value": 13868000, - "script": "76a914b7f4d959a3d62bb0639e02609932fd0b65d56cef88ac", - "coinbase": false, - "hash": "ecad6874192f21c68e36e3092e9c6da40ddbd95f7af8be2fc8a0bfdb100cb365", - "index": 16 - }, - "script": "4730440220157fec8d0c832855cc93414d9165475a652f3e2d9b52fab38141c197691cdb5602204e240f34b64e151f826eb030be4c62884717d8e3fbd6db8a280bce2aacd61b25014104a0163ebd641ca9e7c34d40157e77fa30206cbed0ace3c039e0c852166054db2487a0f7852ec2e27772086325afb027452c15aa377959626370932e8a67118a9e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 41326000, - "script": "76a914db5780163c8e2a9cb720189bd41cd6ef038def8888ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 9 - }, - "script": "493046022100e6295cdf4c2b57f600b0e6147d07c19ed4aeaf6739a8f8c1b866718a7ea005dd022100c09c9189249e506dd0d0a106e32c61198b2200e9a9b8567bafbea700a569c0ae014104b6c85e364195e74ab5c899257d457eb461a062faa94113785bf0402c57ca529f1d338f014072b87e0c9d4ace4e8a8aeb3e811f7325a6f42efa8f37ba98e955c1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 2186495, - "script": "76a914c01a9108e2aa45d2e3e2f28559a7cb62aaf3e91788ac", - "coinbase": false, - "hash": "8f098c0d832c9962be3d517c751cb402a17ae437a8d23837c86c67cd1fd47e78", - "index": 7 - }, - "script": "48304502205d33557680c69c81841d1c6d5985323e461d1fa2aef3e391b76db40010d067d4022100abf2390d5682f099dc81215c2a1b98c127ac04935392eb9f1f3396928ab66af801210339f8234c446a163ec7763e27bead23434e68f9bf94705118bd44e17bd1d41f53", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11252848, - "script": "76a9144e14c7cc91a10829a3a0f1ec46389fdc4936987d88ac", - "coinbase": false, - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 11 - }, - "script": "473044022043aa02aa393aec472ceff91c97b74b93ffb7c08f136e405720b03bc89ed0e614022065e9d9e074ab645cc1f50391efb3e469ecd209f833ac1d4f4748c6d05124178201210307aa9d4302f13d320930085f300ab061018360e7437c011099278b79ff5eda95", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 41290000, - "script": "76a914c61d0ab218ad821dd41452dab5f799fe46f37d1888ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 12 - }, - "script": "493046022100ab7a71d9210748d8e2dab41497df22b3779fadf55c5065f4a7c0b0a598aa6a13022100e5716f4e6b16197e437ad198d6a05183985a1f9c1a8d6e644fb1191cfe1169430141041c98c19561ffeb1365af963eb17fe49b525b565aefc4a9045fa3da6b8c07f28c33ca8cb9fdc6a16aab4603475fa803538d4b3c25e16037a2f00c6c79a1fc1c4c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10827010, - "script": "76a914a0ce43fa069b51e5a90e2664134b3e2d1c6c649188ac", - "coinbase": false, - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 16 - }, - "script": "493046022100b0566ded93c6de6114cc838709765d6f5f4454d5894daa6159886ff94c9d53af02210091800fd7059e684ed78d93d131a48acaef34050f855a5d755736c1833dd50d0c01410422d40f4016b67b2e15e31a609052e5bdbe29563d06d8f39b6b6702a66d3d42dd921443def8277ef9704b6f651caef237d41b33e6c99e374a98c791a21c44ac4e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7f1ba2c5711674ce416a129fa95690cdccefa83b0c925a991369a6b9427ddc4f", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300012, - "value": 13860000, - "script": "76a914fd55e1eb749e6b74f3942ea2a8b5a3a588b7c7b588ac", - "coinbase": false, - "hash": "7f1ba2c5711674ce416a129fa95690cdccefa83b0c925a991369a6b9427ddc4f", - "index": 16 - }, - "script": "493046022100e5edf6373f032fa8be20b57259861ee937bd323aed314b585d41217b14937fb6022100bf979cc8acd3995e034d6a54e15a0f2a360645fb1c1e250e49aa9ad450d293ef014104c4e0f161838e2d9ca478ea36d9a6f7b018d0c9cb6673c04176222ef29985fd79a0948218fb48624851cf07e9771eacb8098846fffb1b302fe1687cc268bc59ab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 11164447, - "script": "76a91463b15467b5895814bf63f7b9fd7261076b65aa7788ac", - "coinbase": false, - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 7 - }, - "script": "483045022054c7910756294ec7e210a1796a0191d4aadd156fd263603534998a0a48446eae022100f2ccad86c9ab08464e4d408680390902c12ad1e3c5f8b7ad635b5b5e8858dc83012103576d5906a699a780d6903bb016bb87b68665f617b08ba19c46f7cb3cb0212117", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 10950472, - "script": "76a9140b1e69789efc252fb4d0fa66b4faeb44199f800288ac", - "coinbase": false, - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 9 - }, - "script": "483045022100c26b23abab52e1de04ef8fdac547bea102f0b5cabbf3dee86a5a13bb914e2e4402207ce4bf9ae822e9cf1d7a7d5b8ab7bf56ce0235f27015d815bdcb3ae214bc9f42014104c07e639a7fe100709ab8f57057b39ae51019d881a0cf8e177d359983ea95abfbe003eb3edd592e1652bba985eb8c8f46a5e5366f3878c75b9a3f6b7e93c8727b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5000000, - "script": "76a914154056509f0cb2d4a480edac491483d2f8f9955f88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 8 - }, - "script": "493046022100fa32a1157ffd8b5748592f50322c0084a3b35df8e850c33d8d445beaefd03bb2022100f29c93f5a4e1518d9886593b5ecaba8b285acde41b5b526c08a7a28f8219b262012103050c1367bd9737759282f535d676a762b9886343c5a8a8bc507f4fb5907216d2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9240000, - "script": "76a914f3709e949a9d90d35a0ec0f2c17519222315540188ac" - }, - { - "value": 9791100, - "script": "76a91482ba4613650072066806f20bd778a2be9e1651bc88ac" - }, - { - "value": 9171951, - "script": "76a91444018b878f943f929145e68a5a1a81179051746f88ac" - }, - { - "value": 9231980, - "script": "76a91450aee718d49f5c7769c7011479429cc12321e9bb88ac" - }, - { - "value": 9410690, - "script": "76a91416b431a6c0525108cb1a74418248f5c92a74d2f688ac" - }, - { - "value": 9127860, - "script": "76a91471f62a84095c921f4358116090c15cada2f50f1f88ac" - }, - { - "value": 8997430, - "script": "76a914088d7e5a8dc4a1e2e6153ee78f7132ad2809e25c88ac" - }, - { - "value": 9994160, - "script": "76a914ba2c74225a64543ad5b38a5d6bb9a5f5d0a6f39b88ac" - }, - { - "value": 8523400, - "script": "76a91496df68af3b1059d714db12f01bec6d5b095e42e888ac" - }, - { - "value": 9067000, - "script": "76a914865045448678e894f531f206584cfe448dd60aba88ac" - }, - { - "value": 9250000, - "script": "76a914b0ee1dce75a0ccc447fdd79ea1e246d028a382d588ac" - }, - { - "value": 8930000, - "script": "76a9144a87585fe7c40ede87f48900e9c7392b4740ec6088ac" - }, - { - "value": 8890000, - "script": "76a914aac08dc7e30698aedcaaab4715a66c032932717788ac" - }, - { - "value": 9255380, - "script": "76a914a342c86970e8160e6e84b0f09787d52f574b64d588ac" - }, - { - "value": 9076000, - "script": "76a9140fb9077d86f2e6630246c2dfddf14535357b1afa88ac" - }, - { - "value": 9153913, - "script": "76a914b67f88969fe211ae6f03a451e709bc87b7a4735b88ac" - }, - { - "value": 7252855, - "script": "76a914f357f92129da30e443768d62a656833bb06e094d88ac" - }, - { - "value": 9193908, - "script": "76a914b9897b95d0e1cd6656eca2cbaee41d55a12c1a2388ac" - }, - { - "value": 9142868, - "script": "76a9149834818c850a84b0767b00a796ef97c5f837d6c188ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "witnessHash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 446, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9142868, - "script": "76a9149834818c850a84b0767b00a796ef97c5f837d6c188ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 18 - }, - "script": "483045022100b9d2a0532a3e6f4e634b554cdc2fe4dd2d48a9b295f7e3a2d9e8d16dbdaa4b8402203c3678de439ba3935456fca620278de744baa17ddc422896ffe3fb20bbede5ca0121039dc0b578f9adc3d94660f7dee5f32e8f963473e35e271bde55d2deb82079b606", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5100000, - "script": "76a91489bb8198fecbfc5e699ee2bc4bdec4cd682aade488ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 6 - }, - "script": "47304402207c7b9dcb98257a0e9217ba1110a0df04eb3ec1878576a8bf7e94274e746f628502203e83cb32baf71ab02c6f518e84ff80f6ada30f3f204a7e2f65a311a37d0f973a0121027b75818bb8d7488a13816baccbb5ab42c562c81850642a36b4373575daff6119", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 14111258, - "script": "76a91474e2031838cf0f1e8d2c424cd7b08bfa0d9d8e2688ac", - "coinbase": false, - "hash": "90a266057fd7dccc07743c7f062715ea1a7839ddda0e496399e6996c100386c2", - "index": 7 - }, - "script": "493046022100a28fba91858ad80395c8edd69efab8e1b41ef95c3af05567ea17a59dcf962295022100a3bbff9ba62ba5e45d939f5c0f31ee8beea2563e2e89f92e50897ba1ae68da5c0141040ab627c66e2a184e76f860eb189ebfc49fa6d702793b5ea8aa5cb112aa667fcfd5292e2c8beac46ebc7d0f254566e3d4d9902a35e3d25bf06e57772511b815b5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f53ffd94d3af40b157d7cba42586da91eedf7af74f7f47c7fc73516741df5645", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 14279022, - "script": "76a914a2f8c483f22b7aac2e0ca0ce0c2938618b3007ed88ac", - "coinbase": false, - "hash": "f53ffd94d3af40b157d7cba42586da91eedf7af74f7f47c7fc73516741df5645", - "index": 17 - }, - "script": "483045022100b31eb372d8a3f1d087d4ffd75f282a602c20028f2df6805c2a23d60df8106b6302207831994d098d5a1e2360a5385b650395576276da2cf2771cfb73e0c133f3c46f01410472044d8729a85bdd7723b854d8e8b97da471aceed47d39cc88e0e72d7989500d9190ef16aeb2d69c53d4f0d25476994990597038c079d3520716490059a3b6eb", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "65a4b5733d9371c4778feb5c3b0ba2e93820a2c4d833371f503a01d47c2b2e60", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 14021920, - "script": "76a9149e325dcf525d92c981f86a5dd8e11a04b7dd9a7488ac", - "coinbase": false, - "hash": "65a4b5733d9371c4778feb5c3b0ba2e93820a2c4d833371f503a01d47c2b2e60", - "index": 5 - }, - "script": "4730440220558cfdde2a79da0e867359576fe3dff57a57495c1c53398b1eedd9db7b9aab7f02207a507d562be9331b3e8441075072f8bc98565604f719a337901280d0590af0250141040be6890c1bdefdadc459e0a03d7c7246e52a6562cb3aa967498ee419e84cd74be9eca8f2810236e6ea64ef782c5e50f131777514495a1a5c0fd222dbdcce700e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5000000, - "script": "76a914a1c9df47a9f8c8617769fadceb288e93f9af4d7c88ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 17 - }, - "script": "493046022100cb5341c8a731fa907b16f5dffba1b683101b16c5545a0637b0009aeb7b94b5f8022100eff4fc9c7483ea1782e1d51755ebacbeed26eef1aec78a85396f4dc20690974e0121036351f2841d7646b8a976d5ef91d4f8d0961aee618588c0edd1b016ad190fe153", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9171951, - "script": "76a91444018b878f943f929145e68a5a1a81179051746f88ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 2 - }, - "script": "473044022061a715671c0a5dc3989d0d32611f0bda31456ff83f90258853961919545ff9a80220420bc2a6e350784727af4f90c7119215e4721d849a2045674ab2cc18b34ef3b9014104c78fe617c70177bec368eed1cc9cd54ea49833105decd779a8a4f077fd06d2190a816a94f39fb8d4c63001eaf8d1a8c6d1dd743737a9f1ea09a931f699c1d2d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 40840000, - "script": "76a91438156e1a70e0f56410a417c7f5cc0a4173624b1f88ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 17 - }, - "script": "493046022100a4cd41723cc4fb7fd9bcd337daa15448e4cd4ca514ee15186d82d4c7328252e7022100ab3cb54b11dcbc8b313758ac2a06159f2192d0063357a6bcd23e2cfac0dd58e7014104dd4390638c38928d9c5e36c033977e8f94441bf6e693355ce65b318825a803e457b7e6ab0cf0bae17256c9f5119bbab3b091f2a95c9d62f6d9a95703fbcfa10e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9231980, - "script": "76a91450aee718d49f5c7769c7011479429cc12321e9bb88ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 3 - }, - "script": "493046022100af2c59bef6b876b6eabcd9bcb0e3de64589d14ad54d7569b411cb05bd82cea16022100fd884a458a57a44a8e8c94aeebe4f5d7b054754543a8bed1f5603ae9543c0794014104349acac8ab96a8b43f3abe2c7f9127206a684fd7bee9349fddce53b1496631dd1231a691f314eda831667426f92cd0503dac4d6f4a78e486a95507efb1e7a869", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3336982, - "script": "76a9148c23a3da7806dd4a437bc81ca26ca4a02465075288ac", - "coinbase": false, - "hash": "4b26ab370dc47618bd5de04592364a20f97c30ad119c1e00ccd4fc3058692997", - "index": 8 - }, - "script": "473044022071f5f8eeb907e8f1c02c72d5f08be3bce1f8f9a435bb7f23426ebeab102d372102203081f9e996f1344fdbc4fa08fc35e56eed3ee59369d34302b3985932a88f1fa8012102a0354bf72be83d6b1377a9989da3f211fbb65034b366da6239af22d867036aae", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9153913, - "script": "76a914b67f88969fe211ae6f03a451e709bc87b7a4735b88ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 15 - }, - "script": "4830450220592a22e5d2384b51944aa67d1f46aafc8081b1b55323692336f2d354d66adacf022100ed2dba156498b1943186849588707c62b8568b7a267f805285c30eaf0ee9fc3e01210389cd790818fe36634783279c583b4223db5cf8b1995763e0013513aec4e193b3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 40800000, - "script": "76a914bc12c4f9fa9d9309153c9d0fec8eb7f0718ab7a988ac", - "coinbase": false, - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 4 - }, - "script": "47304402207a8a587e200f5196cf7c548076bc488354b5cf25658bb965e0705e7d71f1dd4f0220454057e27e09fe8222599f1685d2c0c512ee9b9d65f2d87d9f023b98ccdb3d23014104b4db8e4c3bb0fd22bafd3c42084a72ccea2fbd9fc07766d9b9362f5c8f6a7381587453ae7c39f31f8c03e938833408e04c06bae0a4f1e18fe4fb0891ca3122ca", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5003000, - "script": "76a914c7de75c1221526b1c662e0d71d6670e38bce7e5c88ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 2 - }, - "script": "483045022023b705a9f1716420640288f6300ba97aa9953e373b7c9358e3a5502f0d7a2ef7022100f28812e78c7a6afc922b9066bca0352f199e31e29f83f742174e87ece8a2998a012103f06a0b01f91b90feccfd3b9b5790ae99cf5b78f75e776d4c706b785580fca4f6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9193908, - "script": "76a914b9897b95d0e1cd6656eca2cbaee41d55a12c1a2388ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 17 - }, - "script": "493046022100ad8633a7cf10b37cdc2255fbda588a908bd8ab7595861afdcf18c4917fcd4f73022100975c7b141bb0aa5578b7ad5347e03666908f49a7b9bf399344c08752f6caace1012102929909af3ab9df5ecb511fe37494ef9680dfa9db63662c23bf39e07fa41a81ac", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9255380, - "script": "76a914a342c86970e8160e6e84b0f09787d52f574b64d588ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 13 - }, - "script": "47304402207e6b86c0ac17944805d0249c364bca739f4f1b6110c1a6459ed7edd5cf5f7108022059d1504d09d7a969a8276df2a3e48b9544b2df32bcc6cf9487bd22090a8f4949012102b9501afcf53eb09c26e09621e1b4a413684f7d725ceba9696705cbd777536fa5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5f915b3fd8036ee5059ede534d2cde7204dfccb18f1b488a908ed4353fafb130", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 41135917, - "script": "76a914fe2e508a59d736b8eb2e5d338c88e96d6ed939b088ac", - "coinbase": false, - "hash": "5f915b3fd8036ee5059ede534d2cde7204dfccb18f1b488a908ed4353fafb130", - "index": 15 - }, - "script": "483045022100bd59059176df9457370d51717b4dd6823cb2e7f33a545f21ffa7be713f4ef359022015cd243c100619bae6f13dbd025180e1023eb703e99cdfde88f659381cd8f9f3014104cc8f5e25ffaf5ab571d297997de2348340b3ed1ab1534fd0a3f92afa9ef3d864a717fb71662e7d50dc6ba3c99cd595237c515dfb83887386039423e6178b54bd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 23 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5003000, - "script": "76a914dfaeeb10bfe54179367391c91fed2b92a7c0fa1388ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 23 - }, - "script": "483045022100e959ec51358573d6f54a6d5ac8b93dc6b1c8a5c1cce5965af585be04247d999102207e2572950af3902a774f5bc0b8ad9c2d5f7efeded81f1da509c25c0ea19b9a1c0141044f4c29c1d050293aa3be036b29d44bf7904bca2567b7317fb5ce0671c0b8d858c12091be465d6936af99010e356b73e2fc377bd46654e0d916f5d317a4c29376", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 50000, - "script": "76a9149f3fb46a0aff32eabcb048978b5709322c4de86d88ac" - }, - { - "value": 13100000, - "script": "76a9145c7a50fd6d68e2a1bdf5e7741ed5bacbec7a94f188ac" - }, - { - "value": 15445340, - "script": "76a91474dc5669d3ca627caa70ec3c7fdf90bbed09718488ac" - }, - { - "value": 81000, - "script": "76a9147751f8011c608a469b6073b8d334fae43f58c7ae88ac" - }, - { - "value": 13600000, - "script": "76a91405064b62643ce6b69308e0fc6a985b4ff16d614f88ac" - }, - { - "value": 14370000, - "script": "76a914ed438c1cfd3e457d4cbdaa31a50dbbb23c814b6c88ac" - }, - { - "value": 14512000, - "script": "76a9142c1f172e0fc1eb108567ba191f1092620175085c88ac" - }, - { - "value": 14900000, - "script": "76a914c45a7bb9d8b8d7d9f3a92e76b94587ee7f3e233d88ac" - }, - { - "value": 30000, - "script": "76a914e6fc4e86f57e647a56b07df9d4ff88439fd7acd588ac" - }, - { - "value": 13864957, - "script": "76a914017dd1b98e8a876d34eff2dc3a6b64603536dcdb88ac" - }, - { - "value": 13380000, - "script": "76a914c16ee8c980a5187e154a2ed52f579aa90607516a88ac" - }, - { - "value": 14400000, - "script": "76a914795344923e800f11872017025a5248d240e3474788ac" - }, - { - "value": 13200000, - "script": "76a914203d6a31fedb2b8857b991523253c9ad4a22af9b88ac" - }, - { - "value": 13871845, - "script": "76a9143c5e962566d5e9d427cff5575560822cc3e79d0d88ac" - }, - { - "value": 12400000, - "script": "76a914c0c2dd09b3622601243c04edd89b03120acc587c88ac" - }, - { - "value": 7835759, - "script": "76a9146ebe530bfa83507b0be8c4d48c5cf49d427290cd88ac" - }, - { - "value": 14850000, - "script": "76a914e9b21ed16619283fc1662260cf6de48e3b00426d88ac" - }, - { - "value": 13480000, - "script": "76a9141cad003bbdbe0e8062bebdf6db1cfd9ac6cda66088ac" - }, - { - "value": 14815770, - "script": "76a9145e9c715abe183b5c1f6fe662a4b497499eb6f50188ac" - }, - { - "value": 13007000, - "script": "76a9143d3614b8b7bfbdafdefa7bc5476ebb4f9b71c72488ac" - }, - { - "value": 12547428, - "script": "76a9146a8d6f45d93bff9cfe1ddcb4008ac79e669f67b888ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "witnessHash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 447, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 40600000, - "script": "76a9144cc1f278d7d6a5492d48a2284fe1ad63f8cc0cd888ac", - "coinbase": false, - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 3 - }, - "script": "48304502204ffcb22ca34260585be03a2450739251739000ee4c5db6d169db0146e08e708a022100e8321d94baac214a334c24991f21ec5c65ca4237f11fa5af23fe8e22b35b2d5701210379d390cc5d9329dd10807279e6efb9afc2e82da5a8ea813d71cb97726593cca9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "19b1655392af1094d2df86d0d50c06449dfe4d1f2debbf05245ca769ded8ea0d", - "index": 20 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 14504000, - "script": "76a9146935a2ce5535669dc641cffd0cbab522a272f1c388ac", - "coinbase": false, - "hash": "19b1655392af1094d2df86d0d50c06449dfe4d1f2debbf05245ca769ded8ea0d", - "index": 20 - }, - "script": "473044022054aac19c360a6d7386c2471bdb2cb38d74f0f4eb7521a5644476d548a77e3a630220663eaa24a5fdae6eaa3123a05fb1bf8a236a6f02d6ece1c0efd25523252ecfac01410407ad45dedfda2b2574e5bde2a824f82e10093a77a14324ea48d7d11a3a37fb7621d127a0eecaea576bd72f3293118ccd092a24cc952f6d2d449e350bbc7e18a8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 14815770, - "script": "76a9145e9c715abe183b5c1f6fe662a4b497499eb6f50188ac", - "coinbase": false, - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 18 - }, - "script": "493046022100b915ed92d5af93e71445efabcd4b17a21c51afe0fbac12989897176134a8d777022100d06632e5b2c98618063e47eea640f490d6841ea188d383559449ad450a5f867201410432503bfade5b2708c3bab06560167a4d164fcc984576beea2ce6d978e40fec39a369e9e1b16ab75aafc6639f3c2b587493b43d44f5bed1743d78a0b1d6ac312c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 13871845, - "script": "76a9143c5e962566d5e9d427cff5575560822cc3e79d0d88ac", - "coinbase": false, - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 13 - }, - "script": "473044022009e4da767dc9743a1981d93a30cc47ab15c90fec4a1963b58ab08bc9d353195d02204c6d573a3ccec947f3b1b90918e5d89dcfabbfd69a45f4bbccebdc47ff956fe50141049fa65b02c5b1eb83018e15d5a6f6b681f80ebd930260c7b7b0f0d54728a8a550dce127c1920c5861786973d3daad5c12914de69436b8b40db8319c4c9f787410", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 21 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5100000, - "script": "76a914a89794738f3e896b74aa197f21ba681436263a5988ac", - "coinbase": false, - "hash": "77b1b5ea8f9511e1ce40efb59d7d1f8a86c6b0615b8c138e284fb3c85bdf70ac", - "index": 21 - }, - "script": "483045022054462022b02a3e0ebead53e121869d9ec326041b08f5d489b36a8be147deafa9022100eb0dfaf1225ab8734b14ed0f332ba994c1831da2c41255438e5620f59540ff5b01210337925f5ed77284a7b66651d4aeaad3b5fd286084ef5d3ceabcb71fbb9c718a6e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 20 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 12547428, - "script": "76a9146a8d6f45d93bff9cfe1ddcb4008ac79e669f67b888ac", - "coinbase": false, - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 20 - }, - "script": "48304502201b696f1e4e01a54d0243709f60f5532126eebee247a55dc9e4a4c1158d361374022100ac01ce18ff489bc8739ac204c267fa2da5952b0388970686fd1aefdb78ba1e670121024bab8603999541d8584131eb32114c8cf4f421f59b40d0d6eca964e3be17a1bd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5165860, - "script": "76a914fa3ee28d80d7695195dda8c31ccefc69562fe67588ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 7 - }, - "script": "483045022100de84a803dcff97ac02fb24ac757c37acba9665070ca8bb0fd7e7da232e9f7799022052b0ea84db2011a9be0f3c1a80df9c860fb77bbaca0d5f16087ed7e789c2319301210342bb966f104b2aaf979647d4c56545a0c48800c242c5dce98e2d634f8b8834e6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 13864957, - "script": "76a914017dd1b98e8a876d34eff2dc3a6b64603536dcdb88ac", - "coinbase": false, - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 9 - }, - "script": "483045022100b9811a3e5c210f1740d6739ff7b726e67432a7b7460fb01bcfa2568936e6f04102207d76da67a47e57b6b2db82fcaa0eb6b202b6a6360873deafef92eb46829142a70141048278864edde81ad6b1a881f2240c4b229cec1d2448c907a842442078ffc18a94c5b39fdc9eef6db5c51a44f6e11e16ec4b42e6becbdc75a81d4cafca80a6a076", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "19b1655392af1094d2df86d0d50c06449dfe4d1f2debbf05245ca769ded8ea0d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 14499000, - "script": "76a91438f3d5ab4c78f77c4ea4a06ac74d1b8d8430572688ac", - "coinbase": false, - "hash": "19b1655392af1094d2df86d0d50c06449dfe4d1f2debbf05245ca769ded8ea0d", - "index": 1 - }, - "script": "48304502204654bf51dd576a7a95889693c98fcc91449e5d6945cd9e63ccef1c78b6b7b12a0221008b7cf76423affe9fd369b2239da3ab2f4368aaf8acd59c5b3399382d1dcd897e012103c8adcf7c8cbc2841428625551aba0dcfd3fdbe45710fd477017b7efde7d0aeca", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 40750000, - "script": "76a9146450c354a46a2ce8d518363122bf6ecc62e378f288ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 10 - }, - "script": "4830450221009ec3f4b1e1f5a58ec766ac3436766164a10ba28370498b550d60da88b536f7c502204bad59c1a4d4070639f0af0ec11df7b87f60e5a4eff726efc372376b3c6de1fb01210333ad103cb6f1b78204f95ef314b6ec9395a10f01d45068156999f2e980af722c", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8891670, - "script": "76a91473f9526707d3d4ca945e28a9dff924e79050b1cf88ac" - }, - { - "value": 9050000, - "script": "76a91465429e5f47fcd947b2a72799fe36b06d299fe27c88ac" - }, - { - "value": 9063335, - "script": "76a914a05164bd2f5df2aa83e41819ed072e72b1b94fd588ac" - }, - { - "value": 9338070, - "script": "76a91460649d2f4bccf38f5c2e9e5fa3708a17b095696988ac" - }, - { - "value": 9039700, - "script": "76a91496ec1e063893a8993e1a5f03066de21c8d6ea0d788ac" - }, - { - "value": 1022530, - "script": "76a914e0d1a909b8741db823b36236f83b53589641fada88ac" - }, - { - "value": 10090000, - "script": "76a914e72fe516dd087a8fee406f9207abb3070255919d88ac" - }, - { - "value": 8999540, - "script": "76a914c6436930f538461b6225da8b174339b3d21b44e788ac" - }, - { - "value": 9504270, - "script": "76a9145ccb8f23363ec2cc7f892fe1a3d43fe9f926bb1e88ac" - }, - { - "value": 8610000, - "script": "76a914848051d8c354909f2391cbbbfb82e9342188e2b288ac" - }, - { - "value": 8920000, - "script": "76a914e23ce96401f5583571dfaac21488cf4770cb999c88ac" - }, - { - "value": 8940000, - "script": "76a91405792d55332be831f93b91428a0986972ba41a6188ac" - }, - { - "value": 9890000, - "script": "76a9140c3d9773ab3d024fc97dd247ac0bee555370dabd88ac" - }, - { - "value": 9281000, - "script": "76a914326c19764d1cf7322f9af51bd23502bff9835d6588ac" - }, - { - "value": 5810, - "script": "76a914fd331db6e477d3b991f8114b560279a62270a63188ac" - }, - { - "value": 9300000, - "script": "76a91408ff0b6a8ab9391256a46dccdd22b5442f8ef2f888ac" - }, - { - "value": 9129126, - "script": "76a9141c79fafc028816155202071ee7a1bf8ddeee26b388ac" - }, - { - "value": 8755810, - "script": "76a914ded117e600c9ed41be1637125b45a7bf4918818488ac" - }, - { - "value": 9351006, - "script": "76a9147640f3905ea1817785b1a6eec4bf3bbaf361a1a188ac" - }, - { - "value": 9291016, - "script": "76a9145cdf16cc24f9fa1349663e7a244369414953afa388ac" - }, - { - "value": 9215977, - "script": "76a914b75a9972bac8e918ecff20835a07e613bafa180b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "810bf5b04f992908f43e29548f9c44f568d673854b63ef3aa474f29550474c3e", - "witnessHash": "810bf5b04f992908f43e29548f9c44f568d673854b63ef3aa474f29550474c3e", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 448, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9351006, - "script": "76a9147640f3905ea1817785b1a6eec4bf3bbaf361a1a188ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 18 - }, - "script": "483045022100e05bd60babccf49a47a6cb1e52b57e020272ad873c5f3958d14edf6de7bc4fdd02206c978e4470ca0c0cac68f0feb4f993d6d66ca0bba811a11caa6be8c26d9298fd0141049f9e1dfd55d4c8d5b0168bc1bd37ad0254a75b502afea56e4d3d09c654dfffa877921a4acea4f8ed4f2e820608d05e4f63a615d0281be1ffdf4418c1e794e058", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9129126, - "script": "76a9141c79fafc028816155202071ee7a1bf8ddeee26b388ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 16 - }, - "script": "47304402200138e94a2d808b620ebce683e015424680f05efb74bda799bae593c87893ac5b02200405bf714f989c6587a49021c5ce9072c0b6e62f97fbcb833e19179721d70fca0141043d212a0dacfdffc5d24f9498ed407e35182d624e40348bf9d24fc7d7e2b9388fe5dc0db87155c1c78c751a5c7ddb3ee6ba3e4321e2a53a3d29e8e5aa9b8a2395", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ccd166b2ca8be083036100f5936192d124c976c069737b5b53694309f9e35a3", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 40392791, - "script": "76a914d2cf51b90eee298eebd1da90e718782e9d66e9be88ac", - "coinbase": false, - "hash": "6ccd166b2ca8be083036100f5936192d124c976c069737b5b53694309f9e35a3", - "index": 9 - }, - "script": "493046022100db2de5ecd7e3c2ff48a5c02db808fdb1aff8c47b82c98621b723dae62a50eb95022100f5e93a9668be99bac59dc0fef8a5828e0eedbbebfc7962d8884186cb3e01d0cc0121024cbe599aba38b6d65192b66202db9ccf9ce0c97d15ae2dc6960e1c85e4dd88bf", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5732957, - "script": "76a914ad3bcf491008ea2223cd797f8db242cf7009bda888ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 4 - }, - "script": "483045022000c24343a407eb6256ff6e5796f6a6c30112cb3b396798107c7edd83970b6007022100c348a2ccde562aba1002bdc992d4b1de5c3c575a41efe7a12b17880214afc935014104074b1f0f6761bfb8b4f4d110c8783a5e7198e9993f6e60a2dbc51cae933357f8aa660af847b5bdbf76f15c72ec088c762b9630f8c5cbfd97b72b5f499f0c22ca", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 31 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6056667, - "script": "76a914c684c64e461b1e8bbc4dec71d2642279c784b67988ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 31 - }, - "script": "48304502201a4fe05bd229d28acc42011a2831fa04d8b936b3d6618962bbf1f680864d6ee9022100d7b62b8a996b97fabad930b45449790e0bcdca679634e5e337dc9e019425c687012102fcb6c1c462d571aa7b94aa9d408592953e1084735c24eaa663f4e374fba326b6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a6348c145cd509c6136b4772e4a0c1bd0a1ca3b0f470eb8bba7afe5831faad8c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 20330000, - "script": "76a914278943373222be0372b8420bee13d725b77f914488ac", - "coinbase": false, - "hash": "a6348c145cd509c6136b4772e4a0c1bd0a1ca3b0f470eb8bba7afe5831faad8c", - "index": 0 - }, - "script": "49304602210082bdb5b2336db1231c0c394ddbbab97e014723ce38a0802c1f6c50562561cb57022100dc8cf4e14805fd8a99463e4e745943b03d58281ecd3cb2ec91c8d6112f38515e014104331a46d2370484a409a0cca12593dc4dfa243e2609943d68ad0a4a2f86f3c786288172bf0d0f89786e8de67cf45ab070e53ec5546437032427ac16704dd798bc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6729d5733f061fbf9020305729689b3751a413fd6992e76ab343e7ac9f5c2298", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 16080570, - "script": "76a914daf2c072385c709e199041b036c44d9495572aac88ac", - "coinbase": false, - "hash": "6729d5733f061fbf9020305729689b3751a413fd6992e76ab343e7ac9f5c2298", - "index": 17 - }, - "script": "47304402206303aed8009904c8d500f11c396a9656354679aa283ed83eaf7481a321280a42022055b81d27512374a0f0bb94ee045027930c73c5e0c56a3e74ef7ba958df92f3ab0121025324a3daa5b47e5ccd7a07938f8d2f0c372592d9b08275c48edc676803f4ef7b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 40000000, - "script": "76a91476fef1e8026902d50d768238a0efe1246dd9ea6a88ac", - "coinbase": false, - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 18 - }, - "script": "493046022100c2c7eacb200eaf19d36f4ecae919165e948bb23077d6eb9483ec90c06c74864e022100f844379a0a10df0d5539964e780591bf3819e51739171a41a3f071998ddc493a012102fb945c51a529b3f5ed6ed81ce3345e0b241d4fbd1af4b24d515715e1314bf32a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 38957100, - "script": "76a91405c8c22d5f7b3968493d6e90590b8ca256d9aaca88ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 13 - }, - "script": "4830450220514af2350316c5b6a0dd03e67f5476133303334a23ac3218abad3a7404619ec9022100e9e18b70f7ba5c94853b38069fb72b58d035d1a2895707f588421f008181660c01410454055de3b018f650c1c03d2a22548e1ead2735309c20d19653e628e2b57350033224dddef8e477b99889d82ef4be3ecc29f3426f5dd570b61a33142fc0723881", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "feb7272a5da311ac9fda29a3e87d569ffd9c5c5083265b28c46f89ad849b0226", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 20000000, - "script": "76a9149c76f68227aa64e626630a7b2203b2432bb09ba588ac", - "coinbase": false, - "hash": "feb7272a5da311ac9fda29a3e87d569ffd9c5c5083265b28c46f89ad849b0226", - "index": 8 - }, - "script": "483045022100e1889ae4255a1546a9e72cd11a8768499b640d25dfa74516fe8ba3f37ff826f20220381c02fb322daf31ee79eefe7ccdf2d21e4266c5f8ffb7dbe83e7c9a3de07b22014104718d4ac1557f499510ba7cad7c4365edf5f9c41da1b2fc66acdec2a698c1a85147f4b8dcd66b67ff033e78d3472c86d14960499953232a814d110ac992aacdbe", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 32 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 5273710, - "script": "76a9144d47e4ae5665c8f16a8ef690217518bf6e5dc77688ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 32 - }, - "script": "483045022015bdefe338541f9c976571c007fd472b2aac99c237ef62630c1e0e57c27641f1022100f9263c85b01c2a3f2d41254f49060a66d6ff954db0ba13c19b1c7d8c1d74e000012102291921051224b976f0523d6bf9e4d4e09cb540702b209a3ae3dd3d017a9a8502", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9063335, - "script": "76a914a05164bd2f5df2aa83e41819ed072e72b1b94fd588ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 2 - }, - "script": "493046022100b30c46e8304aef3b606a20f40526963b076ffbcc8c2837c158c0c8fdfa33e25a022100f96df2a51b3063d0597f1dcedf4bad7f41a84c37019a869149b2db2def0e5425014104a26b69ad0badda04be9bccb3cbed4e982378732ab3c5224669f05016b1cf7dc2b9bec5f3e5931fbb8dd47a9037b5e92e7b76ef3a8b16adfc061979f635b171d8", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 40000000, - "script": "76a914a5cb89f6b13487dec05b10a690e947bc54137ce288ac", - "coinbase": false, - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 10 - }, - "script": "493046022100b38f6e2c94a8d1f55797dd4b02f39a4382aabf6893f6ef76d6afd27c2576db7d022100fa0ebf5371af6c1918eeccc0bee63d4c03f4b2f41ab82df5fc92ab8524454aec01410404f792848bda5201ce9576c36a0449149b327629b721d08dcdd43dbc0c141ca1ffe21a8e5a16726a71fd8c0128ec08ca9d3302c24f41f399e09d396417e668b6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5196620, - "script": "76a914f2e2e2acbad94f0fc0c5c7eafe21ebe615fa1c2d88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 0 - }, - "script": "493046022100a27dd82cc6784f10f5f35c0a7e12589c2ebac641d20eafd2542980fd1da0c8fc022100cf2129af8385b7da96f9b23a7665f83a16d79dff62bef3bb07b81197f02242410121026b3d28d677e9cfd691cfa051680caf524e8c722b90244cd287ddcd50a78b2bed", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5190000, - "script": "76a9146e228e35479a37584710b815a29a7c3d8feed8bc88ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 13 - }, - "script": "48304502201eb17afc98fbf6727392cc50d8dc5b09c21dfb5a90b39a49cc20e3cb984f8de202210084f8ecd1a9c28fb33d933d4b2a15ec3c678259bef43c54ca251e404eac1a88910121037172b04c6828746df914293c3f093aaedb115fc5478b615a759e579c4c06b4f4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "75a98ce35b869772adbf643b3f8acadfa5b46b4cd8bfef26f9e079c517018285", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 17100000, - "script": "76a914c485fd58a81cfc5fcc628f1308161f942b76e8aa88ac", - "coinbase": false, - "hash": "75a98ce35b869772adbf643b3f8acadfa5b46b4cd8bfef26f9e079c517018285", - "index": 15 - }, - "script": "47304402207c0b329cefc9ca8eb7048809203c7f6a7ea2ff388ed9ec114a922b745f40de0b02202e3348d5c34f99bf1302fb614f74fff11d79e648a1fc382d3f22a7cea030635c014104241604b57faea6825c53048341f157a0e9e1b2c507f744f3dbb69339cc453ce6d07129e66b20ba9f09d1e3db9181cc58a2e693f2a8ea1545386798bee575f620", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5215000, - "script": "76a9141e5d736be3911036ed0a6e1e6f90c3afc93a4cf888ac", - "coinbase": false, - "hash": "759615d1954c62380c492a51743c365037300d04b729d8e573d3ecdb0bb0ad89", - "index": 4 - }, - "script": "48304502204d92a600c1a6458b70751ad45baca7a9396092458251e5469a3e67a47f6bd218022100fc3e7f0f524b17177b7af89e417f75a2cdc5c176f6a2ebb12223c01da46dcceb01210318f6958f258afbb705724d260c269392660c3ca6e8027e3549f641051169c839", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 40000000, - "script": "76a9142c9b234bc44b6d4d8e6404fad46d2ea2a02bb0a688ac", - "coinbase": false, - "hash": "bbc0ab273f26b206ad1ac598789da141044ccbf4f3b7ae472e422fcaf4f8ada7", - "index": 17 - }, - "script": "4830450220506627d8f9eefff0d78cb4e6a2c6b1d94c044aac8de1db35d6cae66050b7bfe90221008cc5fd24d468ae725fbef64c2508c0b6431e1e796ffd68ad4edca927dd0e25930121038aee40afd9a4312ff37be23afc503c0ac63909d063cc28465d4c035185d06bab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 22 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6359667, - "script": "76a9145833a6016eb94b63b3dbbec846106cb505b03b3688ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 22 - }, - "script": "483045022100d47bd92691726264d150431178770919cd41962556248c0afd518cf682539de302201ab0b6e8fd107946e020ddc533536fc702679432c30b8073c03991e9a0b8cc0f012103b871203f74c3e84d1e6acbfe2ad3ae8afcd448cee76aacf1c18eb6828ca2cc21", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 7252855, - "script": "76a914f357f92129da30e443768d62a656833bb06e094d88ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 16 - }, - "script": "483045022100d5edea6b9afdc9d7a3075db5f38589182babe1d1afeb8fd28a422cb6a54ac57402202d0d9ff8c99f423eb79410ba15bb88690f27723969d0d8d72c316e93715c69760141043101d45591871f36aa5c5d93bae9d0bb52c3c0f501821bc8da80cb8d8163c39be0f9053d327d954a94f7cdd2fee189e35b1d7d0cc609165d52a9490ffc5ce911", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 6066667, - "script": "76a914bf48b74b4ba133809b4201c861358af44092fbe788ac", - "coinbase": false, - "hash": "6b608f1ed2b1d9731c2e455b948232a60fb855817e9438c574c577a8868b71aa", - "index": 14 - }, - "script": "4830450220750aee1c89d4306916060177c353b6a11b60b53b444875bf9de0e72cc882a91b022100c08debd5186999d435bc78538ea98b8c9e04e3bc939413dea08e802555bac345014104262c109cd450bbfc1d7ef3bd3f6da17a354c1f02e3082fd38c5fe994296bfd3118eafa4a95ae5e574f8d06620f9fbdcaabafcadec6b3b4d2260c001abdd453b7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 19 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9291016, - "script": "76a9145cdf16cc24f9fa1349663e7a244369414953afa388ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 19 - }, - "script": "4830450221008d7194a9944a9776ac5106e35d96067977d93b9d7caa52202313e2c7f8cdccbc02205689a74255cc78a57d26cc8cf03407a29e5f70c2f878d5975501377020d49f0d0121037f2f0b0dc23a361e3b6c5053fea7666e5c52350cc0b695693eac0b8e48ee6db6", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8999540, - "script": "76a914c6436930f538461b6225da8b174339b3d21b44e788ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 7 - }, - "script": "493046022100903fc7857d80d90407e2a097c6f9553dda1aa5b3f13faf81e1100138583874df022100d51493b0a42db101044def71b2ae821a026c4dcf9ab965a403c01a47a5bbc8c201210340df1f1b86f5de9947ef9a72a26b8f7097bfa683abb888705e64d3037794c2e5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "feb7272a5da311ac9fda29a3e87d569ffd9c5c5083265b28c46f89ad849b0226", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 20000000, - "script": "76a914438556c4d4ac14e6b7d47ae3792289058ce80e5888ac", - "coinbase": false, - "hash": "feb7272a5da311ac9fda29a3e87d569ffd9c5c5083265b28c46f89ad849b0226", - "index": 12 - }, - "script": "483045022100b85d8b24bd1a9e490ae465256f16650227cdf170ea060b1664a1c50f2a70aa6102200b508e1adc32ab059dd85a69afe09c917ff5aeed653401b000fe928ce30158ad01210373b90042d0d240fece4bcb0e09f5d44709b905ec54094e6fd0bee2275b31048d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d47b3890f00d45df78e4b7243f42ba05e5de3329d235379712d93fb8a6588b7d", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 19600000, - "script": "76a9145052427fbc9cbc56067ef683f03517ef5acf189a88ac", - "coinbase": false, - "hash": "d47b3890f00d45df78e4b7243f42ba05e5de3329d235379712d93fb8a6588b7d", - "index": 8 - }, - "script": "4930460221008f9884e96c862e507611c8c0b0ed1263de25908d949950dbd5a936457332d7f1022100c4ffb8e888d78d25194b09becca6283dae2e4e3de61f747ec37daf2b74ead198014104d3e951433de2a3a0033ec7bc59a88f3d366b455f063eacaedc77ab1862d468c725f79c9535f95474e28b10fab24c853f2ffeda096a7267fa063abe33e791eb21", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 16 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 38800000, - "script": "76a91400511df6cb881a848cf0e693019ab053360c7a8388ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 16 - }, - "script": "483045022100c1e444ff5fbcc53d6391f01c44d5c786de29b53fc8276f27ca4d06683dd54034022040d729f1115b01a5e77193ff433994455bc56cd59002f946aaa0e75ce74cf222012103f16afe3a743f6eff12533fa155e4d20f83ca03862ccfbc3e6b3d86d6054d54a5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 20 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 9215977, - "script": "76a914b75a9972bac8e918ecff20835a07e613bafa180b88ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 20 - }, - "script": "493046022100f39d1ce431c1cb2d95bc60976703acae51b9ca83b20303f56f64c1af242a46b602210093f7507793fa0db4a950ecebb0da252d67b34d50db85621ed75ade3b13a0757d01410414ed552882b9700ea3aa600ff26ab24cbe488ebd3883711422acb71cf4b043c43f20f0d110cc52f463b8a3d17c6cd25786cbeebba365ed8aa9ca83badc66fa31", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5000000, - "script": "76a914791763eb9805371fc5d5bd92204538c1d54e333688ac" - }, - { - "value": 1000000, - "script": "76a9143ae23ec3757c3492d5fcf2fbddd4301b0400b08588ac" - }, - { - "value": 60000000, - "script": "76a9144ed84c242d2da0f2287282e3dc0a1a5c6fee1de988ac" - }, - { - "value": 55000000, - "script": "76a914ad82898dfd676b580d46571af64f4a22230277ee88ac" - }, - { - "value": 60000000, - "script": "76a9148615f34761543717b4b7abaeda7431bb7a06595888ac" - }, - { - "value": 56000000, - "script": "76a9140b13c2b8e46405bb1268e4185da05cbca1f448eb88ac" - }, - { - "value": 56000000, - "script": "76a91455191c5e137e7ac7a2af277152afd4d84e99546888ac" - }, - { - "value": 60000000, - "script": "76a91438b841186fbadbe6752e0b5da8fc342be6a523fa88ac" - }, - { - "value": 60000000, - "script": "76a9141543d67e917fe2b4c4c4c0b6c533ca4e705374dc88ac" - }, - { - "value": 45594604, - "script": "76a91444122fca944211bc10d67127b4fd46000a40770788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "36c30d565051fc52504406366cb54d219f1282d5e70e2253e23af6ab214c557d", - "witnessHash": "36c30d565051fc52504406366cb54d219f1282d5e70e2253e23af6ab214c557d", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 449, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "f16b182df687ef2959714c4abcf3224db293aac8cf107bc7cd9a0c5e31a75974", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300021, - "value": 13513336, - "script": "76a914e66c8767ba96c416e91ff59332473b3e8864ee1b88ac", - "coinbase": false, - "hash": "f16b182df687ef2959714c4abcf3224db293aac8cf107bc7cd9a0c5e31a75974", - "index": 7 - }, - "script": "493046022100cefec98a07fa712a531a2c9ea1df0099ea2235aefe7c57483d575f51a132ff2d022100b8d19ff4cbfc59fcb95f15ce545d260e7041250ceef8eef13faa2b0e119919b1012103cd4b4142e4124999fd1d1422fb9dcfe4c7042ee0b541cf45378f910b133b530f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 90000000, - "script": "76a914a9203622510960e6b670a8cf319e1633048967cb88ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 9 - }, - "script": "483045022100fdd83eb2bde64d04f0536a15a2a44cc3e9bbe29db9022df61c778d76c26dfa3202203164e0b20ad7b83538f6f2f46675c3ed27f2b691a6046a84fed879564273f7f501210313743281e26dca0ab310e376ab7081d1a1996105aa51ad3a8678854cdf201fa5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 30400000, - "script": "76a91493bf010ee52b745594411899d30d117037ac19e488ac", - "coinbase": false, - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 0 - }, - "script": "493046022100ebce8e6fde43217e4f8c3803f833c4723a530e16ac3938f7a616ef55b16f47e302210090b60cc342f0818de43d15dc5f651929672a012d608baf31c7ba9948959e9308012102b28d6d2f51bea96418dcf1decccb8544639b086b520d2934d609b51c6a4cfa47", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1022530, - "script": "76a914e0d1a909b8741db823b36236f83b53589641fada88ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 5 - }, - "script": "493046022100bf8780ddbf6998fd998cd89638185acefabf5b1d741e01a275d5ce794f3078d302210090076702e8b68c3d8e69bb33ae198f989eb13ba7b7d6860413f9e56c18942330014104906298631fa14bea3c875d9898b97c52a7904b0b8d84f763ba916a0a73150916d3d702cff27a5aa9f1e5810f0313c3e713fdf30ca9592c68f34203a4937e9e54", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 29563179, - "script": "76a914238c66df22023bfe1c5cd5aaea2734037fe9e02588ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 4 - }, - "script": "483045022100965cbba5732bfa904b25470c8da327a0f532330b33a3856e51a7754f62c8c79b02205c7bf6fdbb592d0d977b0d5eb70f72c26eb23cc9cc197569eb60d90fef646b53014104eec28b3ecd97d8401d55b72671dfd2bdb0da6bc282143a6ea3d3090d438a7f93981447c03f2eb130e135dbb47cb710cef47d6a8ce15cdc7f66b6532b5675191f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "index": 19 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8500000, - "script": "76a9147c5d112d87d2349a795733b2986d9878767d485588ac", - "coinbase": false, - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "index": 19 - }, - "script": "4930460221009addd85eb1e5ac44c397fd760b0746cf685937a195fa123eff79fb031a92fd1d022100a32597877176c7e42fdd833c695dc7b4f292d9c25787ab70a5646a16bd447701012102615f718760fb73741fcd6a4ae898537caae2f8b502e46d9ae66c4d6a14745b46", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fd6f2589734ef1bc573534ca7eec086c5e1eff21fa9417e690ef3dd18e4a7e54", - "index": 2 - }, - "coin": { - "version": 1, - "height": 298681, - "value": 20937513, - "script": "76a9148f92000d9a9786f69275811cd8476b534305f33e88ac", - "coinbase": false, - "hash": "fd6f2589734ef1bc573534ca7eec086c5e1eff21fa9417e690ef3dd18e4a7e54", - "index": 2 - }, - "script": "483045022100808b8da99af27fcb954e61ba0a48e4b82b2b3b10f76e63cc5a554b286742f5fc02200875985d23fed78cab3e2fa0ac11c0742cba0c2efc0c72d2a35f5b8eeda3447801410488f4a8f10e8b3c35a3f2fb3181cb57e1f725d17334c52dd852419da67a6d643d36903f9f22d12f05bf6c3f085c4de9e79bcb8933fbc6841e634de5360d105292", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 5 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 100000000, - "script": "76a914f46acae1d837d1162b1c0812d0220c79435c002888ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 5 - }, - "script": "483045022073ec11969171ae1b3c7094756756b5505bb5f99be058047ae4423f4b786096a4022100ea9fa099e738e2b9553b2d2d3272dd8920021e4eb516b3fa8d2f59ce2d1b35d1014104fb501c8dc58b1c44fd0470117dea1fbffc71ad8d03e45a37cac213609a33ffbd6fb2c4d66985af47871c09878bcc936b78bb89c14bf71c9e03909f2b2d6986ab", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8523400, - "script": "76a91496df68af3b1059d714db12f01bec6d5b095e42e888ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 8 - }, - "script": "483045022100c8887747b2f775400db53122e70a36b5e50380321aa2743c280593a45e0a46b5022059d21ba0d0aca6c37b3f5b942f165751c5d7d93004564fc289c746fd6c4822280121035fc959116fea5bbce94348d67fa4a0390827cf8eda70382dd0c3a9ff4070e6e7", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 37260000, - "script": "76a914bdfcf92b37668c98d2b2213ada9d012b23ef779088ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 6 - }, - "script": "4930460221009ea226de1997003887a2ec08b4f9df2fcc5c45a4ef9e23430cbbfc6314ba21e9022100c93bdec96d8f9fd23525b5b0243d60562ebe3288bcce3122d28ded956e94e1fa012102bf01ef81ae1a41b9561dee3d6e80439d0937ab69a70a7f0dcd9a48740e7c17a9", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 18 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 38543800, - "script": "76a914ecc110ad72fccd59fe90f5926f68b4ae8dde5ca088ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 18 - }, - "script": "4830450221009965decda6426da2886a7720e0b552fdeaa121257f81edc886eda353bb975755022018695ee280dbd4a425269141f139ad9b7015161bb4acf44482e3003590e5abef012102b846755c1a54dc52736bd62ec025988208f0c800fb88905b724c7ca5c44a0cd1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 7 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 36581760, - "script": "76a9143875ff5ebdf12a90068447360c865a438881a45e88ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 7 - }, - "script": "47304402205e8de151556f19a8e076de728e075e3d4debe736b1f3653da341be26030545840220064cef7206a393c3cb0a83ec0254bb4a42a27a7822800b79247dcbc440103597012103a65f1da344744e46a2c3cc7bec130454f707903ed8649d0db366b8a351b20d5e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 8 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 90000000, - "script": "76a9149b5cfe149635f3ac54f3b30b9caae8c0eb14944f88ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 8 - }, - "script": "493046022100f53d82c50840f19c217bc7dd199587287b9a8560af72a18debd9bd630481b3bc022100c5009c40e8a1008a329fccbbea9084ca128acaab9e281cf2039212aedb533c15014104a08f2620c85842db196797a4f5b7440603f7b25f9db09622f27f5f4d7b6e7400f264d2f76767e1cbde526a818ec3343327c4f0c8d2943b251fac0535df19b1bd", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b6c73b487847f9f23716dd4aa37572d0ef33a061e5763a5277dafc1e09c0804a", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 9386000, - "script": "76a914302156db68abb60aeb24390e7b0f3582ede0585588ac", - "coinbase": false, - "hash": "b6c73b487847f9f23716dd4aa37572d0ef33a061e5763a5277dafc1e09c0804a", - "index": 11 - }, - "script": "47304402205e7da7afad3d19cf57fded1ff1b40b78f31e8e2012439c2346a8cb0f0e9cccff02201274eb2359ed9d7022e3cf2f391c38e174b681baa4fe5b295881b4dc1080ad69014104c81fcdd400e947543a41e5a480695ad769d5b7aa51ac36ad458cf6d8ce78516673b3ed0d30c390bed0bb4978b98453f1b5dd441d7c4698dba2d8f36b9a35a366", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "810bf5b04f992908f43e29548f9c44f568d673854b63ef3aa474f29550474c3e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5000000, - "script": "76a914791763eb9805371fc5d5bd92204538c1d54e333688ac", - "coinbase": false, - "hash": "810bf5b04f992908f43e29548f9c44f568d673854b63ef3aa474f29550474c3e", - "index": 0 - }, - "script": "493046022100a0ad392174f9c5adaebf7206f95e5505550f8a95e4b8d792362e0643b9a3899a022100e288d28c62650e77add3e11fd8d915168310fe411d9be220c87fb071dbe73485012103c60f4a12b7403438f7ad4473991bb5859f1752a7851b736ecf5e1de03e5fb7e5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 8900000, - "script": "76a914888bf0a6d73bcc2d5ffc9c5e275dae072d34817688ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 6 - }, - "script": "483045022100ee4702cb54c33bd56e3878b26c6b100bc2c45e5a639ae12966f6552c36fe337a02203e6d6bc34f83537a30479086e8c77d1343846d74d528aa7b79a761c6a412be130121033896ea84e5d7463d6f40e2ae8e30da1e6ed1ea9c819c16244db0d6fda0d76d7b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 37100000, - "script": "76a914f224ff71fd9fdc07e1dc7cbd8e39b4c03a5f7d9e88ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 11 - }, - "script": "48304502200631c65f5285e743643baa896147205fd583a496c3bc26d96ca71fbdd86d116c022100d6776231524afa90856209ca01994ec7cd209a6d50fc472fdac5328673e2e6af0141045fa2715eacd61422d4f4e5615f6cbaf32e13eb7fb57cc15daa8f2b66989165fbba4a4284b760e4ff58770166bd53e8ea9fdedae4693bff980ed9a9592d02850d", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8559151, - "script": "76a914bb5a3ec420c2cab2ef166f4c1fddeb5f6fd287db88ac", - "coinbase": false, - "hash": "b4c414b9acb15bca04f8ae614f79f547dfd82340e9651b22943342bb3628d7ef", - "index": 3 - }, - "script": "483045022013dfb2bf8dc60ac810b44bb418326695ce21516fd37f29e12b1b9af4b8fbb8e3022100aa067b05e3da7f93d66fbaab5e6054bf90f169c6313d929106db15e6a7cbec55012102cba1e742c4ddb77ae6653e94af3c0ed15d0710b53b35cdffa18a0d52afe8ed98", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 90000000, - "script": "76a9148c1e72166efebecab3f386e1885e3e81339c4cb288ac", - "coinbase": false, - "hash": "dc5ace8e7ef7536e034324c8e7949afb45492a52c16b3846722a2909decb378a", - "index": 0 - }, - "script": "4730440220746d8e2799918672c6a8d93b661accd54d621ccfebb8e1c457f39951c7339be202200f8433a5aacf9d211e9b493865b1ffea29d82a1ab51c03d4419f571fb445a60201410412d9073ff42f2cef8d7dcd8be6670186893d19aec09814f1342e543754b14e55bb74c17122c1208f0709f3c7f79140955ae62608d2cb346f06604a09008f7f64", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3ec3fb41cdd0e73a874937cac5c6ff8051f63fcab0bcc6b2da709aae0f270f36", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299962, - "value": 82614000, - "script": "76a9143fed5f5d39aa1a0cc2335da20990ce5b3c57f4b088ac", - "coinbase": false, - "hash": "3ec3fb41cdd0e73a874937cac5c6ff8051f63fcab0bcc6b2da709aae0f270f36", - "index": 0 - }, - "script": "48304502207751632760ec05d0ab9d417d9e5276775bcb4c5ebfe9860aef1d607fdb6440af022100e945a67b9eacb1f217efd6231886f043fdac37badb2ec019cf1a7ef236e50496014104f5ecd36d517b5b315b5c308bbf8bfe9e43210cba48a2332035dd0efb90dec749315db967c3e5cf51e04dbe0c78a6f08711d64d9edb66c6e2ddce892163058375", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 36865281, - "script": "76a914151d619ec4edadcdf45afbba2b3328257169a8c088ac", - "coinbase": false, - "hash": "e7711581f7f9028f8f8b915fa0ddb091baade88036bf6f309e2d802043c3231d", - "index": 14 - }, - "script": "483045022100f5687bd88f8f28bcb0740d02f9048b7e30a5a541a2a8c579ef0f220a7aebe3d1022052c19db331c8f52d0b2977dab4d63154a5b4684980b09a10a6e36b1e6245064c01210356cb0220b3717d45df10c6519a84ef3de1097a0b633d722381bc64dc720bdeb3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5a157495174c5de62732d2da13f00e6090848d8e063b1e3aa57c4c6c5e1e343e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 9300000, - "script": "76a91470813e1f240cd703029c177c7a8558aeaf360d4988ac", - "coinbase": false, - "hash": "5a157495174c5de62732d2da13f00e6090848d8e063b1e3aa57c4c6c5e1e343e", - "index": 1 - }, - "script": "48304502206a5254a8a18dddc19375d5c1c7a85ab2a32356f9acb0edc5388308fb1fd124b602210090b66926a5680dcbbb0d191537895ef2a2265c9eced133b78ae700fe99d6d8bd0121025281c2168599d6cc96f03154c5db7fff92128d1cc938c5ba3ba5e70cc3b1b4fc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a4e1eff4f0b59e1106878a918dc7954a3f254864e3fbf4065fc0437488747c4e", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300006, - "value": 13500000, - "script": "76a9147eb45eff2e992e36e2b571fcd78647631844a02188ac", - "coinbase": false, - "hash": "a4e1eff4f0b59e1106878a918dc7954a3f254864e3fbf4065fc0437488747c4e", - "index": 3 - }, - "script": "493046022100e7270f47be28ad8524ed69fa5e9f8b2b5dabf8ab98277d422f52af0a636be6ca0221009e3b0c31e29ab4f3c250d16cd63cdfa3f90a2a09cab65d1cf5b8869f2d96963a012102a5f560b6979b5f3b8013375e934de12bd53a72003a740f8c7bab9f8b657c9e44", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "810bf5b04f992908f43e29548f9c44f568d673854b63ef3aa474f29550474c3e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1000000, - "script": "76a9143ae23ec3757c3492d5fcf2fbddd4301b0400b08588ac", - "coinbase": false, - "hash": "810bf5b04f992908f43e29548f9c44f568d673854b63ef3aa474f29550474c3e", - "index": 1 - }, - "script": "473044022012df913d0cb1b86749308ad1b8ab298d9f43f511070608c5e2cda14ac2503f5f022070d826e5da5a5ad1a1dd34ec927f5532d69400883b4275c57eadd80fac5a777001210380f15d7ec8e488c7e532ae04af43ffcbb59703dae84734f6daffdb09d09541bc", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7f1ba2c5711674ce416a129fa95690cdccefa83b0c925a991369a6b9427ddc4f", - "index": 11 - }, - "coin": { - "version": 1, - "height": 300012, - "value": 13490000, - "script": "76a9143ab3a450c722e069ce515ae21e3a5701546869aa88ac", - "coinbase": false, - "hash": "7f1ba2c5711674ce416a129fa95690cdccefa83b0c925a991369a6b9427ddc4f", - "index": 11 - }, - "script": "48304502200ddac38b4eef2eb0c8e8b6f8dc9a198bf38167004f14fe10e9c8744240fbb7240221009a60d549749548a28519119e4e78f040f5dfb5c9bb6bc9eb36cb7c693f1aead3014104e4b8651057276dd6457a339fc64f94d6b23043bca87a280e1d9db7798c7a1a25edcbbf026e30f48f02ca23d5e903859912fee6d62c92ba13c0dbd599fe942521", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 2 - }, - "coin": { - "version": 1, - "height": 300015, - "value": 36820000, - "script": "76a914ac5bb7dcfbab66311b2524ffb714ee61cf99449488ac", - "coinbase": false, - "hash": "d585c42ee012736f3641c8dc661d46330721d628bf8a62dcd24eb3738fb61444", - "index": 2 - }, - "script": "483045022040f0b4b57e46cd5bf93655eb7d104e5516ed97935b6ac59c43f120a2f5a3d5d4022100df7bfdb064b3f7ac6e594d7f05cc595de87523687d0af00839e42bde6f67387b01210391d809388c525211444d5ca2dae844e332f2e8c73c86b16415f0f0f61b9c7d41", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 27700000, - "script": "76a91428621a29e7ce9fc5623ba19ba14a1428e534f0d388ac", - "coinbase": false, - "hash": "b564c7578da0c68f1ab71b717e509d16950973a2d39b05a71bf37915f20a6ff7", - "index": 9 - }, - "script": "483045022100b1789d8b38acafc3ef70553e9b6bce55765d56d4c4747d6401512758111983dc02201d4f8acaf8b00a5acfa3426c0b05ae7e0558674ea2294853d8c42666c37c98990121033af1b0c28e9b2bebb64b7250a8cbc31dbb5acedac29d95d48318e12019aa11aa", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 7835759, - "script": "76a9146ebe530bfa83507b0be8c4d48c5cf49d427290cd88ac", - "coinbase": false, - "hash": "b6118f48fa46fa21a08ac0a4ccd47cb051ac6f88e127c596a901f06fb109116f", - "index": 15 - }, - "script": "48304502210083eaf8e412aec9552640d8835c3c38c0c6c8a85f6787c6310746f70fb2f3d76102205d924ed5e36f6dcf3c7254afcb15bb5d262d1334ad8b148e69f42f9edef67b050141045967d2db01391b67e80c42a8a8114446ca1cc364b41e2bf93c5513e84824ee9c24521eb729eec6b04c8707449b27cd521b1d1c586ee5021754d9e97fa6d87f00", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8128000, - "script": "76a9144b62eeb2be03d1e7d7e3e07c8b8566af9c01172b88ac" - }, - { - "value": 94485330, - "script": "76a9145aa4d8f0be1fc1a2669bdbe5d9b20ee8911877cf88ac" - }, - { - "value": 94945600, - "script": "76a9149a346cf86b5d83454919114d491caf434f9203c588ac" - }, - { - "value": 3834118, - "script": "76a914bc3fd3e093bd28ccc0214e02c12d95b2cc69ec7988ac" - }, - { - "value": 8550000, - "script": "76a9148e3cfd05cb70010539c23803e4009f0d09f7b86e88ac" - }, - { - "value": 9016183, - "script": "76a91456c0ec44f6ecd461487af2ad4bd462f2d86ce1b388ac" - }, - { - "value": 8555913, - "script": "76a914ba26460478473f1fb2fbd6f31f71da4c8a404f8288ac" - }, - { - "value": 94308997, - "script": "76a91404f1eb215fd9f99dbdc1ee70b98ab0b8aafd635988ac" - }, - { - "value": 9370690, - "script": "76a9146ac8ccba25d09b619f08adcb78a0a859714ff03a88ac" - }, - { - "value": 9192516, - "script": "76a914c6255cef71333ba1c390e48e81c6f1d73ea43b5a88ac" - }, - { - "value": 8931320, - "script": "76a914b294e9bd49951141ef0120991b02c1f0ecf2fb3a88ac" - }, - { - "value": 9027208, - "script": "76a9146b8d9f13cbc7d45171e0027dc44983d0bc9d2ffb88ac" - }, - { - "value": 9203953, - "script": "76a914d2ac9d49ad251b4897d979c3c1edd81271f79e3888ac" - }, - { - "value": 94951513, - "script": "76a914f06a4daef1b0bcc05b1d9af35b37949d594248a788ac" - }, - { - "value": 8322000, - "script": "76a9141ad0884bb771d4ac4c41cfd8d8bd2c87d32f2e4c88ac" - }, - { - "value": 94570190, - "script": "76a914ac5b8fac6ad0de39e5c99aff9a8a74040028b3dd88ac" - }, - { - "value": 94474305, - "script": "76a914d88c81921f142497048938b28df743b5921dddcb88ac" - }, - { - "value": 8978500, - "script": "76a914a26b08dc36287c3156da453adca5827e75f7233a88ac" - }, - { - "value": 8629700, - "script": "76a914713c033a0416661c316897cb7fef513d4e411e5888ac" - }, - { - "value": 8250600, - "script": "76a91464504bb70d6f950fea2e896aac5c055fb1935c6188ac" - }, - { - "value": 94297560, - "script": "76a9144442c101e7ec022458b3691c0d096854b3937c9188ac" - }, - { - "value": 8985256, - "script": "76a9149e21da9681b0d479e90cfb493db803c8eedb632688ac" - }, - { - "value": 94516257, - "script": "76a914f09a7be64a39146a4cfbb97451a5f39ebe48656d88ac" - }, - { - "value": 9330000, - "script": "76a914523c051d4c11d65c0c8394b50b7d10f976ad012988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "c1b759121d09b36f190f34d60a86fcdacb5b7ed4560b393c4e248a1f6ab2b638", - "witnessHash": "c1b759121d09b36f190f34d60a86fcdacb5b7ed4560b393c4e248a1f6ab2b638", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 450, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "2f637d397e7a7f475b31d7cbac564ffc52ff7a2e826590c1a07b67c863e819dc", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300000, - "value": 9400000, - "script": "76a914655226afad30d329371f8d00b44860f493f180ef88ac", - "coinbase": false, - "hash": "2f637d397e7a7f475b31d7cbac564ffc52ff7a2e826590c1a07b67c863e819dc", - "index": 6 - }, - "script": "4730440220566f4f3f7ccbc7f5c4d4aa80566b6e5d9bc87fd85880629ba9dc1f97d9f2bb09022049b9b9f1099cbb3f4604411f0af1c8c50929e14a3a2d8fadc9178890c92c98a20141045ded8abe2aa662df92aa66b247b5bcfed9e88fe4b3ddf3b7c2db749285392fe5e8338ccc8faecf21dc1219e2af599630621eb091ba6e2b6693621f41f19a29f5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8890000, - "script": "76a914aac08dc7e30698aedcaaab4715a66c032932717788ac", - "coinbase": false, - "hash": "2131827f1edc2c578f63e5529ae5c19af045f1ae059e0eee58fafed22a3c9846", - "index": 12 - }, - "script": "48304502204a23a83d03c3dd75a9f7a2e369e93fd25e0afe19710acfb19b5d9a2c46f762a002210085ee67b1a43e1a93f817ed306e28afbbdd3dc03de20dc91fb52cee9f46b66d8701410457363cf1468a6913f4ea39f12cd670149a0701efe64f574e5acaecaa79c59166d5c5f78e61b8033b83753e1b8a88293d9e1f6fb6b6291c3166a096ba9f388ba4", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "589905e1dfbc57726aea8a801cfb17ccfa96232b3b43e2829aaba94e7e116582", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 9430000, - "script": "76a914699224e28922439db7ce6aa95087a0d1fe408bcd88ac", - "coinbase": false, - "hash": "589905e1dfbc57726aea8a801cfb17ccfa96232b3b43e2829aaba94e7e116582", - "index": 12 - }, - "script": "493046022100e1d7cf0fd68b3315b0f6346cff847b9bcdb0b080779086202dba14c58fbbe618022100bd8f7cb078ffa0f914cecf4bffc8a142585657897d046a7409a83e6bf6adf85c014104321a3bedf530da04b6bd6f56b8d4113fa61389576936038538a76b973811a539d0f809aedba74c641433abde82cbfd64104d5d9042801558c93dccbabadc6a63", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 9393900, - "script": "76a9143bd588b3f977087fca1c0ee4fe09eb2c6c3ec87b88ac", - "coinbase": false, - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 13 - }, - "script": "47304402207c58aa59241fd1ccc3faa49024c696092f44cc444053d162dcf303f14d46dd360220531e4f2bba40cf7b9308f8663f6758f6b20c181f06f5942856ad51d61cd71cfe01410492934785015dac92b26dbf1676ad964d0d8b663ac7758e615e3725cf35f7d603ae36bc794bfe7910b04977a63289fcbc3859c549e9b7477833a3fb57137ef488", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3d8bc0d32be4aad90d55a0de69ebe35606d1f5309a04a6ebc5cd460cdc1e705c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300010, - "value": 9927003, - "script": "76a914ba41987a903f959d2de3d2078594c7cf08f881f788ac", - "coinbase": false, - "hash": "3d8bc0d32be4aad90d55a0de69ebe35606d1f5309a04a6ebc5cd460cdc1e705c", - "index": 0 - }, - "script": "483045022063dfb505abf370433defcf8687cc1fa749ae5138e91961dda881cd9d7fce0fe7022100d7fa5f97f90411d01b9ef32e0886bcd63a93c935078b701b746efdf0fa71f68b0121028dcb75fcb1adbff78a1d01aae3d97c9a67e1f44233c71106d343a12bde28761f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "index": 14 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8904200, - "script": "76a914254c7a2b7ccf21a1d695d24559e4e10c8e78817a88ac", - "coinbase": false, - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "index": 14 - }, - "script": "473044022000b812ca523a39f8432ab57117bdd70de41e4d626e86a6b080fce8712dc75b7e0220163132570bad4353fe0cfe8dfcec2019beb0a5cd155370c273166cf6e3861ea201210270167d6f017e9844ac50a6ee3ad2f3c965f86a5f2ae536da59c2696f79789947", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8665800, - "script": "76a914fe0f4a1bf09cabbbe8b67e3ce3e5216a799a680888ac", - "coinbase": false, - "hash": "39be4c5fbfddfe532179f47509f9c1a76fcc3778904114592fc5fe1206f1fbe2", - "index": 13 - }, - "script": "493046022100a760dd953a71133e47ac807afaf4d6ac331e31cd6ac39db7822a8ae969b7ebb2022100ad36d8b0d45030ba37b70c238d3164e7058c6a43b5bf93920f5a30fb55d7d29f012103b5adfa235849f84afbc02097099670f417f7a29ab475fb09ef5d6b3a03f516ad", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8891670, - "script": "76a91473f9526707d3d4ca945e28a9dff924e79050b1cf88ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 0 - }, - "script": "4930460221009e09f8ed845c89dfe2a098a036b606f851a92fdb60e77b0baa732640caf251f80221008d1fd58540dc90135b6e110d4c8f6adbdfad992d98fc6e0324324d38db96804c012102e904b5bd0d05fd5ce17f16a2090dae522a329418c1024a2c3020d38ce4d79c1e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 9 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8610000, - "script": "76a914848051d8c354909f2391cbbbfb82e9342188e2b288ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 9 - }, - "script": "483045022100c7d6366025e4fc314ba90464d8922866972d88f6ef18f7aa484d5078e03e6c1802207cf711fc7fb42821cbff6f04a5407a5d7e63836a278d457ba70db47dba14357e014104abb7facaa49b9d4c244da027bd744accea7391bd7fa7f43511ce77e8bc2046cc7d61bf67a3b3110665866aec527d2dc2b3b0514294cd8611044027f81bf8073a", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "36c30d565051fc52504406366cb54d219f1282d5e70e2253e23af6ab214c557d", - "index": 3 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 3834118, - "script": "76a914bc3fd3e093bd28ccc0214e02c12d95b2cc69ec7988ac", - "coinbase": false, - "hash": "36c30d565051fc52504406366cb54d219f1282d5e70e2253e23af6ab214c557d", - "index": 3 - }, - "script": "483045022100ac3449886974572a2d65941120f5ce44bfa9919e38d6bba161b833a62b5f14af0220234a3922354730e003b4fc15ed96196a1a8cbd685275e1e2f2b66f44aa936b94014104bb8a6a2beda4ae4153b30d5c67549c54fb88b506280bc04be1f8e3aad3c9e4cee477f03545ef04c04f3c7fac56b555a8c86f904c986604eb7390f5737f27e930", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 10 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8920000, - "script": "76a914e23ce96401f5583571dfaac21488cf4770cb999c88ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 10 - }, - "script": "48304502210097be3ef7e8aada8658d1d621e964b3aa61a7c4945e18671655761c0fc774937202203b6800885abe3e5cfb6c1bf1c362518ca2fc61f924272e6340002d5e552e80400141047170e96c720c8178047cbdf29aa1881ef164b73b67337b108cca4a1ac7aa883532e3d27d4af82fa85344544802036dc067b394a9c033f76fddb5cebc9a692f7e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "36c30d565051fc52504406366cb54d219f1282d5e70e2253e23af6ab214c557d", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8550000, - "script": "76a9148e3cfd05cb70010539c23803e4009f0d09f7b86e88ac", - "coinbase": false, - "hash": "36c30d565051fc52504406366cb54d219f1282d5e70e2253e23af6ab214c557d", - "index": 4 - }, - "script": "473044022000b5f89682b72532b3826f2f6f82a72a94951074bc88e49986e826f2bf6becbb0220433f8df9f24d9a999adda7047d908a4b2ea541e605dd22e5e31fb6ff74dd5047014104984dd87cf5ea98849bc56c3e92b846ff9b68664eaeadb1cefab3b4565de54e312a751aaaa9bea98f2ab43e83993fcf8dcc87017553caa2ed7f124edc0c9c7488", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 6 - }, - "coin": { - "version": 1, - "height": 300005, - "value": 9441000, - "script": "76a914cce7c92ad196a831e139b1ef77384695551a9d4688ac", - "coinbase": false, - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 6 - }, - "script": "483045022100e0b95596973484751e66b5a1f508474e04b3c1b5be42a092d66e5b823e36379002202ab53881251fb16ce98fa29b824120c762cb0beddb31074b30792bd5d9b6c627012103ced99cd03f47fccba4c566514b86d33c7dfdccf06fbd304027d93a25af862276", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 17 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8755810, - "script": "76a914ded117e600c9ed41be1637125b45a7bf4918818488ac", - "coinbase": false, - "hash": "ed29ed3a5ae474015b4ed1875a43acb767f68ed274b5cc64404364f737d02bca", - "index": 17 - }, - "script": "483045022100a6801d5aeca890c1c071a2586cd7095056c8ad557a44748075251e03e7b8ad3202202a5a8838b5257488de7db7de34fd458e52c4a0fb214f9ec423a454b042a4b8d1012103ee6d22880517de747467f1c5ae8e9f90f97ce02113addc7c0f9e7b434256ef57", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 8700000, - "script": "76a9146d3084a29be8e56ed65f828219ec0207172a8db888ac", - "coinbase": false, - "hash": "d69c66fad04a28f68398c16251b7eddeac01ee13471d17cc4260cdd2ecd83678", - "index": 1 - }, - "script": "4930460221009e8e83b5a8143948407faf5292af6a211fc64ac144f3197f480f2a2c1f267182022100aac5fc0c701db8c7a2a47a78a49722d6b0c33a94dd7dd131d517af80067399700121021cbe3461085feda4a6ec70b27fbbcaf5ad2d1dc850ba475addc98df520e05430", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4d301d92c7b7f47b1e2d8695fcd8c6751ad225166e71b4d96e7a0eef9bcca6b9", - "index": 4 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 9430000, - "script": "76a914b3935c5cfd20e9aec1e63e5b094ea4c0aeb3bf6e88ac", - "coinbase": false, - "hash": "4d301d92c7b7f47b1e2d8695fcd8c6751ad225166e71b4d96e7a0eef9bcca6b9", - "index": 4 - }, - "script": "483045022076e1a97d351f83e7385e1ea6839353e7403f3f01473877b6ca8cd95bd204eed20221008bdafeee92713d521013dec8b311ead492e8d752007249e6428a43cbe85395fd014104b112142efe049ca8d34ec6d3c5069860f6c8ecefe66c9b6cf7e8f088ec7c33fc524601956224994cbf90fd3f0883c09694b5eeca80ebfc25485751f90bb88580", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 15 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 9388100, - "script": "76a914da873855b7cd724638f3cda8f8f882165d199f6188ac", - "coinbase": false, - "hash": "a1d1f01f47b25c7d0fd20859f5827049c2ff3f286f6c33c67b9313c7c8e70a1c", - "index": 15 - }, - "script": "493046022100e80bf3d7a02f6a988ffd9cbcac2e204201c80c7a8e7dc0175c6c95dad29ea83d022100f55e332f8a62762da082aa2b6b19c4c069c368e2e83bea0ccd7493974b275414014104e67dcd0ce7fc404699b93e220b4b954c8447b93362799699018941246d94c11e373be7137a133740d822b829bf278d3efe238150dab8458259365eabc2767ef3", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 13 - }, - "coin": { - "version": 1, - "height": 300005, - "value": 9425500, - "script": "76a914bac12ead918508f226ae799e144154d59bdff03988ac", - "coinbase": false, - "hash": "18e353c000289be6318d719bc50852f153b91386e8356e9aac60fb81ea3ac643", - "index": 13 - }, - "script": "48304502210084561df0515dc44d5b8eb364ccd7a4cc188d0e7cb2c537a40a4bd9f8e8a1f09902205a17ba80e2cd3d9fada0cdd2602ca745eb4f7e373ede3ef9a2384296bf0ef1a00121039da94091993afc58605ddc5dd6f7734ffc0d2d687911216fdebf34fe7132b074", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "26827ec25546928dd995abcbf54b4b045509cd38dc417004698aac6fa127aeaa", - "index": 12 - }, - "coin": { - "version": 1, - "height": 300004, - "value": 9390000, - "script": "76a9148dacb0c284a9c9011b8d7cecc433f1e1fb97457188ac", - "coinbase": false, - "hash": "26827ec25546928dd995abcbf54b4b045509cd38dc417004698aac6fa127aeaa", - "index": 12 - }, - "script": "493046022100b4be4860c799df2d45fa053307b4ed1715017fcb2f22b99886eb5111bd127a540221008ce240dce95c8ef383dc539e833da5edc8326c77f7d5cf4dd44614bcb54d830d012103bfe155d769a5f5b215e6c7efeab9a5b046f477ea540998eba61d55dd28d7c804", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3824118, - "script": "76a914941648232a0a880eb9cc606a408751d34f5305de88ac" - }, - { - "value": 8972983, - "script": "76a914c12ecf27182ff7688643788d0a26d5d8785257eb88ac" - }, - { - "value": 9000000, - "script": "76a9145914a5020347b3b748688fe922a04bd3ae3cb7b388ac" - }, - { - "value": 9000000, - "script": "76a91465e15b1ad1edcf474a30415c88a72c75243e0bf088ac" - }, - { - "value": 8900000, - "script": "76a914c89d24e4466fdd585704825dcb1c28ec81fcf53588ac" - }, - { - "value": 10000000, - "script": "76a914e09338ce14ae34199ff0506fc0b9621f4e58d31988ac" - }, - { - "value": 9000000, - "script": "76a9141b3d67d86a7b55b00b7ee9c2a56413e6af220af488ac" - }, - { - "value": 10000000, - "script": "76a914ed4ebf61763643ee274657692fde0fa3c86d2e0388ac" - }, - { - "value": 500000, - "script": "76a914487ed1900678211d2bcca4e9d75056894336541088ac" - }, - { - "value": 9000000, - "script": "76a9145295e67da06250eba0041907a4299f3e45feee5888ac" - }, - { - "value": 8900000, - "script": "76a914e1a289322ba6bc2ab5e4ad73c724a86c8837dfca88ac" - }, - { - "value": 9500000, - "script": "76a914ac1229bccc7deab455b8fd844fe274740d50ae0488ac" - }, - { - "value": 9000000, - "script": "76a914cc4bc8e1700d142e00e3e4080a32d07857ce369c88ac" - }, - { - "value": 9000000, - "script": "76a9147e39237401a3948d2e5d85735a7d9fc832fcdcef88ac" - }, - { - "value": 9000000, - "script": "76a9146946e7d459aac715749b1a069ef596de262491e888ac" - }, - { - "value": 9000000, - "script": "76a914b82391f2e0ca700d4962be3070e7af605443b01588ac" - }, - { - "value": 8900000, - "script": "76a91419b6a2dbf2284adc88806dc104431922f50d8c2588ac" - }, - { - "value": 9000000, - "script": "76a914cc6417cde4f3fd78c1dd133c9a55f25469378c3988ac" - }, - { - "value": 8900000, - "script": "76a9146f194ae6212dcedf8844471aa3fe7e25955dd08988ac" - }, - { - "value": 8500000, - "script": "76a914c150f31e5bb5704bdcffa692f11f1a91f4a8ff9688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ecfdab638152d74b1f104519ac6cf7df675fb4e89e33b63983af979657e82b7c", - "witnessHash": "ecfdab638152d74b1f104519ac6cf7df675fb4e89e33b63983af979657e82b7c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 451, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "9c19aac9e2141c50c29be235da1911b65509a4743b5b0fef6e0d3cfcc5472374", - "index": 42 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 107644161, - "script": "76a9149bf2beecd50f745877c20fd07f48e28f153331a388ac", - "coinbase": false, - "hash": "9c19aac9e2141c50c29be235da1911b65509a4743b5b0fef6e0d3cfcc5472374", - "index": 42 - }, - "script": "4830450220756b1a8fc2260a4320ea4129c8f0383aa4ca1f4dbe59fdfacdbee01128a1ec58022100874ddf0ee79a736529faa4d0faec2961052d4fb8f20b0e6f9a1d372a29e4a84e012102682feb79761d9851996f626b61794dee5670cd11f05c195e19cc9103849b67a4", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9635, - "script": "76a914be7c150acd020d354c9f6b3d430ac25a68286d4f88ac" - }, - { - "value": 7297, - "script": "76a914b0d9ea091f8cd2b6e77f0d19a4d7546b35ccbd2188ac" - }, - { - "value": 7444, - "script": "76a914a07a6f555290f1a9ab4a215862fe80bb3ebea6e988ac" - }, - { - "value": 7170, - "script": "76a914a1cf9b389c64050f338baa45873392c28e70c94388ac" - }, - { - "value": 7421, - "script": "76a914b1825c8f0ea6b95dbfb30b3c805589135235e5d688ac" - }, - { - "value": 6960, - "script": "76a914a1b68c5d49d475fba648bc41eefd43a7bb31829088ac" - }, - { - "value": 7402, - "script": "76a9144027ba767b9824c6eaa7a0e53dfd859c4ebc72c288ac" - }, - { - "value": 6737, - "script": "76a914b802c7f4a92399a03789b9dbcf0f8051707a7b9d88ac" - }, - { - "value": 6641, - "script": "76a914cfd0ec4caa74229896c4763d8ba760b4b29cc04d88ac" - }, - { - "value": 6640, - "script": "76a914e96f4690ed48ae32c4e72f582fa11cefb05bf48188ac" - }, - { - "value": 6594, - "script": "76a914e77875aac55d82adca0a6c5700925f08a43a62fe88ac" - }, - { - "value": 6577, - "script": "76a914b124f8413ed057ea7539def5f308ccfd869175f488ac" - }, - { - "value": 6576, - "script": "76a9143b5ae0170daea946ff0d75497eea640af7dea43e88ac" - }, - { - "value": 6560, - "script": "76a914447d5eab382953f80762bdf5e05b7609e0a4aafd88ac" - }, - { - "value": 6560, - "script": "76a91458414e9bd95492d5805c02596437994c55f8b09188ac" - }, - { - "value": 6496, - "script": "76a914b0b31a330127bb3c55b2d185a1e72d5ce4c03a5488ac" - }, - { - "value": 6433, - "script": "76a91417e0ede2815e4a4e73e2e1dc12b5c9512028f07988ac" - }, - { - "value": 6656, - "script": "76a9148051ef480170f5e737bdd31604bcbbfd61ab4fe088ac" - }, - { - "value": 6562, - "script": "76a914b853219eb28e67d839fa0251821548171e5b6ee788ac" - }, - { - "value": 6556, - "script": "76a91438dc8a104f7ee62be2f2e6e73ec3005a211c28cb88ac" - }, - { - "value": 107305819, - "script": "76a914ed23a91a4e082274fedfbe78cc9516811916440788ac" - }, - { - "value": 6434, - "script": "76a9146b62c92196cece151dbcda573b76314278815dd688ac" - }, - { - "value": 6434, - "script": "76a914fff5cacea9fd28f1f047e92f924186f343a47d4e88ac" - }, - { - "value": 6320, - "script": "76a914ea4efe4e01a3cde7a4d82a9c3bd74adf7bead8e488ac" - }, - { - "value": 6291, - "script": "76a9149aa262b4284e6eea7630dc945ff33acd1c2ae9ce88ac" - }, - { - "value": 6401, - "script": "76a9144e9138ca469dcced698c9b8f0fa037d28857532f88ac" - }, - { - "value": 6481, - "script": "76a91492c30a2903d493b143feeb63480bf966a0e204ec88ac" - }, - { - "value": 6219, - "script": "76a9145eb56ad59aae0e4b6d01ea1f76a951d622cbce1688ac" - }, - { - "value": 6195, - "script": "76a9143ed8007a26f7edcc2d9b3fecb2e95eda362acb7a88ac" - }, - { - "value": 6195, - "script": "76a914db6b4b323967e5eb0fb8d3b8138a7ccaa642e6c788ac" - }, - { - "value": 6671, - "script": "76a9148973dcd9e68f5d8b65529be89fb67204616b195f88ac" - }, - { - "value": 6161, - "script": "76a914806f29e273188b1b2c7c945526c58600896274f888ac" - }, - { - "value": 6131, - "script": "76a9147fb7fffb5bd54407ce796e8f4c267a9242cb889588ac" - }, - { - "value": 6131, - "script": "76a91445c58cc58967052e94e575838b82a03905b5ea8f88ac" - }, - { - "value": 6131, - "script": "76a91411274fd48a37174832afa04124e94e74535750da88ac" - }, - { - "value": 6210, - "script": "76a914aef67a5b7a22f38f78953f7d18e12ea8bb0b3ecc88ac" - }, - { - "value": 6115, - "script": "76a9148ce93cbffe228ee77fde18cbb1d5171ce608132488ac" - }, - { - "value": 6097, - "script": "76a914188648854c683901dab9b5e634aa0177bc2f744288ac" - }, - { - "value": 6097, - "script": "76a9143a03b74ee6aa11ce8db776697cdc2552d97bdeef88ac" - }, - { - "value": 6256, - "script": "76a914e0100653de4558084138109d3d9d147ee0f8810f88ac" - }, - { - "value": 6081, - "script": "76a91456f3d996274a06059161d3e518a7de036ee9486f88ac" - }, - { - "value": 6080, - "script": "76a914368de10f14c03e348b0eb2d319391285d8d7546288ac" - }, - { - "value": 6053, - "script": "76a914d2b5fbc2120b9fe285219da5e46731fb997a097088ac" - }, - { - "value": 6035, - "script": "76a914e1febcf8cf2a98c75aae0f93212d3854f3a3e4f788ac" - }, - { - "value": 6032, - "script": "76a914e6a58fd398cfbb02ec18ee88fcef108fe33fb27288ac" - }, - { - "value": 6008, - "script": "76a9148a41c5a6e31f5b6259a110bd909e2ae13463442088ac" - }, - { - "value": 6003, - "script": "76a914a987e7bb58fe3368d109fcf958a0250d4c67354688ac" - }, - { - "value": 6161, - "script": "76a91481174d2d3d7a7bfcb4e0a940167fc2a8e5873f5888ac" - }, - { - "value": 6001, - "script": "76a914fe19ef18f19cd071ab7c7fefb9ebda579683efeb88ac" - }, - { - "value": 6001, - "script": "76a91461cdd8df984b2e44e59dbc30eb50646c504a9e8788ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "01dcbe5dd8ecf909ef7e10a5efeb83bfb81c5543b3c7c5f36f18bec0a8198463", - "witnessHash": "01dcbe5dd8ecf909ef7e10a5efeb83bfb81c5543b3c7c5f36f18bec0a8198463", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 452, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "91165fb0d40be73f238dcdaff441c8adb8bd0017bdce8580349c524cdbb2ce2f", - "index": 1581 - }, - "coin": { - "version": 1, - "height": 299650, - "value": 570000, - "script": "76a914788a2c15b4412a5b8b7146c46208b53d3860db6888ac", - "coinbase": false, - "hash": "91165fb0d40be73f238dcdaff441c8adb8bd0017bdce8580349c524cdbb2ce2f", - "index": 1581 - }, - "script": "483045022100968696c9bc2f99f8e13e21de314ad97235ba04b1c07dd6e5c56eb89f745c5e53022053023dfe3921ca415b233ead6ffe33d5dc43f276d00fb4fdc74c14daba1a24790121027faef25310102ecc33292bb3f6d39bf0d7a1516e64dee69fd38e173d17442232", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0965957478d70f23c3b1733da25e12cd5d0ca41b792c3dbfc29f061cda573052", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 292390000, - "script": "76a914fe98eae8e7f86edf164129f4530a6d172a6aa37d88ac", - "coinbase": false, - "hash": "0965957478d70f23c3b1733da25e12cd5d0ca41b792c3dbfc29f061cda573052", - "index": 1 - }, - "script": "493046022100bc908785695c4068aefd92b789c097e416be00a678abab1b6991b0ae2dc18146022100e3c19940f63fe7bf93c9b841864d53bb7fa24a3057d55a144d4b2315bd1da98f01210302aaa48943d328c88adae732ccbf2d53b760d1db7b8aae76715b0570c8d4146f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1b8197a1eb87f4120298d9ce6723a449fc8b2b6891648ecef83f429a883c1237", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 299990000, - "script": "76a914fa4bc11be62b61657b2d9eb8ed1a72eb2f2cb46088ac", - "coinbase": false, - "hash": "1b8197a1eb87f4120298d9ce6723a449fc8b2b6891648ecef83f429a883c1237", - "index": 1 - }, - "script": "493046022100ab34eae14f34f10a754ad32377b2677db8fd316b2848772f9b1b65fe17f8c7d6022100a7eb7c94eda36a0864a6a788eb1b5727c64082d5ab6a09218cc31a9086b2bd500121036565544be681ff48f39c550f6e09626096be42a2f794b22df1b6b4f83b3096d1", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e6cf8e9f86d24f4e234530381c5d8e05f573fc7c72f1688dfd6db159cff5c6a3", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1900000000, - "script": "76a914501a5a003b0446f673ca64652bbc8f97aad24c0488ac", - "coinbase": false, - "hash": "e6cf8e9f86d24f4e234530381c5d8e05f573fc7c72f1688dfd6db159cff5c6a3", - "index": 1 - }, - "script": "493046022100f1afe6ee7a1411cdf181f960cb886f7649c233fc4ded9ba487e6c1d6dfe7ed50022100a90149c7450901b01519111dac4834124a0c4dc086e039f734990e7dbce538f60121030e7ebef87ab46dd49b883e978b8be5e3dad6bc08f8a5f40fa5c9d4fef4c85c9e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a2ecaa520eaab3a0540d29f18f8bd897e0a69e9e256828f0e834d3084289bc6c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 499990000, - "script": "76a914fe98eae8e7f86edf164129f4530a6d172a6aa37d88ac", - "coinbase": false, - "hash": "a2ecaa520eaab3a0540d29f18f8bd897e0a69e9e256828f0e834d3084289bc6c", - "index": 0 - }, - "script": "4930460221009ebe278d1090fe35cb25d207d5ac6107a3b65b98bdc101b84bcc3dac088a7f300221008def6b1d4316c712a3eac9a746cf9996a351a07c13a820152e3dd61498afc19901210302aaa48943d328c88adae732ccbf2d53b760d1db7b8aae76715b0570c8d4146f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 1212 - }, - "coin": { - "version": 1, - "height": 299989, - "value": 7070000, - "script": "76a91457f040629f0524dd9c257ce3f33c6a23c7800fa088ac", - "coinbase": false, - "hash": "10cfc6dcfd365ece95344732428e7e4ae766109c2ac951e52e56d81291d647be", - "index": 1212 - }, - "script": "483045022072c665c25933baaff6b738ebf5d098152381487dd4b79da135028fcf26664d0c022100a939b4ffc670b3fbd423872ffcde35e24e30ea804b1294dd29528b7710a08fc5012103fd125f758e6fa962b2892fc227ad5488b22f55d4caad3561c76af53c67aa4fe6", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 3000000000, - "script": "76a914a2b1a9a16ecea77d759328b341d2592cbb13e52688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "ff067e8ed0672b5e6716962a8a839176d8c560682ec0f5cf760e758ede442e59", - "witnessHash": "ff067e8ed0672b5e6716962a8a839176d8c560682ec0f5cf760e758ede442e59", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 453, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a4c8d3df2f6721f1c8ca94c166fd98603e3c0de0ed38ed330e41238750329644", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300018, - "value": 1000000, - "script": "76a91426ed9f1c595cc832f71d154652959f6acefcc36b88ac", - "coinbase": false, - "hash": "a4c8d3df2f6721f1c8ca94c166fd98603e3c0de0ed38ed330e41238750329644", - "index": 1 - }, - "script": "47304402201972fc1d5944c2e61130657dd80099ef198910a6d163eaf602d273d85c5c15b60220482ca2b42bdcd9196e980aa0f59f709b43d6f9b11c31bf11be7307bce1e6001e0121026816a2ca1636207359b00727dff8b1ff881230d768d9433c331c390cb570aac5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5344dd988383e9a1dd65cb7359f3dc723299608ee2e78963a9b9d24984d6534e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1000000, - "script": "76a914ced1e967d07a738c5136b5944dd8d7e188e15ef588ac", - "coinbase": false, - "hash": "5344dd988383e9a1dd65cb7359f3dc723299608ee2e78963a9b9d24984d6534e", - "index": 0 - }, - "script": "4730440220277ef1a43a02c0f372fe7c1c7c805b3d44c8b5e9bdeee0fa48d18684ac625da002202fe9c972c0f21e98bfc6b76180e9c5aec5f776f04ca6e21d850675959bcac057012102b86cecc019a9d88a3b01e9716a36222b743081919a4e3c8c14a0b504cfc09294", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "00eb5ffc4fc5ec74706c168f791c6162308c231cf3cb08726ebca42ad57fcf85", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 1500000, - "script": "76a91426ed9f1c595cc832f71d154652959f6acefcc36b88ac", - "coinbase": false, - "hash": "00eb5ffc4fc5ec74706c168f791c6162308c231cf3cb08726ebca42ad57fcf85", - "index": 1 - }, - "script": "473044022018f5f3b75092538eeb473cf97efad0b119aa920df5494bd81c899bfe2717afd8022035d9a0599cdc2eaa5521664c9450785ec0a5748570ccc6e8d984aae3ef5dddb90121026816a2ca1636207359b00727dff8b1ff881230d768d9433c331c390cb570aac5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1501aa1dbcada110009fe09e9cec5820fce07e4178af45869358651db4e2b282", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300017, - "value": 5300000, - "script": "76a91480b2305ef0d7fc98504fb0ce5889d69da80bf7f188ac", - "coinbase": false, - "hash": "1501aa1dbcada110009fe09e9cec5820fce07e4178af45869358651db4e2b282", - "index": 0 - }, - "script": "473044022052a6a9d9079ebe62dedafe53f1bc212b239a6a13f19f5dfdfcb8668c105df0590220165c837c57677e4fcf063d168a8adc86c2cc05c55dcf6eb88c4c65506fac7442012103e002c57e67341d298398e7a394dda9c27223eb543ea97e125d47b3f2314a7bea", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "04eb05e604835e2409af9317e3787ce5e172068f45d2d6a3d3ffd30e634589cc", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1000000, - "script": "76a91426ed9f1c595cc832f71d154652959f6acefcc36b88ac", - "coinbase": false, - "hash": "04eb05e604835e2409af9317e3787ce5e172068f45d2d6a3d3ffd30e634589cc", - "index": 1 - }, - "script": "483045022100b7b388b431d0e692d08a6926523d0a708cec1b843640c31a3a9b489f9def2db70220397323c3044e50e780856485e15be41fbdfba0c2a88908b6d22b4bd369aa9ab50121026816a2ca1636207359b00727dff8b1ff881230d768d9433c331c390cb570aac5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b94a2b2b69a223cc8753243c508feb5384942587d8fa3627859a155a52d4146c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1248559, - "script": "76a9148a68f24e02ff4c829e130899095cd2f69c08a33f88ac", - "coinbase": false, - "hash": "b94a2b2b69a223cc8753243c508feb5384942587d8fa3627859a155a52d4146c", - "index": 1 - }, - "script": "483045022100eb7bb0cd7211f5059d57f1149ee9976c4866c1e46ad7ce8911bf123c8568145702207ccf204789366399c2402ca182ec3e9dd20153f134db1cffeca4434ac5c2733501210240f8025cad3ee151fa240fc4249523672e5c95b11cfb41ed142bf94b4ee6140a", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 9990000, - "script": "76a9147a1b8da395daa85e92d225af39be2e96a46c645988ac" - }, - { - "value": 1048559, - "script": "76a914efef738305ff7300847b015b2da078060c21985088ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "2c9e8d2ee2316ed2c4ffccd293a9c4a901a00fd8e42ed58eccb19cfe7b1a5939", - "witnessHash": "2c9e8d2ee2316ed2c4ffccd293a9c4a901a00fd8e42ed58eccb19cfe7b1a5939", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 454, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "0395aa85acc26dd67638ca29699e48accb2f9a462a6167c24bdb56bdee11fc2e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 552828, - "script": "76a914256ff8926dc10fff15104b09ef3ac8993f02a4b888ac", - "coinbase": false, - "hash": "0395aa85acc26dd67638ca29699e48accb2f9a462a6167c24bdb56bdee11fc2e", - "index": 0 - }, - "script": "483045022100ba4cc19d55dae1ffcb2e70de7848569a1f36ff800922bfd0f0a5b235b215aac90220148ad9019f9957e3b47d736eabe1d859b6871f8c91fb1382dcf973ee7af1004c012102e584fa8bdc74926dc57319358660a29b99c978ecf97eef719957194317e15354", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d06e2909ee4bb942e522fabb4408bcd81120c8f2c63c4e27fa51bc0aab0f76c0", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299992, - "value": 2198000, - "script": "76a914ca59a9767351c39419dd851f184f67aef20596a388ac", - "coinbase": false, - "hash": "d06e2909ee4bb942e522fabb4408bcd81120c8f2c63c4e27fa51bc0aab0f76c0", - "index": 0 - }, - "script": "483045022100e1c74697bf150e27879e1d0cd3ca1b76e71b988b489bcafbc79ba52447b28811022053d1427745e2ad0d7d39d90286701486f64e28f2ae427b5ef4a764302f41e843012103b12d06d98ee67b31a9ced405a13bd4a83a8de9b632b44e4b5a7adaeba4911ea5", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0fa41edf0c90665760b4fde94a3b1cbaa05e8bb74cb41c75c184a1043055d15a", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300014, - "value": 220994, - "script": "76a914379ce0d3e540dce19e26d4967b0305e4708cd53d88ac", - "coinbase": false, - "hash": "0fa41edf0c90665760b4fde94a3b1cbaa05e8bb74cb41c75c184a1043055d15a", - "index": 0 - }, - "script": "483045022100b2de269da17b81e9b1b148b6f8186ee65bd140cc50c06942f78eb39965cd583a022045638f025dc8b8136ff6acf04de539880643bb061fbc1f5769f6b4d57791ae05012103e8b85496e760c32f21c1e83b680c5238846170af383a718f346f5d5379ca1a2c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "61718d5452c51df8dc5e0db2f61b3f9c648ff5977a68f9a96a7cb78eec42fc97", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1029522, - "script": "76a914361c2dc2b7a39ddf61a30316fb0b76456831939888ac", - "coinbase": false, - "hash": "61718d5452c51df8dc5e0db2f61b3f9c648ff5977a68f9a96a7cb78eec42fc97", - "index": 1 - }, - "script": "47304402203bfcf202f1985f7b1107d05e9be9d93e5392c92d64d4d0c0526caebe8151147a02202fbef239e77c58d1242c6e1f1ec79f746b589ce053ee5b19704cfc6c568d98b40121032f468d92e69eaf380d458804a8485e3d09d8573f586c33db94ac7c30d54a1221", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3edebc87178bf3b959242ce3025bdc3fe4da6b3dfb3358368ea94825ed04ba48", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299998, - "value": 1030160, - "script": "76a914548af4fbad50c3f48765745609f83b83871a653688ac", - "coinbase": false, - "hash": "3edebc87178bf3b959242ce3025bdc3fe4da6b3dfb3358368ea94825ed04ba48", - "index": 0 - }, - "script": "483045022100ed578ca09064346551e8124fa24abd44f5fe18bc635b886eefe56c95d2d5dc5f0220654e12584acaf0007c6566419a6d68d1860b3f2ae8e50dcaa68e90840055b47d012102aef097b33961cedc6bced566f670095fe3499d9a6bd9f80668a979e8ce24740e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a13e7d82dbe17dfecd5632117ebe90cc4a0799fda1feddfe437ee4f4a8ac59cf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 1020282, - "script": "76a9141c63d046eacdf9800ded7473c88f1c6cb73970c788ac", - "coinbase": false, - "hash": "a13e7d82dbe17dfecd5632117ebe90cc4a0799fda1feddfe437ee4f4a8ac59cf", - "index": 0 - }, - "script": "4730440220395e9f1e13efaa7b295d75e8de56abc1de6ef9c09fc62097744560df5a8679cc02201221a7cfd59390c202ba109d8d5c2c5fda496feeab3ead1681cc534b60f8bb0101210290b2caaa47cb7dc9973db0b898df9b69545aa73ec28552353b82dc6b7a83a6c5", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 5038800, - "script": "76a91459f5b8447f63287fcee0a11d8ec41df1ee8cebad88ac" - }, - { - "value": 1002986, - "script": "76a91437d27ed6bb6c66920bd75b4696ea16fb3679957b88ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "a598fc81415c72ac00bb52ea2fce4a0919caf39ffea1ccc098b6ed020754fcd2", - "witnessHash": "a598fc81415c72ac00bb52ea2fce4a0919caf39ffea1ccc098b6ed020754fcd2", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 455, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "25e5206c6f34c5caae55499a44be2b051eec3bbdde65b888ac5bb0b63ee6e19d", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 1003372, - "script": "76a9140807483d1ef110a22846946b5d31f7c7a0ea8de688ac", - "coinbase": false, - "hash": "25e5206c6f34c5caae55499a44be2b051eec3bbdde65b888ac5bb0b63ee6e19d", - "index": 0 - }, - "script": "493046022100d195a67b4dd3f3f2b91ef28cebca82c9cf1b4d77b977612b435f253a4dfb97ac022100803005b279240f5007307a8ec6b5ba252a39565ab8f39eb4a544a34eed02e335012102f894cbc3cef6689f78bddc51deebcd5da5e716d45e45804b2c78822f79a7da6e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5861c6a5593dec0bfecc487ac5ff9ad7f852b75bce7283caa7512639e5752a04", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 28000000, - "script": "76a91493ed6b848575ccfe0b7efe67694f02bc17af79a288ac", - "coinbase": false, - "hash": "5861c6a5593dec0bfecc487ac5ff9ad7f852b75bce7283caa7512639e5752a04", - "index": 0 - }, - "script": "4830450220565890210cb5861e1514e5e4f4e79b460f1ba54513585eb8e06fae8e73bfd67e022100862beec8efaa81be3681553868b5f96baf3bc4d483a0262e08f3fdfc4ad810110121029e11b2312d99ce388be72bc6b0a736dc7d43408a5159a02c9323f45cbb432079", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f38e4348d2da3ea00443975bf018772a72b58b819f31cd50f2f92ca27c02a925", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300019, - "value": 1041061, - "script": "76a9142e426c478548e2ab91accfd5d8b3e458eed381c288ac", - "coinbase": false, - "hash": "f38e4348d2da3ea00443975bf018772a72b58b819f31cd50f2f92ca27c02a925", - "index": 0 - }, - "script": "48304502203b029faf3d56eefe8389a63e2dfeb12df41c4b65debd19d3d00c6471a60b32010221009a1c34dbbcb190fd72a45fc8f04d52aac77dfd21935098f49977b021d784a7ff012102d70c55a6df30dc8dc8d7efc749ccf9f5fc5a96cdf5fc3f5ab53414f24a85289c", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cbb47d4dda28db32d83872a13890a802db1b590a08189842199c79960bcbff7c", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 368374000, - "script": "76a914a453ac43e2da54a878c3dad284baf79d0903250a88ac", - "coinbase": false, - "hash": "cbb47d4dda28db32d83872a13890a802db1b590a08189842199c79960bcbff7c", - "index": 1 - }, - "script": "49304602210099874ff52b3f0d5d4182eb624ab5431d6ab4449874bfa27efc1c4f31c27f295902210098f07d8310da2bb4aa22891a7a8fba7e056eca4ee9098ffa325f3325a6cf9706012102a682b158e3363f4724b18524fd2c75036b1d4609f87a8322d084f88537e5fe6e", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5944a82d22f033a74596683c59a2e85ee9679c7a9bcffad856a90a4da2df0aa2", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300023, - "value": 55327699, - "script": "76a91499d7589337a2c0f88f2f9f8ed37935ade01c8bc788ac", - "coinbase": false, - "hash": "5944a82d22f033a74596683c59a2e85ee9679c7a9bcffad856a90a4da2df0aa2", - "index": 0 - }, - "script": "483045022057d260058d647fd2d8fa26a7f4c8ff9585b90216aae9bfcd215a93fb4f8a08ca022100d6832d47185def9a120741aa829373658eab3bce65d009bd4c499a21e0f3ea7a012103417d38c77884e1b779346fcf8f2d632aec96deb5f658bb9e5317715cc3a1d097", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "efcc16d0e5bc34c13ee7f8f1e66745908eeaa311b88c5980d1942a02bf1f4926", - "index": 0 - }, - "coin": { - "version": 1, - "height": 300024, - "value": 47478618, - "script": "76a91419dd54979c0c46a2f79a02058c6b079a432f2ced88ac", - "coinbase": false, - "hash": "efcc16d0e5bc34c13ee7f8f1e66745908eeaa311b88c5980d1942a02bf1f4926", - "index": 0 - }, - "script": "483045022005b95d3482901ac3f412a81b02acd8182fdfd3388375cd688b1ee316da5eb0e0022100dec67ace0612e9c2daec68da5ede7e1525398dc896c219848a76e21fb063dc090121032cffdcdb663b51bfcd271e1423ee462528d21912f8fe9373b55566aa4b4aaa42", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 1214750, - "script": "76a91478f59f038ac60e9b75b5d4064948b0c70504257d88ac" - }, - { - "value": 500000000, - "script": "76a914b198c8d267a0840436bfb076ac0e6ca1ede09d1288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "b48e235cec32fcdc66e9d5d04ec94756121aa5b48acea1f541e6dccceb94375f", - "witnessHash": "b48e235cec32fcdc66e9d5d04ec94756121aa5b48acea1f541e6dccceb94375f", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 456, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "22e3c397082619aec359f43832a1f4cf47eec80ace5890bb823bc684b6b36283", - "index": 6 - }, - "coin": { - "version": 1, - "height": 206706, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "22e3c397082619aec359f43832a1f4cf47eec80ace5890bb823bc684b6b36283", - "index": 6 - }, - "script": "473044022007c523b0d3547cef97f4652db5463d134c8c70bab253c6040adc1fec5cda096c02201be3eba405aa355fb3095acea3897592150a5ccf387b2333ded7ba3fa8f944370141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eb697c500751d364686dbb1f89dd14c44369a6b5ae43eede89a6ba2ae13c649b", - "index": 3 - }, - "coin": { - "version": 1, - "height": 205330, - "value": 32000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "eb697c500751d364686dbb1f89dd14c44369a6b5ae43eede89a6ba2ae13c649b", - "index": 3 - }, - "script": "47304402204243512549966608932099cdc8a4575940f3165e330621f6ad1a660fc18a661b0220340b93054dccf1ac9e1735a7e066318c3fee7b88ffd9b890931271b9f8d2854b0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b54536ba5539449e2b537a6b859bffcd75e6e491d3193c4fe7d128dfdd02e30d", - "index": 23 - }, - "coin": { - "version": 1, - "height": 205560, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "b54536ba5539449e2b537a6b859bffcd75e6e491d3193c4fe7d128dfdd02e30d", - "index": 23 - }, - "script": "483045022100c095343dbdabb326782efcd031b1b60de60d42d9d98f86c33225d02786a6ccee02201e5a1803ec659f82ec1a8638df1ab4b7aa7ff17ddd4b7fae07467d9cbc0cf76a0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "231342b6f9cf88aaec43f5ca338895acfdf87c74455469b3f28d577b0944ec2f", - "index": 8 - }, - "coin": { - "version": 1, - "height": 205330, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "231342b6f9cf88aaec43f5ca338895acfdf87c74455469b3f28d577b0944ec2f", - "index": 8 - }, - "script": "483045022100a7b20e1197d7a3419ec807786cc94b7054053b0a6e6a0f5f229bd883c71cc246022010244b74bee6047e8332f181901e6fb12db17bcc7e83583176d71a03d2d7bae90141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f797e85863c990f734e6c3b66a7616d53ae0c7433ca4925e3aeb44952ac91f43", - "index": 21 - }, - "coin": { - "version": 1, - "height": 205024, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "f797e85863c990f734e6c3b66a7616d53ae0c7433ca4925e3aeb44952ac91f43", - "index": 21 - }, - "script": "483045022100eb949cd857ba124cb8530e60f341cdea24fe1194151f1dad272d9d0dbdd9e4f9022071c9526b181db4b7439ea7db2d34d5fa96391e48564663551b699a0d8d7056cd0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1edfffa4e49aa23925a57abe83a20b8a7c1679dc68d3e1ff0ec62f877252697f", - "index": 13 - }, - "coin": { - "version": 1, - "height": 205022, - "value": 24000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "1edfffa4e49aa23925a57abe83a20b8a7c1679dc68d3e1ff0ec62f877252697f", - "index": 13 - }, - "script": "47304402203eeae3582517a3c008539f481bf48c4bc0248f4df60a6972d07b274e810296b5022038e16eb5eb8dc57426f7d72c01124b515e856019f49fa5fccc61453ae8ad9a490141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d442aed0d81da0353fe97a77fe11684b182871c2690cae866029b33437382342", - "index": 20 - }, - "coin": { - "version": 1, - "height": 205862, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "d442aed0d81da0353fe97a77fe11684b182871c2690cae866029b33437382342", - "index": 20 - }, - "script": "483045022100f4d78bdd125b72bcdb21d54577e258bddec04e85b5fd6d1dc80f096fd34e450a02204b1e20f87ec3d047f6f3fee351d4b4bd42ff7aa3ecb254865d8d66808a1f6e140141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b85ec6722a4e0f34a621b0380b43edc8fe44c18b68f2e2a7e7e61e0990609ee5", - "index": 16 - }, - "coin": { - "version": 1, - "height": 205022, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "b85ec6722a4e0f34a621b0380b43edc8fe44c18b68f2e2a7e7e61e0990609ee5", - "index": 16 - }, - "script": "473044022014096683b525a40e0f2b1c9616317e6391da43bc06e8ff197201fe38bb624e65022040affc1cca4ef06cb4a72084ae60fae2944b17b92e28efea581b2c661e2fd99e0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "893d7a5c6e30c8447b14dc053873ecebcdfb3a37f142bd25eb0381dc496d0251", - "index": 196 - }, - "coin": { - "version": 1, - "height": 205628, - "value": 12131, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "893d7a5c6e30c8447b14dc053873ecebcdfb3a37f142bd25eb0381dc496d0251", - "index": 196 - }, - "script": "47304402203014dc3efff1f9ce8b9a779c3b5f3ed507b5a60965d43a63db21d5dd1ec3fc4302201a4992024de5988ea6073b73dad4d4199e3a61ef6d1caf5f7448d21185dccec20141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ed4a7789b249d38b1b2f1b4da0f0071362579414800af17248deeca679868ced", - "index": 14 - }, - "coin": { - "version": 1, - "height": 205159, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "ed4a7789b249d38b1b2f1b4da0f0071362579414800af17248deeca679868ced", - "index": 14 - }, - "script": "483045022100b17d8df246554797adbdd822f0dca794b9772592288c0d67982a9f81e090d02e02202f8ca5b484de4bd862eb69bfd687b3f3666b556ebcbc5b9987d3ef1a76d8a98b0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "92c5162cfc4b3837f125c2f1761557f9271d3b6fb6c99e94fc244256de91b5bb", - "index": 2 - }, - "coin": { - "version": 1, - "height": 205557, - "value": 24000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "92c5162cfc4b3837f125c2f1761557f9271d3b6fb6c99e94fc244256de91b5bb", - "index": 2 - }, - "script": "47304402206de28bff459d8085dfe93b8dafe1bd8a91997b8b7b16afbe5a81e2f81520931602207f9077fa5bb76a1ed17d1b881917972931f21dd91e2dfa08f7236bea718bf3580141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0674e9c9c3fa61d2670ec05a080953f06a9e7dc78063446fbc83a192b89962a3", - "index": 22 - }, - "coin": { - "version": 1, - "height": 205060, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "0674e9c9c3fa61d2670ec05a080953f06a9e7dc78063446fbc83a192b89962a3", - "index": 22 - }, - "script": "483045022100910d7a8c358c5651fd741d53db06d9a3950a13a3289d45b40b2cf9ba722acbdc0220367efcb186e14f49e61d10e35edd0077c9c9c0ff0328a4aea6d4268064b4a0fd0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "75d76f0382e480ccd2618c6acf0f70df766af3b39197ac9232ab0c56a35f83fd", - "index": 27 - }, - "coin": { - "version": 1, - "height": 205064, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "75d76f0382e480ccd2618c6acf0f70df766af3b39197ac9232ab0c56a35f83fd", - "index": 27 - }, - "script": "4730440220250f8703be9c98fa5667eccea47af04b6ba63d8bce0a78d98aee975606cb5e140220465e2ed49f56c3cf497ed2a948ce88e59b4978b74e44c00394dccd84022ce5b10141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "42225fbf3c170475009ade328305b62c6893dbb72f4724d66a70cbe42a5928d2", - "index": 30 - }, - "coin": { - "version": 1, - "height": 205862, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "42225fbf3c170475009ade328305b62c6893dbb72f4724d66a70cbe42a5928d2", - "index": 30 - }, - "script": "47304402206368d052aed1e578f0a125862561d2517bf06191d1817c2b4e925798fd92406302205b0052cf2be3bec6379abbb0c35e42ae9712838373357f12b6e6f19b667051a10141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c3f9b8fb02e2d0322e10a3ca2c3fa58742b2f31c71d2e588317877b4bc097f37", - "index": 20 - }, - "coin": { - "version": 1, - "height": 205022, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "c3f9b8fb02e2d0322e10a3ca2c3fa58742b2f31c71d2e588317877b4bc097f37", - "index": 20 - }, - "script": "4730440220327effa2037bcd19e30e69f85c66a767c327c4f13fb3f0a5d7ded35a40ff822602202da88c0047503957a879a3c65ff8af1853e968f683a6ef43a64a334255f25c820141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d23879e84716a0afdda0d29f47147c12d2624b2e69d68ad54a97fa89267e027f", - "index": 18 - }, - "coin": { - "version": 1, - "height": 205158, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "d23879e84716a0afdda0d29f47147c12d2624b2e69d68ad54a97fa89267e027f", - "index": 18 - }, - "script": "4730440220080fd1872ab31911b163f343d8b9b75dbd3be0dac97a1c9a18059a48d101807902200a3319d0361068c690113d42ba36c929456c85a09148dea59913714d3f765c740141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cf373d4140c476f79b442ca633a3be9a2c20e7c51aeb952fd930501b9206802d", - "index": 18 - }, - "coin": { - "version": 1, - "height": 205158, - "value": 24000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "cf373d4140c476f79b442ca633a3be9a2c20e7c51aeb952fd930501b9206802d", - "index": 18 - }, - "script": "47304402202d8010ffaaebf7a6094aed1e49d2b55fde84ffdf8ec3972c5a376a6ec83f9c7f0220379b8af4f4fe70c325fb12e8ed00759ed86c33fa68f74008aaa63aba5ad1fe7b0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c97d94a0ed12928521c6c65cd28eeed76e424e039e50e32f07488eb54b615322", - "index": 8 - }, - "coin": { - "version": 1, - "height": 205160, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "c97d94a0ed12928521c6c65cd28eeed76e424e039e50e32f07488eb54b615322", - "index": 8 - }, - "script": "47304402200773818e2a7b8c45922c649ec26bfa931471bee1ffcdbad5a9696fc9513e5ed002207a0e167643102635da435794377b53a0e6eea97ffefada92fa084514518abe670141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "42210c5ce985d3c4f6fad03d834158ccc7988dac23ff7b21c8a062048bb7ffba", - "index": 6 - }, - "coin": { - "version": 1, - "height": 206392, - "value": 32000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "42210c5ce985d3c4f6fad03d834158ccc7988dac23ff7b21c8a062048bb7ffba", - "index": 6 - }, - "script": "47304402203d06af2806acb4d9de36a3a141d99a9cc40b13d7d20c21646c9512c2bbae80b1022078752213a1868097aa07586c19414fbce86b459518c0fd9104116842371c31810141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "69dc29076d44091f2b6a18ed2d345592d04f927109772f2576e56ce529dd2666", - "index": 11 - }, - "coin": { - "version": 1, - "height": 205164, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "69dc29076d44091f2b6a18ed2d345592d04f927109772f2576e56ce529dd2666", - "index": 11 - }, - "script": "47304402200e68d18ceca988aeff8f5db70483df26256b5ee33b673c571f857f74e862fefe022030bcd56c563eeb9eb794e1f4d1bf0859051ff757d987021e5b27e7bba1371e870141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c6fff5ea5d48be04a7e7be4f59c53c5a72c984db7d8d105605c869a4fbc82e88", - "index": 18 - }, - "coin": { - "version": 1, - "height": 205060, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "c6fff5ea5d48be04a7e7be4f59c53c5a72c984db7d8d105605c869a4fbc82e88", - "index": 18 - }, - "script": "483045022100e8248dcfa1b0d313a06df68c81f80f9af2f53650b8edf4f8835b44fef68b521b022067c82cc521a5b99bdfb4b5bcfe7054200fdc7953a7ba388bbe3c3d4cbcd9f4f70141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "dfa041af53750b211992ec14f6ee1f8220a1b2f3733c83eb4ff087293f88dcfc", - "index": 25 - }, - "coin": { - "version": 1, - "height": 205022, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "dfa041af53750b211992ec14f6ee1f8220a1b2f3733c83eb4ff087293f88dcfc", - "index": 25 - }, - "script": "47304402200fbee1dcfce59a12b1f6360c5a517e9f550e744105eae1c2011d1b551abd1fca02201646842cfb65f25aba53a3f8e522192134adf376c17877364ae8eef697b9e6a30141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "deb87e284bc1de2c08b35d10f8e4df9d377959ea35c75be3bf796fe1fff319a1", - "index": 209 - }, - "coin": { - "version": 1, - "height": 205120, - "value": 10996, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "deb87e284bc1de2c08b35d10f8e4df9d377959ea35c75be3bf796fe1fff319a1", - "index": 209 - }, - "script": "47304402202b6ff401dcdfc59eba3ea51a05504c5e5adba72cf2065dc9ca3b52c079c7e0ec0220264585e0bca49354f1fb04cff09ace792475c04443c88a85d08d5b391d3b48350141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cf15c9d1c7b75866857d717d268cc21f8b3d7cf71cd449b9f2981fc3654492be", - "index": 11 - }, - "coin": { - "version": 1, - "height": 205026, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "cf15c9d1c7b75866857d717d268cc21f8b3d7cf71cd449b9f2981fc3654492be", - "index": 11 - }, - "script": "47304402201776e8f21ad04eb4bed3efe40cb97e576f231eca214e6223db8a37efb320b41a0220443c38b517e1f6ba4d845123e6439843d37cee7938cc1452d88ba6ac43a1b9c00141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "32b71c0bcf70e455aef9dffc058b655ba34d6c8405db5820476afb967eebb8d9", - "index": 16 - }, - "coin": { - "version": 1, - "height": 205160, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "32b71c0bcf70e455aef9dffc058b655ba34d6c8405db5820476afb967eebb8d9", - "index": 16 - }, - "script": "483045022100e05d8f2deb9c81de2433ba1617b09dc5ea2dc1b21d9f4de9cb5557864056365a02204963ae3f428e5d2800ca7e90799a53eb51d70083a1b832c93087bc8bdef6b0180141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "601a1e9c595907d0ed45b107318b84ee4cae7e7b54c439d76b5bfc8d014bc37d", - "index": 21 - }, - "coin": { - "version": 1, - "height": 205024, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "601a1e9c595907d0ed45b107318b84ee4cae7e7b54c439d76b5bfc8d014bc37d", - "index": 21 - }, - "script": "4730440220428b83476619fce41e546578b6281221d92df69646eb593712de934a38fab41002201f04c0193a4c045c5ae528d35d9e4b76eabed4d7c41645bf141c06a01c36ba220141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "44785b3a7a5125517232919e6e69596f784ccd7cf45544ac651661479fa760a6", - "index": 9 - }, - "coin": { - "version": 1, - "height": 206394, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "44785b3a7a5125517232919e6e69596f784ccd7cf45544ac651661479fa760a6", - "index": 9 - }, - "script": "483045022100a9bf74b868f05c027e799b69f9ebaabeffc8a6e66d126e6592659604e2baa45602207c1814e6c9c44240ecabe455c8edfc66c5e4ecb6387d53d43df53c620db120ac0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "60dbec09c993ec2b0ac14dddee6d64ab35e6eac50966ad364a738cc9fdd9583d", - "index": 18 - }, - "coin": { - "version": 1, - "height": 205024, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "60dbec09c993ec2b0ac14dddee6d64ab35e6eac50966ad364a738cc9fdd9583d", - "index": 18 - }, - "script": "483045022100e2ea80e871131ad0b11bb19c41887ae309f9e51a2b8d10797602a29a66d48b5c02203518820f6e83aebb64d64517157be835646511826c21597088ce573002cca3390141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ae58af9ad4eb4c587aa5bdad883d7f22e94db3137e08dac85f00b68076bad28", - "index": 20 - }, - "coin": { - "version": 1, - "height": 205066, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "6ae58af9ad4eb4c587aa5bdad883d7f22e94db3137e08dac85f00b68076bad28", - "index": 20 - }, - "script": "483045022100e86873ce256c590c2461efd97c51e0d9c44f7970a34ef913d3a0b9566bf16f3902200c9d84c3f5ed7ba448779de664fee8597714f6c1206d15d3ad6c16427f30220a0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "18207712d944018cb280a69f06d262568649fe0a26cef11a96fdaa10ec14bd77", - "index": 10 - }, - "coin": { - "version": 1, - "height": 205330, - "value": 24000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "18207712d944018cb280a69f06d262568649fe0a26cef11a96fdaa10ec14bd77", - "index": 10 - }, - "script": "483045022100a79cd1a443625fc860a0f05c893c0f419c3ed126334f7af36fd9232ddf942bba022033f5c9bc360e873be74cef0c1434a028ccfe6742f27b15f490beb5f35a37d7b10141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "60ff2b3ba309339bbe4649bd03c0305378b5a05fca1d639297a13037e0f4f282", - "index": 4 - }, - "coin": { - "version": 1, - "height": 205163, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "60ff2b3ba309339bbe4649bd03c0305378b5a05fca1d639297a13037e0f4f282", - "index": 4 - }, - "script": "47304402207f0faf41d73986962e187b83cd70c3f9079643fe049435059d420e70ede7d70502205452919cbd7239336876fea14ab82a3a5f23d04903da5c5fe49fb832e96664d40141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ff708f554729358c910afb7087b2d91fc7cc294f8d23bbcd9eb1a224ab2c8cd", - "index": 8 - }, - "coin": { - "version": 1, - "height": 225748, - "value": 16800, - "script": "76a9143241807a5bbf2c602d43dc5eca3a8e89930df65088ac", - "coinbase": false, - "hash": "6ff708f554729358c910afb7087b2d91fc7cc294f8d23bbcd9eb1a224ab2c8cd", - "index": 8 - }, - "script": "47304402207669de0dbafbf0688c959e4e9e68ed7e238296c0a5d2e1858f51af6a9e78f0ba02200acadff50c320f22acb8d60918c5d14e8954c342afa7ebc8aaf55e8e46db3c4a0141047b9b89fe1b2232ca86a5837e059f9c886b5e0c46270b5f150314dcf4df199aa784dc3f8d25b576596fb1a21044b14f518bfc5a15d2eb06fc391333c1dd17625f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f245fbfc6e8df66856c7db240b63f495e6f2e07b9c87f664d312685c96cf473a", - "index": 5 - }, - "coin": { - "version": 1, - "height": 210001, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "f245fbfc6e8df66856c7db240b63f495e6f2e07b9c87f664d312685c96cf473a", - "index": 5 - }, - "script": "47304402207b38353d594412ce1b61951a8149bd696ff1d5f8b4d5edac3cc7ccaf6a4901c70220304096b198f334d5b72d8d3dd33b09b6044b353c9a01c80b7956ffda9968d4fa0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1a80927d21a62a36a9e82d7945cb346585a8bc5c1f521420827d70f26fd4353d", - "index": 25 - }, - "coin": { - "version": 1, - "height": 206135, - "value": 32000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "1a80927d21a62a36a9e82d7945cb346585a8bc5c1f521420827d70f26fd4353d", - "index": 25 - }, - "script": "483045022100d31180330c1205e4ef714ad6c68dd43f8161249690287ed02deebe1330e1127b02200a41b91c34ddcd50caf13354c4e61a0fd62c384582ac7aad53a6ffca0c23c2540141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4a2a81a433698672af0dd2cf4b8481580080e975fabf4e5d26911e4aa7fc8299", - "index": 27 - }, - "coin": { - "version": 1, - "height": 205575, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "4a2a81a433698672af0dd2cf4b8481580080e975fabf4e5d26911e4aa7fc8299", - "index": 27 - }, - "script": "4730440220267da9b63ae62f8dc06038fb2da04adb47e9a2cb87cc0aa54e9f939aeeceec3c022059cd90b914caed493e842a1f7560440ae9acb77e58289a4398da0a874d0028e40141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9d83521c0fbf1d3e20d630cd94f32af7a17c732cca295645ed9ae53cf3b5e7e0", - "index": 37 - }, - "coin": { - "version": 1, - "height": 205066, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "9d83521c0fbf1d3e20d630cd94f32af7a17c732cca295645ed9ae53cf3b5e7e0", - "index": 37 - }, - "script": "483045022100de6adb755e0aab6c9eeedc01b1875f059f18fab381198a825cace584cf34d4a1022035795487055c14e45be965fcb00aa45f3246a9a9404bae2e06b3a40d6e6757fc0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "41be5127277577d6f3976189c53e776f17ac29b797e90e52173a44345216ce3d", - "index": 3 - }, - "coin": { - "version": 1, - "height": 205168, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "41be5127277577d6f3976189c53e776f17ac29b797e90e52173a44345216ce3d", - "index": 3 - }, - "script": "47304402202c65927df84a0d6cf9f04738372ee605fac17bea23684642704110663797febc022032f18e93d4da7880febbca62c6e5118e3bc375baacfaf1da06fca09332cfb1160141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1ba4ae605db8b989a736b529a2a1d0dc66339e0578f71d47119b651859b34ee1", - "index": 7 - }, - "coin": { - "version": 1, - "height": 205557, - "value": 32000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "1ba4ae605db8b989a736b529a2a1d0dc66339e0578f71d47119b651859b34ee1", - "index": 7 - }, - "script": "47304402201a82c5abd90e4f7875a0e7dfc0f1798753386c446f9797a77d61198383a577a30220372392018b9fae5c6c46179afa577f27a99a51bd6de2e2c31c6c438e17fe754c0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d561adc5a0150377621da5a4f763005b697d73eeeb6c5f90837f11d86ab4d4e0", - "index": 7 - }, - "coin": { - "version": 1, - "height": 207433, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "d561adc5a0150377621da5a4f763005b697d73eeeb6c5f90837f11d86ab4d4e0", - "index": 7 - }, - "script": "4830450221009a5d1263cbe8612e8cd535762e74940870b48b28628ea1deab0630c5b382611a0220389be07b1136009c2bd17ee257cd793790985d23f2ddf7418df5794e83d2d5900141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8c672f285b78c7ea8a468569190801fe18a66fc5321ab4f17183aaeb466e39b6", - "index": 20 - }, - "coin": { - "version": 1, - "height": 206137, - "value": 24000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "8c672f285b78c7ea8a468569190801fe18a66fc5321ab4f17183aaeb466e39b6", - "index": 20 - }, - "script": "47304402200e1bcc546cfb480491f3cb40832219b5c0eb418915cb910b1a8b88ba78d45fed022009b6209df6719bc39df76dd7d07cc1c68ceea4fa071bd5b014c9d0a5820df6370141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6a1de9853b4ce03926a3a22e8189f96e9d1d60ad6d58b44fc67fa2127677fa84", - "index": 10 - }, - "coin": { - "version": 1, - "height": 205160, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "6a1de9853b4ce03926a3a22e8189f96e9d1d60ad6d58b44fc67fa2127677fa84", - "index": 10 - }, - "script": "47304402204889fc189348318452c1205b80449352d20c816280eff0029739a37f3453c78d02200df8fbbba684fd23833b05047aa9d974eb4eb348356e4ecd93b1c685c78d26560141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1b56d7c13c1b8e1865b35e3443cf2a945513d5e19579662f7b7e3efaea05776c", - "index": 0 - }, - "coin": { - "version": 1, - "height": 205166, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "1b56d7c13c1b8e1865b35e3443cf2a945513d5e19579662f7b7e3efaea05776c", - "index": 0 - }, - "script": "47304402205db32441f18e423c39f4d10d2dc4f5c2173b7d75e2d3dc98892b2ff2f6a5b66f02202f4f1a5cecb988c54591d91e3959fa448b7f549ee1a2fe31cced0a48163108e30141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a7c52079d2c2740d3e4f06f49069e9315494af6d8f6c8491cb703d76be0d5e33", - "index": 18 - }, - "coin": { - "version": 1, - "height": 205862, - "value": 24000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "a7c52079d2c2740d3e4f06f49069e9315494af6d8f6c8491cb703d76be0d5e33", - "index": 18 - }, - "script": "483045022100cebc6f93e86ae2058cccb0444c9805c90a9946f8a2b209abdc1358df491cab6202200b36b7ab597d24d8025a5b8957497e5c00efdba1fee82926f9791a917822256f0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "00022f422421d17d5e04457451f5a716c54482ee6f91f768395bcd2d22d7ce95", - "index": 9 - }, - "coin": { - "version": 1, - "height": 207380, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "00022f422421d17d5e04457451f5a716c54482ee6f91f768395bcd2d22d7ce95", - "index": 9 - }, - "script": "483045022100ec339941d8ea7c923d2224bcd80516f61b776eb0835aa2c0fcde9d726a77e2b40220597ab446ae1008bd500149e5ca9189e9acede07a06f999ba7c737a22810dd4c00141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0cc9efafbef09e9aa736c5d2c10a54027e17f874a35a09921269cea6ad25e790", - "index": 2 - }, - "coin": { - "version": 1, - "height": 205330, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "0cc9efafbef09e9aa736c5d2c10a54027e17f874a35a09921269cea6ad25e790", - "index": 2 - }, - "script": "473044022049e2bb367ca0440ead5da2b7a2c94ed85005ee3174b2d00a5299b49c29f792ef0220106bb143cbca824ee87187598c24c80fb53dcc5a336b5ede77d7a584ede6e4350141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2aa4727d1971ab0aa7d13dabf485b8a656b9a951657517384914fc33c74d04bb", - "index": 17 - }, - "coin": { - "version": 1, - "height": 206140, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "2aa4727d1971ab0aa7d13dabf485b8a656b9a951657517384914fc33c74d04bb", - "index": 17 - }, - "script": "47304402202ac3de8cc1927a42a6d4715eef872f080dcfcc2c1b008f3af9013c6dd56a721002201e5a4af8089b9a78a9647a67f161b6c08d692fe2eb3fc2b9c9aae49fc169eac10141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6da13d756302ab5e8db5fc2b4dd03c8783c2ea4429d8354332ef90c690ce5ccb", - "index": 13 - }, - "coin": { - "version": 1, - "height": 206705, - "value": 32000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "6da13d756302ab5e8db5fc2b4dd03c8783c2ea4429d8354332ef90c690ce5ccb", - "index": 13 - }, - "script": "48304502210084a6ce52ff3621487aeef7d2608f16ef83c0d6a9c866a763ee22b6fcbbb42fa30220627a683c63f8871a8402884353ebfafd848cd61e0627a4efa07c6c517a90ce020141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d2109cd3802340d05694838c06b7637fefac19a74667e550a746ce1712279a5f", - "index": 11 - }, - "coin": { - "version": 1, - "height": 205066, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "d2109cd3802340d05694838c06b7637fefac19a74667e550a746ce1712279a5f", - "index": 11 - }, - "script": "483045022100cd752d22c5696339efe435600f1ad6e295c28f67e8142ffa0cbbef73caaf1dbd0220231efa9f6d6d90ed2e3f2997ed57fb43ebb8399c4c55d43677e3511f4a4f607d0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cb578eb579a097cdca00f5c9f4efa44a624fba28b0433d1108c9f3c6dfe6bef7", - "index": 8 - }, - "coin": { - "version": 1, - "height": 205158, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "cb578eb579a097cdca00f5c9f4efa44a624fba28b0433d1108c9f3c6dfe6bef7", - "index": 8 - }, - "script": "483045022100907a143404a9d21f1ac821bdbd4e9f0e6c22fb11e49f2607566123c465ea9eae022075846e35a69e34ba4cb24975e1009dc05e32f9d5890980de871e127e4d2c28de0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cafbf70122202bd8ac523f41499bc44b09d4cf86d7c90851c23a67490e42bfb2", - "index": 16 - }, - "coin": { - "version": 1, - "height": 205159, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "cafbf70122202bd8ac523f41499bc44b09d4cf86d7c90851c23a67490e42bfb2", - "index": 16 - }, - "script": "47304402201843371a165a3936eb67c849a4d03ef4ca22e435295e327406201ef4dd299f4602203d788ebfc4c4aca654d42d3b7660e85a86edf08fc1c5acd4451e1c2a2a5f665a0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e8d72ea4a74e59cab6d8356fb9d08ea293a4d6e30b0b8cdce7e476a5914eb430", - "index": 2 - }, - "coin": { - "version": 1, - "height": 209460, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "e8d72ea4a74e59cab6d8356fb9d08ea293a4d6e30b0b8cdce7e476a5914eb430", - "index": 2 - }, - "script": "483045022100bcfa05143c3cfc479879e909faf78347092b02d9432287c26899157b4b24c94202206a2e62cbf2a54964aa9b902c62fdfda043c1446b5f74d9731e3ee0f071efd22c0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e559d263bafd438472af049b996728d2fea7cc746fb390e22ad1295978953ea5", - "index": 51 - }, - "coin": { - "version": 1, - "height": 225854, - "value": 14400, - "script": "76a9143241807a5bbf2c602d43dc5eca3a8e89930df65088ac", - "coinbase": false, - "hash": "e559d263bafd438472af049b996728d2fea7cc746fb390e22ad1295978953ea5", - "index": 51 - }, - "script": "4830450221008e0b3ff902bbc348f8bffb30a9ef686c2ad6bd88de92eae09edf2ca10d1efc5e02201f4690093e98b80637ab201ad2aff34422a9c0988325476463f570aee563b0090141047b9b89fe1b2232ca86a5837e059f9c886b5e0c46270b5f150314dcf4df199aa784dc3f8d25b576596fb1a21044b14f518bfc5a15d2eb06fc391333c1dd17625f", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a7e90b7b0b3ea5654b3efff2b2d196afa7b5822a4dbaa9e3bde1fd757c5d9568", - "index": 6 - }, - "coin": { - "version": 1, - "height": 205064, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "a7e90b7b0b3ea5654b3efff2b2d196afa7b5822a4dbaa9e3bde1fd757c5d9568", - "index": 6 - }, - "script": "47304402207449e06a446bea65e213601e0bda6d1bbd7a4462dffd475ceb2152d93e60d15802206bfcb8762f94e5176c5fee5eb33fa4f9e4e8013608830e6336260c5d03c0de280141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7eb4a30fd811bc1d33ce125c9e9f376dfda52bb2a60605e350e62f892f4e7d4", - "index": 25 - }, - "coin": { - "version": 1, - "height": 205561, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "e7eb4a30fd811bc1d33ce125c9e9f376dfda52bb2a60605e350e62f892f4e7d4", - "index": 25 - }, - "script": "483045022100f28da4a33150fe0dedcc8a6522137a13b1ffbf75f4f9c1c4ad78e413e4822fb4022079d2151b13f4407c7efd289552a7dd2bb254706e15a5155281001f49c53d33800141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2c0481913d09b25cf2110836dcf4dbc4d1f696582594cc8fa276cac602091d86", - "index": 15 - }, - "coin": { - "version": 1, - "height": 205024, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "2c0481913d09b25cf2110836dcf4dbc4d1f696582594cc8fa276cac602091d86", - "index": 15 - }, - "script": "4730440220160eed456dbd5315fef11aa31d6fdc8a77b960dc1c11f29fcf137d21d2e0cd1d02205c615e18a180ad1f8f64013d96329632e97b7d6f389ab718556d5e65d04103640141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2be4ebfa3e0de5d87c4619f1df1d91b5debbbdef0be38a58be4dabc2591319b2", - "index": 3 - }, - "coin": { - "version": 1, - "height": 209457, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "2be4ebfa3e0de5d87c4619f1df1d91b5debbbdef0be38a58be4dabc2591319b2", - "index": 3 - }, - "script": "483045022100f032bbced8cda5ca7641bfc82c344377b8fd96f5759b894475829cde6db230d102205e89e1d26562a041b7e80d4215b91f09aa426cd8dccb46ac700891dee25e20840141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "031d53d0553f1f17c73581583f4e8d08da633e9ca64b45b29ecf649e3460b32c", - "index": 6 - }, - "coin": { - "version": 1, - "height": 211708, - "value": 16000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "031d53d0553f1f17c73581583f4e8d08da633e9ca64b45b29ecf649e3460b32c", - "index": 6 - }, - "script": "47304402203f09f6a90a5a40ac0775c75bc49297196e4e781559cc179467b9e00f3ddac9580220644ac04faa52f5887353c4be34f482cc048e57bd2935f46df3a03d997835717a0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "223f0d5ce0000fc3c2c38423a097fdefe42e768754af132e6e644f4a5ca9708a", - "index": 11 - }, - "coin": { - "version": 1, - "height": 205164, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "223f0d5ce0000fc3c2c38423a097fdefe42e768754af132e6e644f4a5ca9708a", - "index": 11 - }, - "script": "47304402200700d63f3607555a5491d15e9ee17c69442c1e7b0ae255e91d40cfc1e4f325a102206260b8617186389fc07fbfd4f3e2bae3dd6b60d5312eeda9933379cad91de8f90141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "262382a92bad0e8cf33fec055f07faa1fb72bbe7871c584aa332c36c725810cf", - "index": 25 - }, - "coin": { - "version": 1, - "height": 205024, - "value": 8000, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac", - "coinbase": false, - "hash": "262382a92bad0e8cf33fec055f07faa1fb72bbe7871c584aa332c36c725810cf", - "index": 25 - }, - "script": "4830450221008640452dc020b3db077c8642f4eb71f43d7a717ad530376b3c4e41f0caa14a30022028da5e7099c998c053cfc24122ca83384cab8312b4c1b1d1a8e39fd264b3a50c0141042dc08b8891b55da2a017eaee689b9ecac10b63578d1304ebc954d09f2e881f463e91e2a38e5eaedc59d7a528d45c1a7a79b02b12e0f192bda3e5d4d119844674", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 750000, - "script": "76a91470829b3172404c5c49c572ad19f5608e0b3cd59b88ac" - }, - { - "value": 18327, - "script": "76a914ff384351395a46af9e887468b195c639fb37156988ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9d728f581941687e5109da282ab73c143345e075de9528e2030d5d3a115e6e32", - "witnessHash": "9d728f581941687e5109da282ab73c143345e075de9528e2030d5d3a115e6e32", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 457, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "61b973a54cfb85d39867551a0184d641d5cd4b969dba05cecc5763edbb840528", - "index": 23 - }, - "coin": { - "version": 1, - "height": 299835, - "value": 3090725897, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "61b973a54cfb85d39867551a0184d641d5cd4b969dba05cecc5763edbb840528", - "index": 23 - }, - "script": "483045022100916ac49ce7c238ae77c751ef9e03091d22f6e9f41493209652e316b5c3dc71dd0220281c23439723e7d69dd603f3414650089835ac90e2e7ef61191601086f1bda66014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "edf0c0fd7a55a377a6cd04b10d76a4d586ad5733cb57c30a001834778e962137", - "index": 37 - }, - "coin": { - "version": 1, - "height": 299380, - "value": 34678357, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": true, - "hash": "edf0c0fd7a55a377a6cd04b10d76a4d586ad5733cb57c30a001834778e962137", - "index": 37 - }, - "script": "483045022100fe353753d2345635624a2953d1df2acde57b4822bef3c8e167e0cc18dcb87c1b0220748238008e4955350695f1f97bd2e3894eacc29f8e7a41f3d67003a22d54beb8014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "674beeeb55742f849d93ea228a569dae07c6ef3ddf83c70bcda8cc81a791e540", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298793, - "value": 49779168, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "674beeeb55742f849d93ea228a569dae07c6ef3ddf83c70bcda8cc81a791e540", - "index": 1 - }, - "script": "483045022100949928f8c7c0eb397cb3186a6f63e65c2486b35d3f7b6d9f4bcc754cabbd62c002205a9e83a14dfe30a7d3d584574bc1b65e66ddbf4cc2e130b3bd85f313bdc0049d014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6ceca5ab62984a5ff91f4e8954294a8cfccec5f9b3d56def447abb97363f704e", - "index": 263 - }, - "coin": { - "version": 1, - "height": 299675, - "value": 1258873619, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "6ceca5ab62984a5ff91f4e8954294a8cfccec5f9b3d56def447abb97363f704e", - "index": 263 - }, - "script": "47304402206996d48a5ddeb62134c199b32ddf79d9bc2dd0648d115690c43288a940aa1fd8022024c77c18d510e82f44828dc44b5d6f647b832ded7156719606fb5b920071e28f014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "ad98340b3256c0e8a28d6b6b755ffa8f5a043720b9d424895f10c14d0537f662", - "index": 1 - }, - "coin": { - "version": 1, - "height": 299903, - "value": 6036639761, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "ad98340b3256c0e8a28d6b6b755ffa8f5a043720b9d424895f10c14d0537f662", - "index": 1 - }, - "script": "48304502210096ff8d892032848c220a444ad7433697d7273c317b1ef98d0555838181ce902e022020bf415a31508498188fa4380898062aed36a09b69708c3601d6b6ebb190031f014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 4743962496, - "script": "76a914d667915af52ec126ed143185aae90668ac31e9b988ac" - }, - { - "value": 5726724306, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "e92e8166572c576f19e831e976a1614557ed5522800f34c90653256386529d7c", - "witnessHash": "e92e8166572c576f19e831e976a1614557ed5522800f34c90653256386529d7c", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 458, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "5e72b888c2c5c350127ceb0b6b10733ce95034af04d3ab98c72f7846981e0032", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299897, - "value": 1124800000, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "5e72b888c2c5c350127ceb0b6b10733ce95034af04d3ab98c72f7846981e0032", - "index": 0 - }, - "script": "47304402206c82b78d05639b79cfa92db93c18d12210e60c5145346005f60911aefb67b03c0220154d0183f8018e45b649a3109883ede9cc819301fe9e4ec439b241e6e7c25f5b014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9d728f581941687e5109da282ab73c143345e075de9528e2030d5d3a115e6e32", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 5726724306, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "9d728f581941687e5109da282ab73c143345e075de9528e2030d5d3a115e6e32", - "index": 1 - }, - "script": "483045022100bb829732db31b9c3c0b8bb6c6d915ba1ebc8bb97253f8415f48be11302189b74022013830a68d6f70d23e1cc9689d448f1670b0bcf44d84d6673d5704e9324fa21c0014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8de8c4538c16c25a3bd287e316d982d4dd1e489a3d4b5007941156e70a789a42", - "index": 0 - }, - "coin": { - "version": 1, - "height": 299897, - "value": 1000000000, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "8de8c4538c16c25a3bd287e316d982d4dd1e489a3d4b5007941156e70a789a42", - "index": 0 - }, - "script": "483045022100c98f9e132f0ca010a701181137d9ea0917deb947adae5ce9d6164c887324d965022018a16f443ae14e0124602770991bdf5d312569495050eb88d194e929751a63aa014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9de81225c9f0dbbad5b7ab751454cff5e268cb753ff2f30ebbce12dd11b57ff2", - "index": 2 - }, - "coin": { - "version": 1, - "height": 299903, - "value": 283015230, - "script": "76a914f3de04dcf6ece03583224826d57c136ee0fed09288ac", - "coinbase": false, - "hash": "9de81225c9f0dbbad5b7ab751454cff5e268cb753ff2f30ebbce12dd11b57ff2", - "index": 2 - }, - "script": "473044022025d5f4ea2b65018a5e9e09749a1a0ff3075f34088e658ebb2a4fb0b0cce39fca02205f031e4b3acfee19fbdb1866adad4c75cbee9bd52deaec9ced3fdb9bb7d45196014104ac024e19b6d21c2b93a8dcc9f480662c6259e9f9823696a3c4fa8e20d4fc87b464ad725a91cced3b090c52ffe9b1cbd458d25349244089fee80871d1536599d2", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 8134529536, - "script": "76a914dbaf5426e9c23a27d849877ed11ca65d04cfefd288ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "eb65f914814460cff8ce7257d87a6ff1aa5b6fb6eb88c2188bf2e1ceefb69db9", - "witnessHash": "eb65f914814460cff8ce7257d87a6ff1aa5b6fb6eb88c2188bf2e1ceefb69db9", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 459, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a76f5b4e67d13aa07e3c8d3147a6209f527ffa62456f3b20e6d62d91444da914", - "index": 0 - }, - "coin": { - "version": 1, - "height": 287191, - "value": 4555996, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a76f5b4e67d13aa07e3c8d3147a6209f527ffa62456f3b20e6d62d91444da914", - "index": 0 - }, - "script": "473044022075d3048dc8bd155c535721960065af0a950343ee59fea8135b625733482ab0be0220215fbccfcf529f74514b47f78e52b105138c7b825bbe79f35ac0b42efb86bdbc012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "70450a226ef3998b38ac1f7ff70dcb3be5d1200228d5dd451c44292182ee2c1b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 287014, - "value": 4733421, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "70450a226ef3998b38ac1f7ff70dcb3be5d1200228d5dd451c44292182ee2c1b", - "index": 1 - }, - "script": "48304502210095da6449e4bdc9993909662ec2b61c834aeae0e2a3f61dfa5b7ce1b1091f4ef00220675cc43af22bf5e8cdc11a24d85621fc4e7c8475e6976a26ba0edda7500607de012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "81e3f047dc9044f1c89fd47b7be3de7f9b7e68276b76f9ae285f561c86d62265", - "index": 1 - }, - "coin": { - "version": 1, - "height": 292005, - "value": 6906580, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "81e3f047dc9044f1c89fd47b7be3de7f9b7e68276b76f9ae285f561c86d62265", - "index": 1 - }, - "script": "483045022100a56d289f0dfaa0aa2e756a570a3458e5a494faa6547c7af7a9af42aec099ecc3022012b4d7f6c5431a98058eea0b958e6af35d1c50adc57e48e9c6b5f9a918bfaccd012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d56db9372b14789128bb88122d32b778362df4c41be6255b7ed15dac30cc9044", - "index": 583 - }, - "coin": { - "version": 1, - "height": 288149, - "value": 1233117, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "d56db9372b14789128bb88122d32b778362df4c41be6255b7ed15dac30cc9044", - "index": 583 - }, - "script": "483045022100d12b40dc9009669e83d151f12d8f260e71cd4c6d84203ea3d46bd4e34174f34f02206cc8dc4f17ad9ec095be93cf4ae9e892612b0f5c616a9d15bf6ec2ea605ad770012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a856898e91e604126ee24a45b3f9c49216f2a067a2adb3458e6337d7bb86db72", - "index": 0 - }, - "coin": { - "version": 1, - "height": 293377, - "value": 4476381, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a856898e91e604126ee24a45b3f9c49216f2a067a2adb3458e6337d7bb86db72", - "index": 0 - }, - "script": "483045022100f25ef9b31780a37161ea7b139aa2b7dceaefbc6a53a7cefe1f1c1fadd8f59493022070d0043695d44966f8096cf6b2bf80e6191fb0dfe2fbb6c515a685e89bf164fb012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c244912c4f1ee799eb9778c0260d6c28fb7e75177ad757b03c6ed5b45c436c31", - "index": 426 - }, - "coin": { - "version": 1, - "height": 287613, - "value": 2505699, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "c244912c4f1ee799eb9778c0260d6c28fb7e75177ad757b03c6ed5b45c436c31", - "index": 426 - }, - "script": "47304402206ab761eae79651f8284dcb6085fccc081fbecf0912a3fa67abd4a6b50e95e37702202f3962f802ec4693d806c50f286f59b2f4972486ec6f55141dbf0fc5c34b6168012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1dbeffb2c8bb3c1bafdd4995315ac1e754b1822c6e9ea90e0ca664a126639a6b", - "index": 162 - }, - "coin": { - "version": 1, - "height": 287861, - "value": 1114698, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "1dbeffb2c8bb3c1bafdd4995315ac1e754b1822c6e9ea90e0ca664a126639a6b", - "index": 162 - }, - "script": "483045022100ae33640eb798b2f227592242251b099d13a49c31c8e3da0c0cdce07800c712eb02200b1492bd51a2f5056ddd4242ea450690fc6633a5d50a3e5ea418b93ac3f81176012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "db32d244c6ba7d1c8bc27ce999aad2942aeb0086a38b6113e1e1520db9cd2155", - "index": 1 - }, - "coin": { - "version": 1, - "height": 285086, - "value": 1285915, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "db32d244c6ba7d1c8bc27ce999aad2942aeb0086a38b6113e1e1520db9cd2155", - "index": 1 - }, - "script": "483045022100fcbac2ed1572f307527db77829a2e942dbccc3d6178ebd91afc4f65f9ebbb1f902204f6b2d4c22422216e1e5305dcc44b4b8a6c83b016c1bead6e454f893973c9035012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f8527acd00befd811fde0e191a45b144f2d86b32a762e21a4142e7c67f615ffc", - "index": 0 - }, - "coin": { - "version": 1, - "height": 285587, - "value": 4636135, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "f8527acd00befd811fde0e191a45b144f2d86b32a762e21a4142e7c67f615ffc", - "index": 0 - }, - "script": "473044022037ac76b34ece94f8c7c3cca5397f090dbecf1c7ead6ecd25484e15de7c11601e022045d639dbce6dab658ae37feecba515fc3a10f4bfb252bfedcc4ba6d5f673d8db012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1891c72741a99deb1200414dc73efe7543e5fa52331c3ce5387867899eaff848", - "index": 0 - }, - "coin": { - "version": 1, - "height": 284631, - "value": 1007798, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "1891c72741a99deb1200414dc73efe7543e5fa52331c3ce5387867899eaff848", - "index": 0 - }, - "script": "4830450221008e17cb1986a3585b3f841949d86747ad28166ac17e2736736d9cb341ad0bf97102202aff78fe920f317e68af3b7f366ad832c6de9beab26c8e9b9e766c951947e2d7012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "1cbe47a66de6d9aa118a3ed7d363e372d91b4e49c8d67528932acfec3df56376", - "index": 0 - }, - "coin": { - "version": 1, - "height": 288887, - "value": 46377884, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "1cbe47a66de6d9aa118a3ed7d363e372d91b4e49c8d67528932acfec3df56376", - "index": 0 - }, - "script": "483045022100986d704470b2add3f3e368cf964c391d631279205b1be6bd75df31c277e6c4ab02200d29f072fa9dfa9bbf913fa8c8cc166a4bda9996ab46dc3c77053bcc8c025fbe012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "69f1f2fd12add1f53d3ac2aadd04c51921646dcad5f4b610188bea19e681a553", - "index": 333 - }, - "coin": { - "version": 1, - "height": 284906, - "value": 1290014, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "69f1f2fd12add1f53d3ac2aadd04c51921646dcad5f4b610188bea19e681a553", - "index": 333 - }, - "script": "473044022068e171ded942bf7053f61d93f7d4a56d520387c82c2f1ac11caa765d877eab2f02201e9f1afc791d2b3259d4eae5a561497625d31fecce713ef7e28bca46ffac060b012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "46fbdaa87c59135a6eff78947b5b9b8493f02a01110e5f308f65d05b6a8c2122", - "index": 856 - }, - "coin": { - "version": 1, - "height": 288131, - "value": 2047444, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "46fbdaa87c59135a6eff78947b5b9b8493f02a01110e5f308f65d05b6a8c2122", - "index": 856 - }, - "script": "483045022100a0fa81a2d1cdb8a47f4b56d084bf393c8ea2f5daad9abebfd7cc8f9cf7afbbb502205aff0cb484e592e053b0e82d1f1a4dd812bee0205ba376266f521bdcd361e168012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e065ae78e64382cbae2b0a61def2ebda993d727e4838c2cc6116661c3c7c6a04", - "index": 187 - }, - "coin": { - "version": 1, - "height": 287802, - "value": 1106966, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "e065ae78e64382cbae2b0a61def2ebda993d727e4838c2cc6116661c3c7c6a04", - "index": 187 - }, - "script": "47304402207498918e2d7c1773fa9ebdb347572fe38336a888cee87d97f7a7e6e483c398bb022079bd525d60c01c520d61cdfed6e3a47b40b953de885df3e3f2646d42f6078069012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a8e4dcd32730580b44b14f6222913e16a58a0131fe3e8f0757a9078145fa1982", - "index": 1 - }, - "coin": { - "version": 1, - "height": 291913, - "value": 4522783, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a8e4dcd32730580b44b14f6222913e16a58a0131fe3e8f0757a9078145fa1982", - "index": 1 - }, - "script": "483045022100a2b601faf559d2b2a42972f3d2c1117cb8bc2c4d1c1f4e746cb29f5cecfa0bf202202c7d3725802f9a0237544dbaf2aa5e4346af9a5599646652fc38a65912ed1aa0012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cbccfbf9755f89165621c55e1a6d7f2310d5b5c2c59fbb49e66ec01a6916c87f", - "index": 100 - }, - "coin": { - "version": 1, - "height": 287942, - "value": 1029093, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "cbccfbf9755f89165621c55e1a6d7f2310d5b5c2c59fbb49e66ec01a6916c87f", - "index": 100 - }, - "script": "483045022100edace2a597b685f6f048005836edc822464146b231c6818a7a1b5ac2af6bff6b02201ad31b971ebc3427a9a7691f020eec7ee5fe23b3d62f0a9ccc7ca194f885d1d7012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2b4b0644d4ef6decb470120c5ff84ec69f18d1e4b7cb896ca418bd3021fd1b3b", - "index": 443 - }, - "coin": { - "version": 1, - "height": 285042, - "value": 1157460, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "2b4b0644d4ef6decb470120c5ff84ec69f18d1e4b7cb896ca418bd3021fd1b3b", - "index": 443 - }, - "script": "473044022029b97f4490b46e26f2bc50944d7497e5fb2265680ecc7aee69492f48d6b391fc022061908f32dc22135980fcfd30012a079880daf65241b5856bb145088024710082012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4d7efe854036017daa38a3c6f71aec84e1f413dfccb003c6ba3fb700ae992a8d", - "index": 215 - }, - "coin": { - "version": 1, - "height": 287542, - "value": 1123626, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "4d7efe854036017daa38a3c6f71aec84e1f413dfccb003c6ba3fb700ae992a8d", - "index": 215 - }, - "script": "47304402200900ac2eb19d20785fba483a8da0511886ffffcf0be81d35647abd2f56f41d4c02200267b0305c5de8dd658ffa42d7387749e72f22485fc1db84ae59a5cf9b35c242012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f59684a0b67bd21a4af7fb1809caddb5fdc3f5c94bd75689bc2f779284c14a22", - "index": 1 - }, - "coin": { - "version": 1, - "height": 295147, - "value": 7003273, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "f59684a0b67bd21a4af7fb1809caddb5fdc3f5c94bd75689bc2f779284c14a22", - "index": 1 - }, - "script": "4730440220780892217c9533eb073f1ce24bd2e3c542b6b1f4448160d61953816099b7901e022055edeecd327262c8527490bf53deba6f887ebb73c84c5487acd25f7b0248ea6f012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "60af995d8c9c425f9017ff1c1369f4bf22fa6bd72814a1bd44f954e2be821f23", - "index": 0 - }, - "coin": { - "version": 1, - "height": 297519, - "value": 3857076, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "60af995d8c9c425f9017ff1c1369f4bf22fa6bd72814a1bd44f954e2be821f23", - "index": 0 - }, - "script": "483045022100edfa83fcd3177321b80eb8f8346e5997386e5bbd7d01d6e32334de92b5662e0602203c971c9d611beff44551dd32b19a5dd0fda1a16c164d5427d18fbccce29cd0b0012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "281dd418ad7b21e20510690fd87e731c3da98b26bbdaa2196068c9794648f85f", - "index": 1 - }, - "coin": { - "version": 1, - "height": 290187, - "value": 2564532, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "281dd418ad7b21e20510690fd87e731c3da98b26bbdaa2196068c9794648f85f", - "index": 1 - }, - "script": "483045022100d08421af462b84a58689a98a1713a1dbfc1804deb07573f4a70f2d2b5b7f73c3022036dbf2947b1d5837bcdd2397d3b4a33179c88ede84959a43dbf7958b2a2a0253012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "89fdc4fe30a0beae28366a4cff894e335c02c93e676a05b465e359e2f5e3f83d", - "index": 199 - }, - "coin": { - "version": 1, - "height": 288008, - "value": 2099998, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "89fdc4fe30a0beae28366a4cff894e335c02c93e676a05b465e359e2f5e3f83d", - "index": 199 - }, - "script": "4830450221009b29339d67d21881183b3097ce83521234b98bd68db49621bd8400867e07403402202ee7e6815c2284b43db983d548561a10f589f8f0703448bfcea27da690c3c5a3012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "69cdad076f0a05521d0a1c995454c3ed6e548a36271e36acd6ec64cce5bf2af3", - "index": 392 - }, - "coin": { - "version": 1, - "height": 287746, - "value": 1038297, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "69cdad076f0a05521d0a1c995454c3ed6e548a36271e36acd6ec64cce5bf2af3", - "index": 392 - }, - "script": "47304402205b7ae043886a89222531c14fa8141eba7b51849d26111f1f9cae91549783855102207aaa0f49b54d573492e7c09b409ece718bf540853f2ce6ce11bc3141e36043ce012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8dfcf65f82a78853962bdc883162a636192ccad8c6366984ae78ce2d613f2eaf", - "index": 0 - }, - "coin": { - "version": 1, - "height": 298584, - "value": 29880070, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "8dfcf65f82a78853962bdc883162a636192ccad8c6366984ae78ce2d613f2eaf", - "index": 0 - }, - "script": "483045022100b6b265c57aad880f157e3c1b6d93e68dab397b71833dd58bdd81b8bf90088a3b022061cdf207a906509c3bfe9b601aa756a7e34957eb61f7ccfe643e96ff2e8be6d6012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "157c03ca012d815cd1cc286532c36c8128833ef673515d2a1a7f387053afd6f5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 286844, - "value": 3437401, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "157c03ca012d815cd1cc286532c36c8128833ef673515d2a1a7f387053afd6f5", - "index": 0 - }, - "script": "4730440220592fb7188e23811d3d2a506a7a7a20d9cdc11d6152816b03a73a26c1177059b502200b725867c2bb2e3890b32992869aa6805f973f8c375e06f4a5d9408dc514ea5c012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7aa8e651ed148b5da0ae62ba2e7f4855cabc224f4140e4f806bb4df655bc4bfd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 296277, - "value": 104284378, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "7aa8e651ed148b5da0ae62ba2e7f4855cabc224f4140e4f806bb4df655bc4bfd", - "index": 0 - }, - "script": "48304502210090deaabe0dd506d2fb6b80837fec9b4af4a36742530fa1e6db20ad8b61d1653d022003b69d3df5adffe9143460e79474e6f04d624c9b390d472a5cfa41f3daf58d44012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0757e68fa1fa0da9baeea2bb4ab6def16300aa9f28b93d3fd38fdc809719b488", - "index": 1 - }, - "coin": { - "version": 1, - "height": 292417, - "value": 4244600, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "0757e68fa1fa0da9baeea2bb4ab6def16300aa9f28b93d3fd38fdc809719b488", - "index": 1 - }, - "script": "473044022011005002cd5adfcdeb97de0333ee187bf66670ffcc7b1d055ed4e8aa9eb6f8c2022044ef7a49ffb12ed763ce6c3ac9e6413d779f76f26f28f03a4856e7e866c6e86b012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3fd61798b154933fe0b707f1125cd11e3869330a0f265eae103eb1b8ff3184c0", - "index": 219 - }, - "coin": { - "version": 1, - "height": 288225, - "value": 1184852, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "3fd61798b154933fe0b707f1125cd11e3869330a0f265eae103eb1b8ff3184c0", - "index": 219 - }, - "script": "473044022003d04ec07779ba051c14fa37c10ab645267f94b9a44fa3de8f827266df8fc98b0220349681e2092b5f3c24112bad33962421adf317a9a82cfe435f2618f746a1d0ef012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3d1690324c80668601ee27b1f7211837b51c5d4ef44e3b2c94317f1435070860", - "index": 0 - }, - "coin": { - "version": 1, - "height": 290384, - "value": 2828282, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "3d1690324c80668601ee27b1f7211837b51c5d4ef44e3b2c94317f1435070860", - "index": 0 - }, - "script": "483045022100bd1aa1bc0c68a0206dfc8e774e8008f428522366012e10dc6016399d4a5e438f022060bc2e4d711eec687ea5fa8bcbecaf9356ce253928560d80e6d8808b8b0c6d1c012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7272e8bd90ba4d700b516d30c4e9b572e37af4069de4f0d653d255f2a3fdfb48", - "index": 0 - }, - "coin": { - "version": 1, - "height": 291913, - "value": 10316413, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "7272e8bd90ba4d700b516d30c4e9b572e37af4069de4f0d653d255f2a3fdfb48", - "index": 0 - }, - "script": "47304402205adef3ffbab7926135f559f6fd1aa1d486e9077adf5a396b34c6f58eee6613ef02201e9f36a867a0c848e70ca00fba1c001a3823ee3884132d9c22ace48d4fb9aaef012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b9b0824db21b439f8affe40989d00b59c60b781c2b1f41b959ae46be93234473", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297519, - "value": 9995575, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "b9b0824db21b439f8affe40989d00b59c60b781c2b1f41b959ae46be93234473", - "index": 1 - }, - "script": "47304402204a099a265e784b57981ffd80ba890e37a84acccd53c195606858bc50633024250220187c75a5dfb75b4ae30520e401e0f4b3d7254b951b1f65ee51b5ccf75fc67c21012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2b3a93ec99a8dbd7490785a96cbc5cd057ec7a0a30c56d6ecebc2c6fe1cd3164", - "index": 1 - }, - "coin": { - "version": 1, - "height": 285661, - "value": 2700000, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "2b3a93ec99a8dbd7490785a96cbc5cd057ec7a0a30c56d6ecebc2c6fe1cd3164", - "index": 1 - }, - "script": "483045022100b33c075c7183bd5b675f0130c4aee018771736f8510901c9bd4190443823934c02206c2a3ac9becff3d0ea72ee228cf1c08b9022c7d567a12356ea55a04499762bd9012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a8c25a997308004cab55886324b4d3f3bad52c853f1a2aa2bc96dad098fa8024", - "index": 543 - }, - "coin": { - "version": 1, - "height": 287706, - "value": 1236812, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a8c25a997308004cab55886324b4d3f3bad52c853f1a2aa2bc96dad098fa8024", - "index": 543 - }, - "script": "47304402200b6cd330ee6409977d04863080b57ea0b9cc8fe568da41ec5916ed0c7c74035002203fcc6da024e84a80e1cefdf4010ade8f6bed2ec2658d17ab71b2fed5b78255b3012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "82b64ef6163b009f1c10f934bc1f2b349729d56b86ded836f94c7ed763d3e8da", - "index": 1 - }, - "coin": { - "version": 1, - "height": 285493, - "value": 3735627, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "82b64ef6163b009f1c10f934bc1f2b349729d56b86ded836f94c7ed763d3e8da", - "index": 1 - }, - "script": "483045022100d5bdabe0fa57c7659441df64823f0b8f1b4cc1a63bbcc9d1df314abef6b020230220575ff35a69e10eb3a1a41b9cd359af8b1b97c6d60596ab24f59d2a363901c602012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "08fcda5a7b6b778474e6f88a919ea7393370cab565558187395bedc65c896c95", - "index": 55 - }, - "coin": { - "version": 1, - "height": 288248, - "value": 1073579, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "08fcda5a7b6b778474e6f88a919ea7393370cab565558187395bedc65c896c95", - "index": 55 - }, - "script": "47304402201b37ff63d09ff44a006561c36d849a577be2f0e26e3c4715e90fc31590e942d50220028e36aa076c7bd68d584b381b8d1a895d884ea5b01402bad86bfe4554e987ba012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e1dfcacafad7da9bc543bc7174e4f1783dd610119e5e9d92c0dce68d45a6ede3", - "index": 1 - }, - "coin": { - "version": 1, - "height": 290907, - "value": 2361423, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "e1dfcacafad7da9bc543bc7174e4f1783dd610119e5e9d92c0dce68d45a6ede3", - "index": 1 - }, - "script": "483045022100e0dd5678ff67669830e8b6230d8233b8b8e6fc932c3fc29ec168b4e008ad5bbe022036118943a79f7617f897e5c1c9ed64f7050b37683623e9b0600e83353fae0608012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "46e3b4c917cfd1df26ed4ff95252ea2f253b87440fb683e025d3c599016b1287", - "index": 230 - }, - "coin": { - "version": 1, - "height": 288320, - "value": 1204820, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "46e3b4c917cfd1df26ed4ff95252ea2f253b87440fb683e025d3c599016b1287", - "index": 230 - }, - "script": "483045022100b80b95aca2da16e7a0ae98421859c58678e089988ce83501ee1d118dea828c110220145ae63d7711d38bd06d1a9ae4342a326e7c322168b31cd95f29ff79d8c5df86012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a90da42b6d9a34f3e3aa2927856c80ed8898f40e5fedfa590be2e4270224232d", - "index": 1 - }, - "coin": { - "version": 1, - "height": 290206, - "value": 24950537, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a90da42b6d9a34f3e3aa2927856c80ed8898f40e5fedfa590be2e4270224232d", - "index": 1 - }, - "script": "46304302203858bfe6db4dfdda2acaf58950c7fdeb475cd83c594849089a504357920a45be021f796212bb8cbd0882e5977de92f71e065e72b6a50dffcccfb6e7370dfb2ae07012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cfe60bb39113e1988de7ce953556702c24369368dbb21bb29ba388358bcb2768", - "index": 0 - }, - "coin": { - "version": 1, - "height": 288651, - "value": 1550175, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "cfe60bb39113e1988de7ce953556702c24369368dbb21bb29ba388358bcb2768", - "index": 0 - }, - "script": "473044022063113d366e60ca569c1828e1ed3c10a253ed1cd06b74dd272e34e2bc19353d0202205d893369a1807bbf97ad24af141ab2c07d53717671783eab34bd213d59770d94012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "d65e67e295c4943a48e81f46bccf1db8bc08ac07d63d7ea60ea20c12392a773e", - "index": 0 - }, - "coin": { - "version": 1, - "height": 286720, - "value": 5274530, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "d65e67e295c4943a48e81f46bccf1db8bc08ac07d63d7ea60ea20c12392a773e", - "index": 0 - }, - "script": "483045022100c1e9cb771a485ef5cb4a6ef9b21983e40d0e933f1d068a97c45b6674401cc17402207bd4085910aa8e460a253a0a60c5f5239fd554729150a74328f999f961e95e51012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7b5759b0743c7318526be43939bbc6eb00dfbe9cd8b5cf308f47b9b58316085a", - "index": 1 - }, - "coin": { - "version": 1, - "height": 288870, - "value": 9835000, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "7b5759b0743c7318526be43939bbc6eb00dfbe9cd8b5cf308f47b9b58316085a", - "index": 1 - }, - "script": "483045022100ad20ee828657ccbf8b6ab9bb4161d0ce79717bf68852c64730f7fb890b2b8436022020de6d2f915a9dca60c339aaac7962ee122ce492c021da6b27be5695de71d9d8012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7ddd67c232927508002da4314efb75a300d31f0c83470b6f482f58a436bafe10", - "index": 1 - }, - "coin": { - "version": 1, - "height": 296441, - "value": 45494662, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "7ddd67c232927508002da4314efb75a300d31f0c83470b6f482f58a436bafe10", - "index": 1 - }, - "script": "473044022002599f6eee2e735bdb87b4269d038a4d79fa8ada0b259b0107b0b48fd039abea022036c3c5ea408f8255cfe1b9041dace25ed1979201f1014a04ee785bcf3f77981f012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "27607ed821129ccc25cd28deecc24da2673d5a58188311d516117ce771431e24", - "index": 1 - }, - "coin": { - "version": 1, - "height": 289734, - "value": 9427744, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "27607ed821129ccc25cd28deecc24da2673d5a58188311d516117ce771431e24", - "index": 1 - }, - "script": "47304402203d63b7e76f3c5c1d5cfb38b2c6748295d1be60bf5746eeb81e6a28db091e07c8022061a191416e97e8c5cf2a4d8a3fb3cb3d7f0a2249ae204e77341c09d203c2470f012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0335a014dfef66542f31c4112fd48df8f20ad5c15858641d1743a9968ea73efb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 287371, - "value": 3817731, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "0335a014dfef66542f31c4112fd48df8f20ad5c15858641d1743a9968ea73efb", - "index": 0 - }, - "script": "473044022015d995804f0b949e41ebb8b3d710f8f8452d7aba844b31b230b0d0ed71eb32cd02206ad3d553eef1ff03db07d321291b349b4df84981ce01794a8e117a4b6bf3e6b4012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e86370a0c7dd3dbeda9707389fdf3b0ed610516a18514f86762db93351f667b6", - "index": 0 - }, - "coin": { - "version": 1, - "height": 288888, - "value": 13323600, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "e86370a0c7dd3dbeda9707389fdf3b0ed610516a18514f86762db93351f667b6", - "index": 0 - }, - "script": "483045022100acc22543ce450ee1fea7447676f9b7c172a657af86a5f8f2131c6561c950eacd02203a61fd249a201cea2270e4e050c7136740768e5b024a51394b7f059d0c50cc18012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "b319d2a5d237d517cf661184d121562af4ffbb529fe9fcfe5d812afd5910ba51", - "index": 0 - }, - "coin": { - "version": 1, - "height": 285622, - "value": 2112523, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "b319d2a5d237d517cf661184d121562af4ffbb529fe9fcfe5d812afd5910ba51", - "index": 0 - }, - "script": "483045022100dfe7d2382c9ffe5b71470e503a5d38411446b2e26177dac26707f71af651df3302201d131bbfa22cceb2a41a93307155e3bf1963ea29631c569fc0089c3d0443f2a3012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 400000000, - "script": "76a9146e59a226a606a6a0098ec05660947184f364cc9488ac" - }, - { - "value": 1874520, - "script": "76a91499d372febac39ddc6feb39eeb0cb25f7b3836da688ac" - } - ], - "locktime": 0 - }, - { - "type": "tx", - "hash": "9f7704a69ef678d08755f1aec2ee7d7517c4aa82525d8c926cdce523f9863c23", - "witnessHash": "9f7704a69ef678d08755f1aec2ee7d7517c4aa82525d8c926cdce523f9863c23", - "height": 300025, - "block": "0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c", - "ts": 1399713634, - "ps": 0, - "index": 460, - "changeIndex": -1, - "version": 1, - "flag": 1, - "inputs": [ - { - "prevout": { - "hash": "a5e57eaa7ea2a32dc551aa64a6bc4c56c3a5edb1ffe2cc43dd6383b67a6e7634", - "index": 1 - }, - "coin": { - "version": 1, - "height": 284079, - "value": 30503, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a5e57eaa7ea2a32dc551aa64a6bc4c56c3a5edb1ffe2cc43dd6383b67a6e7634", - "index": 1 - }, - "script": "483045022100fd9c59cfbbf1207804d9eab9869287ed5cb55b9a429e44460b1e419b737f14e0022069d359c1a499a8bc50850b47834523489bdfa12891665659e35b70c099538939012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "180c2997aa9bfaea55e7ba9879bb8a16c0a314437fb5f2c5f2532fa0e9b852d9", - "index": 0 - }, - "coin": { - "version": 1, - "height": 295829, - "value": 1279868, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "180c2997aa9bfaea55e7ba9879bb8a16c0a314437fb5f2c5f2532fa0e9b852d9", - "index": 0 - }, - "script": "4830450221009c5a20de437f87c387cde16ff36e5af00fdd30bef134186612b3975d288c365e02206d7dab245f653534d4c86553f066aece1205d573448be392ca5dbef0bdbb36ff012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "9c2f1f3a9a18e245104a169d313f15ef19d158a2caad239c3625740feb457f0e", - "index": 1 - }, - "coin": { - "version": 1, - "height": 295460, - "value": 505229, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "9c2f1f3a9a18e245104a169d313f15ef19d158a2caad239c3625740feb457f0e", - "index": 1 - }, - "script": "47304402201d32d01bd6cfe9ec93e86c48db831471fbd32dd43226680166c7c8a7d6bda3ee02203c8c9a971954e13aad84b30b2b3ad7ed1081f03f2b571f424315f5b44fb1e8f6012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2b9d32d588bbbeddbefc8fa7c6606670c84b18967fd9fd9ed5c8152ab00cae76", - "index": 1 - }, - "coin": { - "version": 1, - "height": 298908, - "value": 3786068, - "script": "76a91499d372febac39ddc6feb39eeb0cb25f7b3836da688ac", - "coinbase": false, - "hash": "2b9d32d588bbbeddbefc8fa7c6606670c84b18967fd9fd9ed5c8152ab00cae76", - "index": 1 - }, - "script": "483045022100b766091ee720d17c0f52ae85c848100fd2468fab3f434a8fa05b1124707b4706022048f300d237322e176da9e518b0d839a9dffe8a80524e2cfd73a1e503d7abdb7a01210269c0dc33b2bde69b558783bb922c1180d4212adbd3b25ea576a14799a5066e17", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "2a1c6f1101863a8dd06785e4d3d49e1204a265260dade62e048dc0f460f17611", - "index": 1 - }, - "coin": { - "version": 1, - "height": 289691, - "value": 983198, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "2a1c6f1101863a8dd06785e4d3d49e1204a265260dade62e048dc0f460f17611", - "index": 1 - }, - "script": "47304402205947449d9f27e0e86b79b2d013c75837774118a6e9fc61854d2f1f43e2cd65390220219e77f5204c5d87efff402496587979ec798d6e36c6aef8d2ba47b3cd958161012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "c080b81cf47a295d7558103b5c7977a59eb80c0f898e2fab9300431773a4d271", - "index": 1 - }, - "coin": { - "version": 1, - "height": 292574, - "value": 350000, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "c080b81cf47a295d7558103b5c7977a59eb80c0f898e2fab9300431773a4d271", - "index": 1 - }, - "script": "483045022100cb1966f372325f1d959c31799ad0dfccc0832d7cbd8b69001c0191acb1122754022024e3201d055cb3930599f3e21b4cdf01a28f8282ea2c8b70dde83ebb903dc6fc012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "109fb0622c21e507d00fe0040e1fde1ff1dba2b928966d2e2bd4d5acf36781b2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 292069, - "value": 985918, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "109fb0622c21e507d00fe0040e1fde1ff1dba2b928966d2e2bd4d5acf36781b2", - "index": 1 - }, - "script": "47304402206664924bbcdb4eab7835a3448317af857c30cd8b36677603e06584ded050522b02204c71a1c8fbd57b133a052f9becb96b1af64d341ab3a8f00180eb3a99aabdb6c9012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "cd3892a28724541c33a7cac8b0dc2bebe3f5c64abd7bf5137a460d975694f876", - "index": 117 - }, - "coin": { - "version": 1, - "height": 290768, - "value": 2031905, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "cd3892a28724541c33a7cac8b0dc2bebe3f5c64abd7bf5137a460d975694f876", - "index": 117 - }, - "script": "47304402200b3a060cdcd0e208d2a39a8eaf04abe49e54e40b155f7cf3c5788a664c87f609022059bf6dbfd8ed83d9466d1a63c94f2d470fc91e2c2edcaea02417c3c590b7ff28012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "4b3f78b69467cf8de803675fdba4639af8bc850fe038ace812cb484624d91aa3", - "index": 0 - }, - "coin": { - "version": 1, - "height": 292187, - "value": 1358932, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "4b3f78b69467cf8de803675fdba4639af8bc850fe038ace812cb484624d91aa3", - "index": 0 - }, - "script": "4730440220569fba2a700e88c1e5505904d2ef29c22ccfc6f601765d851706997de1fb76aa02207934c7368a17d6bffa12a4b7dc41e9649382732f0a46a77605f0c3d86ac28acc012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "7ce010bbfc18bb8bb6d1ebf5c2999cbe328e756197ca2e254772ae9ffc4c1ad5", - "index": 0 - }, - "coin": { - "version": 1, - "height": 293593, - "value": 1647595, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "7ce010bbfc18bb8bb6d1ebf5c2999cbe328e756197ca2e254772ae9ffc4c1ad5", - "index": 0 - }, - "script": "483045022100bcb0e83397f91ba3ba0eb9d6ea9f2cec7c9bcdd099f1a811d12fb39afc154dad02204af16b5537a861cd310ae2d905d9949b06a9b055b22a059deb3e85b8a487e886012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fddd0ebb9714e1a1dc2d5f4e1d5175bfb7d4fba31c00d1bccdf6ccc8b09334b7", - "index": 44 - }, - "coin": { - "version": 1, - "height": 289075, - "value": 1025598, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "fddd0ebb9714e1a1dc2d5f4e1d5175bfb7d4fba31c00d1bccdf6ccc8b09334b7", - "index": 44 - }, - "script": "473044022012ce4da043dcaf77c8148a7d60a8890e4a636a6df9e17368bde7cfc5357ac98002204de66077ed0f088a8270ed85ea819ab36efcb236ea704c8f19ddc11a86849c88012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e7bfaebb6293c3cfa14bcd7926609fc52e06b11aee5068da6055db41d0287bbb", - "index": 0 - }, - "coin": { - "version": 1, - "height": 292574, - "value": 950000, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "e7bfaebb6293c3cfa14bcd7926609fc52e06b11aee5068da6055db41d0287bbb", - "index": 0 - }, - "script": "483045022100cbe547f9a9d3ab678ba21ce2fded988cb46cfac367a4a13a5ef5b35c33141b82022006371144f38d06a5dd34c6ca49a8b91b258240160d572131055ea9d837f4aeb7012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e47d0bb81472c6697cbb41607a923d0e2ce00f2b1af1a37d1fa371f45dcc2864", - "index": 0 - }, - "coin": { - "version": 1, - "height": 295291, - "value": 1295119, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "e47d0bb81472c6697cbb41607a923d0e2ce00f2b1af1a37d1fa371f45dcc2864", - "index": 0 - }, - "script": "483045022100898ace52b718946abc9db85ea295e2d0001587f02bd2415282441ae73cb415b902206f9cfa06e1758231f47a5d102dc549d9ad024ca313938f06f08d7eb88225e899012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "3d0afc6606ef0dd325fa521d6ef2ef838843b026e6461e7684c7cb86f0a0a254", - "index": 55 - }, - "coin": { - "version": 1, - "height": 290122, - "value": 1554758, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "3d0afc6606ef0dd325fa521d6ef2ef838843b026e6461e7684c7cb86f0a0a254", - "index": 55 - }, - "script": "483045022100b249415abef29e305e6891d065cabc9b366404a3b83c6e01a8844689b931d1dd02203096f1b6daf3b96df578fdc61823f92f11f291b2393a0b0ecd37fc3c4f79af71012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "e69c96036a2067824b1062ba0d8bf3adf6af189a4f68a1f7114506d5e919edb2", - "index": 1 - }, - "coin": { - "version": 1, - "height": 288936, - "value": 2005159, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "e69c96036a2067824b1062ba0d8bf3adf6af189a4f68a1f7114506d5e919edb2", - "index": 1 - }, - "script": "47304402206950d1c4a8af60c2e21bec9060119b3ad7093cb7e03707475ed838cd2b1de2fa02205862b602d1c070baf8a7b42b469d5ab3ff627de380e65863c7701ec8587f9edf012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "53c388a6c37fabe55d8f1e299c81fe6ff1ddb7c1a273f773e542746d290e9fd8", - "index": 73 - }, - "coin": { - "version": 1, - "height": 294434, - "value": 146425, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "53c388a6c37fabe55d8f1e299c81fe6ff1ddb7c1a273f773e542746d290e9fd8", - "index": 73 - }, - "script": "4730440220614f48a50ffe43a78aea45b97b38ac1f0e2cff3c71d5d675dedec1d4656dccc8022027b6be1094ac34d7fc0baa324638d9d951b0bb190d26ea1d03cd67372fec1056012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8501efa71303a974549d45bc22b7f4d46f882a2877225a2f34410384074b9cfd", - "index": 0 - }, - "coin": { - "version": 1, - "height": 295652, - "value": 1390102, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "8501efa71303a974549d45bc22b7f4d46f882a2877225a2f34410384074b9cfd", - "index": 0 - }, - "script": "47304402204780d7eb10191925bf129be1f736a598af1a640743a9b4fe00d3fa631ce5e23402204e528db4f1402b7ef65439a82a9effc6d2ab30e9ae79d664a7735d1620f88b76012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "033b4f43a449537b0bf9767bcf7423f54bf74aa0433c2482406aa50d54fad169", - "index": 0 - }, - "coin": { - "version": 1, - "height": 295398, - "value": 948805, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "033b4f43a449537b0bf9767bcf7423f54bf74aa0433c2482406aa50d54fad169", - "index": 0 - }, - "script": "483045022100916bbd6a1deca52e3c6dc4f64868945b8304fef4ac566a20924760876f36786e022043bc5a0bd083acd57e6048b419f2dc4bb95ac25238093454a1319c9443664f8a012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8ecc7145c04fef8ed19809822a44ae4799ba3ddf408e844872ec88d145168578", - "index": 0 - }, - "coin": { - "version": 1, - "height": 292574, - "value": 104500, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "8ecc7145c04fef8ed19809822a44ae4799ba3ddf408e844872ec88d145168578", - "index": 0 - }, - "script": "483045022100b2486e8018f90242250443f677e48b53a0d1ef6136615389f120ac11d6f1d32d02202f4d8f9cfe75dd90c18f6d7d4308837fa9e0463f83d64313c09221333fd49bfa012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "05415069db265b8c7484f9801413105937e20eb8a4e9d069b941ff16f1abb754", - "index": 1 - }, - "coin": { - "version": 1, - "height": 295878, - "value": 704302, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "05415069db265b8c7484f9801413105937e20eb8a4e9d069b941ff16f1abb754", - "index": 1 - }, - "script": "483045022100e44fb23f76a18b545efb57834a0ea5bc650e362ebb0a9e9df0124d6aefdaf6c7022042978543c6a56514d81fae83d62a33d74293d12c501180c780b0bac3a3caac93012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "0557f8a01e60737b7549afb829c777d5fc22d7dde5ce56953f8b65d8fb438859", - "index": 1 - }, - "coin": { - "version": 1, - "height": 292411, - "value": 1882789, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "0557f8a01e60737b7549afb829c777d5fc22d7dde5ce56953f8b65d8fb438859", - "index": 1 - }, - "script": "47304402202a7fd372e3d78564b1a11a7270bc4fb2c5a4188e78a92077604a981fd3f20f9802204d166b65722960cc1ac560a24817f9c76957b604152c2d236c97b1bab0adafbb012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "44553bb44d9f6c25f8617437fd4bb2d562f854e783a13b084086c03e4412683c", - "index": 776 - }, - "coin": { - "version": 1, - "height": 288521, - "value": 815862, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "44553bb44d9f6c25f8617437fd4bb2d562f854e783a13b084086c03e4412683c", - "index": 776 - }, - "script": "47304402205189501a79963e08781b05d332f7a6978020fb4f03647063db3f0dbb885638e3022065c7552a2fe425647a9f463aea0a7f5ef3896fffd5ee59f362e1e1c78fcda7cc012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "65ba438da066d29a779c00f50bc45c34b401f4713d87b6135c44dddde9998db1", - "index": 371 - }, - "coin": { - "version": 1, - "height": 289016, - "value": 1068445, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "65ba438da066d29a779c00f50bc45c34b401f4713d87b6135c44dddde9998db1", - "index": 371 - }, - "script": "4830450221008d45bfa4b40af847ef5a0be9d8b7759b8dce3c2efb63c2a81609b4d2b425ab33022027d2214d2ccc8d12fff9e0bc02baab3d492f93c4b1448fe3f3526a4112e41f30012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "fa272b22e8d20b96d0cc9099522ffe4d129f57970612e4a636c65a93d9718a84", - "index": 121 - }, - "coin": { - "version": 1, - "height": 286410, - "value": 10000, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "fa272b22e8d20b96d0cc9099522ffe4d129f57970612e4a636c65a93d9718a84", - "index": 121 - }, - "script": "4830450221008a7c7d253d9901cad4ae1e3bd839d08bb9a299191e7ba47e965603c09c7b99e90220642027f234efd5b180bd51f8ae682f97236cb81d59866c24dc04de0b583616d4012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "a1b3bf3d2ffec94a2c07da654f23b7f4c7e234947c59fded8de8c8cda312faef", - "index": 206 - }, - "coin": { - "version": 1, - "height": 290766, - "value": 110563, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "a1b3bf3d2ffec94a2c07da654f23b7f4c7e234947c59fded8de8c8cda312faef", - "index": 206 - }, - "script": "4730440220413221a0cdf755af0cf548dbebd8715aee2e870d3366a2a03a50bef85aa4b0b5022069ca8b71bc64f9e37ba076aef967c069aa2678755ad8a736a8232ee3513b33bb012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "daf581d42fc2d552fb068b7f43b9f3dd6edc9a8ff0bccb44b83c1a996e6e2b38", - "index": 151 - }, - "coin": { - "version": 1, - "height": 289627, - "value": 636293, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "daf581d42fc2d552fb068b7f43b9f3dd6edc9a8ff0bccb44b83c1a996e6e2b38", - "index": 151 - }, - "script": "483045022100c7e3820a398e581ec03463dad27f6f3c7ad81ea995c9749fb2460f96a273581f02205f0f225e4bd6bd860d80f9bb14674b9a4a6af4d3ac4f512a9c3e3ba72bf68fcb012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "21d9febfddd0482ba73c4a43917881930039730776236ad40dc9684a8c921c0d", - "index": 363 - }, - "coin": { - "version": 1, - "height": 287308, - "value": 139560, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "21d9febfddd0482ba73c4a43917881930039730776236ad40dc9684a8c921c0d", - "index": 363 - }, - "script": "4730440220226eaa89ad0be809514b3fe226edeba97d32b67315d7170ba490a089016ccaeb022028b2c90a07c978d5bc5a60e6d6de5e1650396abf3e1c6f7207e2c945ed6e5456012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "8a7c1b84c5eab983b6f364f1a6cc2170236c66e1b9e77d4cb817396fe57a362f", - "index": 0 - }, - "coin": { - "version": 1, - "height": 292411, - "value": 175168, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "8a7c1b84c5eab983b6f364f1a6cc2170236c66e1b9e77d4cb817396fe57a362f", - "index": 0 - }, - "script": "47304402204bbf6918b9346eb1b6e07905c6f760bba0a636e03daa2f2083eb697e5273319302201376106c0bb6cf81ab0fccddd51a5dd52a83a24079d82276bb347e4477139290012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "6d842a7e1b2bcb44a65392fd850d48c43a637edee21ffab58d78a191cb375f88", - "index": 38 - }, - "coin": { - "version": 1, - "height": 289964, - "value": 1083015, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "6d842a7e1b2bcb44a65392fd850d48c43a637edee21ffab58d78a191cb375f88", - "index": 38 - }, - "script": "483045022100f007ff53b390df8d4914ada8a926589dca6f69ff7adca1b3f4479dfe0e3a476a02201166221255d3ff2ff6e99c6d264680f7ea529a20314abf90453aa9950fec1997012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "012d3307c2d7c4fd9fc0244ac94b64dbf4f7d901b7f19c8b08134200806fd274", - "index": 1 - }, - "coin": { - "version": 1, - "height": 297658, - "value": 2108602, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "012d3307c2d7c4fd9fc0244ac94b64dbf4f7d901b7f19c8b08134200806fd274", - "index": 1 - }, - "script": "483045022100890c9eea66c6805f32f6c91ad663d3c03dbaaf80d776a1416db371e9badcb526022015b6c5779f4d7693539ed392e7d7ca6bba6206e6cf9daf1f0fe41096ea6234c9012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eea6a77113f19fa44fc62beec6c693971a68a422e8a9c87c44583d97698c9a5b", - "index": 1 - }, - "coin": { - "version": 1, - "height": 295073, - "value": 1294139, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "eea6a77113f19fa44fc62beec6c693971a68a422e8a9c87c44583d97698c9a5b", - "index": 1 - }, - "script": "4730440220773f620674cde7a4c7728982286a456098bc3ec5f8b5ff121f57bf5620965070022073248b515cb6462f4d8f02aa7f68b9c36c2d607bd21ebff7e8ea44ed1e56326b012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "5ba4ee96e48d754d9c4727585f8a4da7217df1d9279aaabe4d8a6aef1b6ecb32", - "index": 0 - }, - "coin": { - "version": 1, - "height": 292574, - "value": 350000, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "5ba4ee96e48d754d9c4727585f8a4da7217df1d9279aaabe4d8a6aef1b6ecb32", - "index": 0 - }, - "script": "47304402200d03ed21ef177cec8b6b5b6968f51f1a41995fcfa43a33786ced111b8b4a62480220523a031ea20d7535d32bae2918e2f14df430f62e6d78cbb96fc919e3dd008f93012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "118bd27cf6d2ebf8a0bcdc7faf106f84f62ed0f9ab68600f6e675e5a40a236a2", - "index": 77 - }, - "coin": { - "version": 1, - "height": 290306, - "value": 881121, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "118bd27cf6d2ebf8a0bcdc7faf106f84f62ed0f9ab68600f6e675e5a40a236a2", - "index": 77 - }, - "script": "483045022100f31baab4ce1a1ef1af8652da507c61dcd4a8b8beacd84b4e43bb0f9bd6c8e514022067c2d66860ddc796096a0a08283ba20cd687a3dd6e88ac56165aef59caa5bcc6012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "eb65f914814460cff8ce7257d87a6ff1aa5b6fb6eb88c2188bf2e1ceefb69db9", - "index": 1 - }, - "coin": { - "version": 1, - "height": 300025, - "value": 1874520, - "script": "76a91499d372febac39ddc6feb39eeb0cb25f7b3836da688ac", - "coinbase": false, - "hash": "eb65f914814460cff8ce7257d87a6ff1aa5b6fb6eb88c2188bf2e1ceefb69db9", - "index": 1 - }, - "script": "483045022100d0c0e74965055e0975fd00bb2b51e14a41b346e1dd129c373ce7389d623c9b8502207c04da477b7adcae68bed5230e6c4673021c20f3430224dd49b458330309924d01210269c0dc33b2bde69b558783bb922c1180d4212adbd3b25ea576a14799a5066e17", - "witness": "00", - "sequence": 4294967295 - }, - { - "prevout": { - "hash": "f33fb429f338d9fae4f0046523047fdaab24611ddd6758cf925840254bcd0930", - "index": 0 - }, - "coin": { - "version": 1, - "height": 287387, - "value": 196041, - "script": "76a914f1fee1bb6451f0d7310d4a3c84c30abe2f0fb9ac88ac", - "coinbase": false, - "hash": "f33fb429f338d9fae4f0046523047fdaab24611ddd6758cf925840254bcd0930", - "index": 0 - }, - "script": "47304402201c3c2c706c8d866a1bf8779a7cd3bd5bf715ec02cce66ed53feabab980b5183d02206fdeda32d334863062c13cee82718d1b512912359156246d25deb55d74155ef0012102ec8ffec825bc4fa6f22cd58559dc65e124b53ab3be1c7d6f792d2607db2cfe5b", - "witness": "00", - "sequence": 4294967295 - } - ], - "outputs": [ - { - "value": 35400000, - "script": "76a9146e59a226a606a6a0098ec05660947184f364cc9488ac" - }, - { - "value": 250102, - "script": "76a91499d372febac39ddc6feb39eeb0cb25f7b3836da688ac" - } - ], - "locktime": 0 - } - ] -} diff --git a/test/data/block300025.raw b/test/data/block300025.raw new file mode 100644 index 000000000..5b3b1b7e0 Binary files /dev/null and b/test/data/block300025.raw differ diff --git a/test/data/cmpct2.bin b/test/data/block426884.raw similarity index 100% rename from test/data/cmpct2.bin rename to test/data/block426884.raw diff --git a/test/data/block898352.raw b/test/data/block898352.raw new file mode 100644 index 000000000..9599e3cce Binary files /dev/null and b/test/data/block898352.raw differ diff --git a/test/data/block928816-undo.raw b/test/data/block928816-undo.raw new file mode 100644 index 000000000..102a80223 Binary files /dev/null and b/test/data/block928816-undo.raw differ diff --git a/test/data/block928816.raw b/test/data/block928816.raw new file mode 100644 index 000000000..a7db31cbc Binary files /dev/null and b/test/data/block928816.raw differ diff --git a/test/data/block928828-undo.raw b/test/data/block928828-undo.raw new file mode 100644 index 000000000..375229e27 Binary files /dev/null and b/test/data/block928828-undo.raw differ diff --git a/test/data/block928831-undo.raw b/test/data/block928831-undo.raw new file mode 100644 index 000000000..bc7417a62 Binary files /dev/null and b/test/data/block928831-undo.raw differ diff --git a/test/data/block928831.raw b/test/data/block928831.raw new file mode 100644 index 000000000..1cfb44149 Binary files /dev/null and b/test/data/block928831.raw differ diff --git a/test/data/block928848-undo.raw b/test/data/block928848-undo.raw new file mode 100644 index 000000000..65fcec76a Binary files /dev/null and b/test/data/block928848-undo.raw differ diff --git a/test/data/block928848.raw b/test/data/block928848.raw new file mode 100644 index 000000000..f641ecfc3 Binary files /dev/null and b/test/data/block928848.raw differ diff --git a/test/data/block928849-undo.raw b/test/data/block928849-undo.raw new file mode 100644 index 000000000..a88a57888 Binary files /dev/null and b/test/data/block928849-undo.raw differ diff --git a/test/data/block928849.raw b/test/data/block928849.raw new file mode 100644 index 000000000..9609f1a78 Binary files /dev/null and b/test/data/block928849.raw differ diff --git a/test/data/block928927-undo.raw b/test/data/block928927-undo.raw new file mode 100644 index 000000000..e99cdbd99 Binary files /dev/null and b/test/data/block928927-undo.raw differ diff --git a/test/data/cmpct2 b/test/data/cmpct2 deleted file mode 100644 index 7bd1b83bb..000000000 --- a/test/data/cmpct2 +++ /dev/null @@ -1 +0,0 @@ -000000200808583f29b95b0d8bd99960c9b07d41620618cbddf3660400000000000000003b400d9122a388cafb9dcb14b2dcdd0f90d4a757e621ba7e6651212b383e977fd3b4bf57dc0e051898002fadba06f0cb11b496fafd9801825ef4177fad4f374cce6fd1cdb636a69bdabe5e75be3da6e5bdd17fe8d6e1b71022361517b0b732a3040f919dba82030bc09c1bcccd255774fa271daa79e146ca8465309c82ffd1943c7ae2d51a8cc5134a14749e7611ee2a003593b312dbad7b597c2f211783a602ef64e9eab4ba2209ddc6d53ca166bc49c1b2509b563b0d09bc2a139268151137c8cac321b36658e088e018baff503c7b11a4e0e7883c232a240a00dd2612711affb2c87afc10ccc3b80e21c724fd5d10d7e6f0defa9cbeb4b196909a3a9f57c0430fc117f3ccf7b891dc4258d13b33611d0afcf556e12f907249367134728a85c5339067e05c33eccc701e27860fb1f5126e572a0acb7e9a3822cac6d4f68bd93c05009b628daf1afcfb47855cd6f066d4e3331398ca649250744b0217ed0a83c14a35f393f281bc7f4e22d10d7bc9e924785e6abf31993ea5216ed1e85f004aa8ba870aa91d4413fd70ff5e0b2dd51ff9f90c7dd1564c1a1e7be3ff45f624a157b19901942c3a8e31053e2b7b7a1016a340ca6b59b341e0677818081fa2cdb773708b97fdfef2f7ebac1852118c9271dd912696b4d57eba2356b632e18c9418482c6c97c4bd46b6336962ee4630a3eb34cc609e76441e55930ad80479de821b04d6c1eb62847506e6ee5f1f8e3b796633016494d6ac28fbc7a63aae4e3cc9f4a6d4d539a4aa0453a9844596b4953ffd2a7dc3c41e989e721c62cad99cd1b1a3dc127deefa417bf44b0538f9032f1e57826e805a9517cb1f50c253d38773187193105f70f8fda269087ff457ebce9d9eef024511cda900a9cd6822152edfc5784a9aeb659c39433ad8c3fbf4ca721c0645a22ee065a9ac58359b631a88cd68ee86bdc210dc05521a5d282697924458c4ca8f2d86524a1e2c31a32029288a656c0cd8e478a4b649c3fca761407410b7061a427ba703ca0dce03694a839462cbb99795fce48005dcf4e2a36ba222e3506612aa3d1c6a0bca678037002c055a49e0f75ee05a079c8bd91274d08d443cda0b0239ebd6a0b0e8191484ed63653fa950aa7550bae0cac833e9e7fd1238330bb686b848a978984269fc05ce1b677627bf785ee921b0292c8653be4a71016fdef8720d131ee468f0cc8ce42cf7706045a05353e33d7d0e1effe32ffd52882ebe34741eb283c2969181177e013ea1ad1a77cd6d4bcd7f6a1156e6dda6c39900328f3ded61d2ec4bc0225866bafc24d4027dd510bbca07d144d87217275573e343470d63c17940f3d2a54362aaf5682e10a8a8a21d87e40c247100df682bee913a210e96cf93a2edf7235cd121937dd7a102af1b695c94a732064e74a660fa718a4dc132a67a37374436e2818b032b1b3bddc811d90607db9938f75e7f6fdd3ff2a21f36fbfb4f909bcfff379a103c6a0af431f2825f65cf235aa8923b145bd5d3cb65fd4de007be2d50e26fb7480831cefe6d22bfb65ab82656af2f76ff8f253dc0e7c9f2adce0e073adbbe4a18bf0960154912fc1b206d433fb0da559583a1de8ca56f3a5281e77526ee2e3e1e46dd72aeadcefca866cecec5e0db6fc52490a6788a6cb534f75625a7241b53aa7d4a72f1a0ba54bcd7620046fbf92c1ed0dd8a43c683dd875da09474e8aa224f70b5b5952d19ba3569b8243e5d24e37654739112fc879b1d7450922a19cf1c60b1e0cb825f451ba1f1e0659ac5551c41bb9a6a3e493dfd7ad0f9da414e821333c2e74d4a89e13cc592371bec3b4d6d479a510d0c1a3dfb4227ef638ab1a7b15eaae7e9cbd725c7d6b1ee987cda7c88df21f1035debdf0d3b14e934de0f113d9715f983d9b845bda7561d5280576930b1442a896230042be8642508b3d24b3e15c889623de0c503f5076efb9924e2c152f0254269aff4562191eefcd8247499693dafadf07974237e2ac81fe0cec042c69ecd62b40ef5447983b45d1610fd16cf41574beb5b511e70c59dc7affa56a2ed885f981a3312e90d5c49393eef92fcc29a8738378c44b5e8649acfb1488a1fa3493c5bf6e0a5548f7d53cc27f5c4713824cc2424c67bab66dabbbd2655f5dcf3d03af5b6ce336ff1265390afd4903f8b88d14ae1e149e66d331069231af72c9ac3766aef978335d692f54e5c4c5215f58847c0a4f43566c6b6d0d407c1376d3e8e7f721088a68bd5639beccf55797e6284ec7c306f508daa5f4e5f85d322a528cfca8feea8ade3ca614b9fa0fcca10f2fa965801d1fd08cffdfafc107a44ad64765dab4b6f459a64d04afe53c65ebc28474b33dbdc813540e0aafdebbb3ffa30ded004e0d80c31365aa0c7b7f2cb3387c42fc74607172d5075dcbce3e13d1e12439dbac042207bdf7874cb5e0e9922b1d83fa9bf3d47c5b9b088108a2cba6a70706dc07ae9aa2bb8efd1e1b0868d0f6193205175bc21633c449bde1218665e274de5970b758d70f9c7e1940d1ba0fc53946a690a2ee044be3af61147e0e5532b62c2eeda0ad7d1e49150f03f216127127b5b95858df7de2c92201494d09e70db523a1df80602feb326e3fa0701af9e3331c95cdcee3bf64732e80435961e0abbc9dbc8997f34203d18345c875b7570f7c01548e0617a526af84d66921a6f3eb83717c388da4d64e1c1c486b8e269a9e44a1d38aec33eaad3980dab6b2c89f49a7c138eb183c9eccdbfbf2268f1e4f803563a9cf4187ed59453c1d235c8c928d95b46f37569625cfbe727c26644eda161771a4609c5dcd7b2d9f7658d1641ed40b4f9bf85fa260dfa4e1f5538e10fb91517f85f2c9739ceea1da6b9c1c3ff89bec3a0b0a21bc876e50f6292be3fc53bca9ab2344ddc6149714225216ea5f054e02e8547981d9bbc4fd21688c8f193d73c4025c5fcce0c9f4c550c0b5758a900cab384a47e8c09469e4981f6d41a26b93ea11414075fa8832969aa9376507a67eadebcef6ebc965738fab43de774b2f1488acfa4e6e26b5ee215968dfb68702b7126c25b415a2bc82389b764bdcd234e57b4cf35738ff1bfc28bfd1a184228819cab87c713575a8b134506f7b2a53ccb761b18e6474381d6e190a5773c61219b63b57c87cd4edc8ce7631657eb27839e37eed35cc529e1a10b8fb80ef0ce67ce9e61a9eff872a65dec61fca864acc8895bfddc44f9f2f9a885736f28bb4273081595deb783ae36f966c559886d018f56b53589b77f6888193f5bf1de448b27a428c784c21807e3c28b6aee12e81fa21baecc58d2b2d33c67f18350f71ef05a9cd5b9a4f4f6812d41738c97eb08719fb384a0aae6e17c043d3f8ed784435f19e186941cb5cb86159ba6738a863fdea6ad87fe46582ee4c8c234f9a6e49a47ad34d7dd0546314696bcc9b4983f7a625a9e8fec8885c0b65e8a5dd19d20be98f014e5ad2ec431aa1f80dfa9467795fec6ae7f27cfed842cd984feced3f13f209ad25f0014e7c04f30c774aa1da39720b32a2d40f6753808a967e780d482010001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6003848306fabe6d6d271cce87ffdf1871c98ef40a9d4d50a72430860f413479bd25753d7c59f3001c01000000000000002f48616f4254432fe5bd92e5aebfe698afe590a6e698afe4bda0e79a84e79baee585892f061263761cefae1443b40200ffffffff01d95d124b000000001976a914bfd3ebb5485b49a6cf1657824623ead693b5a45888ac00000000 diff --git a/test/data/compact426884.raw b/test/data/compact426884.raw new file mode 100644 index 000000000..a132ea17c Binary files /dev/null and b/test/data/compact426884.raw differ diff --git a/test/data/compact898352.raw b/test/data/compact898352.raw new file mode 100644 index 000000000..e49c4f158 Binary files /dev/null and b/test/data/compact898352.raw differ diff --git a/test/data/compactblock.hex b/test/data/compactblock.hex deleted file mode 100644 index c55eb0a09..000000000 --- a/test/data/compactblock.hex +++ /dev/null @@ -1,2 +0,0 @@ -00000020ecfeaa661502b9c6d8702db594f534ffa72ccc8a872237394e000000000000009999521bacc63267b6f03ca248113ebf9c08d2405add98649810bfdb848ac36f06758d57ffff001d0351b75df0e5d38b806d66b209e36b02a54c72723cc54526762a59a3efee094c0a4928b68d01d3043896c1d231789edc09d883bc16aec6020c5c827e4cbc1fd8dc8013010001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff230330b50d00fe06758d57fe458305000963676d696e6572343208040000000000000000ffffffff01da87a112000000001976a91489893957178347e87e2bb3850e6f6937de7372b288ac00000000 -00000020ecfeaa661502b9c6d8702db594f534ffa72ccc8a872237394e000000000000009999521bacc63267b6f03ca248113ebf9c08d2405add98649810bfdb848ac36f06758d57ffff001d0351b75d0a01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff230330b50d00fe06758d57fe458305000963676d696e6572343208040000000000000000ffffffff01da87a112000000001976a91489893957178347e87e2bb3850e6f6937de7372b288ac0000000001000000011bec4951dc732aa5548c3e1cc0ed4ce351162265df48c480b475227e7280fe7c01000000da0047304402204d92018d70ba28edd1f224e05f2fd5d967ebfccd574abe8cbcf227e2f9d09fa50220442c3b9f6948b1381fb276c55c5cbcef62b372f77a49e511cf57153b0ae5005a01483045022100b9600f9e0587b393353ecef8bcfca818668bcd1d92ef37437a173342bf09d2d502201906f99160671b2af58f2765874f21c38e767ca389f5d1b4ed545696475fca5e0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914df5b00c09d347d6480e4c15831e9ed57961cf7718748f231cf0000000017a9148ce5408cfeaddb7ccb2545ded41ef4781094548487000000000100000001bc7238691b3c0ab87efb7f51e70478d6f94ffde19e95b6ca724f6d3125ba8ad6340000006a473044022013ae2d30cdde46ab2da29269b9ceabca57808d940d17c8f5a962f4256e9a8bdc02203cfde3ba7d1e11d5a3971f5c687452a703bde42e3afc079d7463c0429578be66012102d73f2d4bdccc67d0d30b78d10193e86f39ddded006546c8348164802b130273affffffff0238180000000000001976a9143f1eaa9220750b05cb6ac452f0a571dc707ae22f88ac58020000000000001976a91408de748c0f95fa0c34ab493bf8db821cadadb6c288ac000000000100000001bc7238691b3c0ab87efb7f51e70478d6f94ffde19e95b6ca724f6d3125ba8ad6350000006b483045022100941c2aa32ee1bea0c64a396a19f800d8213c1d7ad2cf3e3866e0ccec454abc7d02200b27910ca85d93d302df615068eba18fef9d572a09959daebbfa0ea89d1e725e012103736b48ed7ab69e59c624db907c46e68775d1205fabe6026873312c70b1029238ffffffff02e0150000000000001976a9143f1eaa9220750b05cb6ac452f0a571dc707ae22f88acb0040000000000001976a9140b61303a4d59404c12558d647e44b873d53c114a88ac000000000100000001bef2f50d5b9d473b5657914f7a1a40470b1f7da3937c71d41781eddf57c9b267000000006b483045022100dc6efebe6b5df6e20284b828f88c08e80411e4a9bc268f5c2a5fc14bc827228e02202bca8cc12146a27bbb0ff7198aebb2381f74ca63fb29ddabd686d45fbfedaa3c012102fc4de30aafbc7ea2c65722a2e843711ecb687017f957ebf4ccbd077dfcdc47ddffffffff0358020000000000001976a9143f1eaa9220750b05cb6ac452f0a571dc707ae22f88ac0000000000000000106a0e4343020560e620a00060e620a03058020000000000001976a9143f1eaa9220750b05cb6ac452f0a571dc707ae22f88ac00000000010000000348bff409521a2b6df897395ed10f45e6b65f0f7ba27d3267d8224b57aed9b005030000006b483045022100a93928985b5fcac79e41747ab6d430689e9cb57944e2e4a192e7f11b565932fc022021b7709e9212f9c367d02da30b3f5b77b5c7c61986bd9b647a259ab659288f55012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffff3799187d9aeae85a91816fea98476bcee5d937884f10bdaa313bf38b16a943a5020000006b483045022100ffe6ab6b9055f26b4a40bca06c417f1e0edd5c1d83766246f8501490e194035b022040b1793e7441855511312aca8938e03c031f2d86a70f1498d7f2f4c3666d6afb012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffffc411a8dab81309bee99ed4a9f6e12d24815f36bcde44fc170902c0830a1193a9030000006b483045022100b94d5be7b1910ea3a9c3f7a8f31a7f084d928f89a6b168ef8b417ba25f65df60022007625c7449f9654795c4aecfda5bccdb8301ba96b9d79531c83b447145c80319012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffff0550c30000000000001976a914b67c959f7c168d790bbcbd58cb0bdee15e9e51a088ac50c30000000000001976a914b67c959f7c168d790bbcbd58cb0bdee15e9e51a088aca0860100000000001976a91413d35ad337dd80a055757e5ea0a45b59fee3060c88ac007a5005000000001976a91413d35ad337dd80a055757e5ea0a45b59fee3060c88ac0000000000000000026a0000000000010000000254f06e611b3d7637cce6085e5b2b0d9d29862bad59fb8dde7141cccf4537e39401000000fde40300473044022032da08e93459054b602eaffa804811170ca4ca34726de6f82691c6df7b76d65a02201347af08425ec2183fb4c8eba251fe2b4d9fdd56c4c7a8e98802216f4c940bd801473044022045dd992b90b7425cb105890a6e6cd34733c27603346d93166043966de857831002203adebcefbcc0189f3d523ecb7787d74cb2a8049437f25776df0f62e9e44a24980147304402205ef2bbadee85b74e69ee12f824ad770c9d7cf916c5ddae231291fb8ac45226f3022046e6f8d990d99806ad783a66bc0425d24f87694d87608c51f9efc4cc9ecbd9be01483045022100b603234134f74677de09ff1850038894a0fa1a584f50bdde1288b2e9f2bb462902207a47092343f2b2ab58dd08cac670e310603efc4bf6dcf24de6f6635617325a6301483045022100df589106e2cb3c10bb7ca2c874881e9d73a58d5ee4fefe67e0f55c4ab2b5f4af0220167a1920912f576b51eab3301aee52d6d77de6271b7c0482d717559ddf5fe8a4014830450221009853a22429d8217a35e4ee0f8813ebcc809d0d1f090a6e7516c0f3b3d5efe3aa022079df777ebf17dae85520ef4a14b3468e4e70b2b6fdca254d99d1991e6bd64a9a01483045022100fdbf9e1ace4ebf4622f3a77def98223d05af09a0c8df952f9d6b04e195e48a0e02203ccd923d2cc3ab849a82b172eb352ad60f9db4ca8adf18517856e5906cf34efc01483045022100a59eee9e301f31156a1ed52f8c13ded5351e8bebf95cd9e68b8b35d0b711c3fb02201fe7c06bf85a9ad1c0b6e2618cafda0fa7d91f236b62db7e151925744d041e2f014d9b015821021effdf18b93b4fe1133b1db861ecca6063c6739da3ec37faed78a9049c04d6e521039f0ec095f35a7be9e1ea5c87d67f26162d14b8a1315b45d019b499e7c7a25a2021020237276ac589a4103975fee8a7fc95def5a05f499f76fccd07310ad37f05dfad21027033aa382ac656de1d5dd7d85225d32c14c7345756d6d07f86eae9d82d74dbed21020393cb40e7fe97772698e5ace6e726c0c01ad25359ac9863c6a7bad7fb28d5322102d2a2eab9bb0f4410493d43ee8c0ad984458f36115cc2317813711b107dbd3192210267fb52df3c41b9de1e3ba5f19e87e2e33572a0fe06de808a4dbae1f31d2741ac210245c828c6f2af5b6d422b9bdfba932ae3bfabf59ecc0e767e2a08d0885a46f40f2102da907afb9869b1e9d55e673c1a2a727cbf98614f38f6cd348f683f5e1f4796c92102e1d680dfeaa157b31bd0dcc7d0f53081f53051284afab8472c6b518da2dd6d5f210227c9f50e7bef4a64c06c0061ab956b7e68a3a8ca7d9aa2b5946e0836e53fc79d2103653f0c36a042b59316f77332bae703e4af02a6fa23766e728241128a7c0859b65cae4f414d4c0640c64d22d5896151cea50be9e97c26d9467865d982140df44b58cd8ada067004000000fde1030047304402201ffe54928d32bfac02ccf7766180b0c494916f48857871f0aaa3e3579ee6778802207a2b3517c738ece1f8a6c57e0cc10bed86b2d6cdd530470fc7ce237fb069a01d0147304402203c167b4638c1451aab7586274d600ad69da55199d4b1cb1ab882cd68a8dd46c002200c1c573e9070b4e7e1d7921e8b8de133d834c02485497a21472d9c9341c04b9401473044022005d212352189f15c16b9ec74dc50d6915ad393875aea513cf0d01c7055f98886022044ea489e1a37216cfd23e07c278d40de911e7b54bb908d82d1ab485982909d8a0147304402204a0b58f9e5402a179216a73c1f82c122aae8183221a2bd51089ef6a65dc4105702202a28fed756d09020e1dd0183c9c0916acdfc06fe65faf756a0a1394d27a6fe34014830450221009a4ec3f90d6165967c206962e5ccc5f06c508ca84aaa7691ef50786e00e526370220193019d083248bca3cc9ac279177a90bbb3774aaf9c71280e5b24fd30c9acdca0147304402200a6bea4bbec1cfdcd764c4853f496ef2be7b9f76e0c85d9ad9019ccded06a63f0220314dcf8f916d833c9b0690d25d4fe49626ab5407641ee39ed20b7111e8b4868701483045022100a2b0490a250464279990f43a8813b0d580cc2b5dbf1f66532be8c9d2d2bfb344022029b5c342a8c85a255005cdf6a20bf26653e087e81ca54c1675d861dda4cf6eb001473044022061f452485613a3ef626cd83cab84ac2f093c087f2c83c18b16078e100f0b47a00220255657ec3aff71a1c5adbb4cb285403fd88f5ce5b180e518b4d6cd35b59932b6014d9b0158210244fd32f86e5f7da8a1257fa11b582f65a777a80c0f9a38631bc9091a6b9a8e3721032b2690c7a9dfd21fa8a4cb27805bd0a22715f08a64e424e40bb1fa7cfbff392f2103bc10bcb266ffadfdaaac7f9442b05b8484cd4da791f4731e9c258f8739c79b2921037b68818ae80c7b664442698a4a0770f1cf08eee844d3343c3c683a3d2e5511642102b01100e69a30ab6566a27434b4ef42bd822711474928de4e3237b6dc19c3069d210316f8f6e5803ef8aac8990309efecb4e91ea343580dc38f39002dc4086711670521036fa22efed38ea580449eee44013cc1a4a0213de20c85addab91f99d4aa36709521031b1aa435b022c4b18b607a2142294f3c8f71612409b64b55155ce2e9b50f7c402103b2fa1afd34790604b3baa3b1e7f5ca6e070cc6d5d10d596c57f9a1e04771d3662103813fcbec71c32dd78bd239c85747bd39322b2887ab349bbd088216ee073eee5321022f855d955932b271d294be1f4561a86282d9990ebfbcede5b6c4133fd10377ac2102aa3daaffcb4afb869ba0da34a4bed7baff3cb5dce784c76f785a16b216f91b975cae4f414d4c0240420f00000000001976a914258833938c24cd90d66c8eaf298ef345007cde6088ac9fb608000000000017a914fc0526bbcaf63f3a8eca9b625726c2536e1386a887000000000100000002c73922a4fbba37f7187c6dbf51eb0a7aec0d58970352939ff1b455584ee58c1a000000006b48304502210082442f6d0c85b12a763dd14f56d9d19bb285008563845da49bab722fe5c3b5d902201459c1a6ce8fb6a22dc847cbceaa787c08dfc1c0a75d522ce9eef565b374c384012102fc4de30aafbc7ea2c65722a2e843711ecb687017f957ebf4ccbd077dfcdc47ddffffffffffe2f3d91ffdf117a3907ae9830d0196c0726ac2cff8093575fd1df57b848072000000006b483045022100a29ad563de417154151bde618824994524ff4682c00a12888e032f67b8ffb5d5022025e149e2ebe933d38886b141b1b7e2980e63226b23729cf8ce83343fd415fb1c012102fc4de30aafbc7ea2c65722a2e843711ecb687017f957ebf4ccbd077dfcdc47ddffffffff0358020000000000001976a9140a19a64be18e637918b7cab96171dc2fe113610d88ac00000000000000000b6a09434302150060e620a058020000000000001976a9143f1eaa9220750b05cb6ac452f0a571dc707ae22f88ac000000000100000003bda24b0223e9fdb26c052d8833bfdf7af99b720b400402f2411b9a2294608a43010000006a473044022069d7edc38691a7a733d4dd7f81c92bd11f0f9fecc73c9544c24fd52e82f8027c022023b132b6723190393ae6bc4b5eb2186b63481443eb85b10a856285b90403f3b601210330730a109e15d40ba5d4ca358e298e49431c7f9a6e2985e87bacc021e479fe51feffffff14543a52ff419a57d1e6da635edce6e6f86e71ae472ef74897dbc80838423844000000006a473044022036f9a11e04ff85307862c5afec546874b3fd24824727a7505524b95147d4983a0220284d91cb5b29a6638d46a085fdac42d04ada05088187fd06d9b231ce2657b2af012103ada2e955ec4cbbf3c9393f6b55c3e91d138e3f9229ac52febf70b6ca396f1b40feffffffc4502e7af349ba91fa98be17c8f2230b6b177a0cdf3170054178cf69d8b8993f000000006a473044022061699a1c5570151585b4479fc76b72054c9b8373cbcf46a874b972602830e2e40220599834a1fbb481c99afcf2a1e66a6e8ccca8671ac1f57ed0a2ac692377c5e9f0012103e01e3f526b265dcd96770703e8fea93be29d1daa268d8394a515a83f048fc083feffffff023c3313000000000017a914e3ef292a8b9fbbf7d62ee0e2b353855013e31fd687f0791b00000000001976a91440bb537c818c2e646ec5e470d6f8a59c8d96a74288ac2fb50d000100000001677274602db90c30abf663da46d90606e602884c325a14a15fbe943fe8d970a6010000006b483045022100e76199f83d8a09134f554167e496d0f728685741a28882873b8814ed88d5dfdf0220488733bed50a41cfc29e3a4421e4699cd39ec7f9f8b305786f6fb0b0ba05a1c20121030fd8a8061d77a58695bd1d5aa192c7e595447ad3367cd11fc38514df45962ca8feffffff021b938d46000000001976a9140f40d58a69e60c42eec18283a098fb032924295a88acdaf713000000000017a9141b6d83400e5064b61c6bb4bde797fe3bf3518547872fb50d00 diff --git a/test/data/coolest-tx-ever-sent.hex b/test/data/coolest-tx-ever-sent.hex deleted file mode 100644 index 0afe77c0b..000000000 --- a/test/data/coolest-tx-ever-sent.hex +++ /dev/null @@ -1,3 +0,0 @@ -0100000002bab3b61c5a7facd63a090addb0a4ea1863ccb0f8d6d8d5c1d7b747b5aa9b17bc01000000fdfe000048304502210089666e61b0486a71f2103414315aa4c418dc65815f8b8bfcfab1037c3c2a66210220428b8162874cfc97e05dee6f901dae03820d11011fa7828ecb8fbca45be2188d01493046022100c6c19d75b6d5c911813b2b64cee07c6338f54bca0395264e53c3b3d8ca8e4f8e022100bbcb8d32960e62f26e3e5bdeca605a8b49f1a42cedd20bad507a1bc23c565faf01ab522103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea21032462c60ebc21f4d38b3c4ccb33be77b57ae72762be12887252db18fd6225befb53aeffffffffb1678d9af66c4b8cde45d0d445749322746ab900e546d3900cf30f436e73428a01000000fd470100483045022100a7af036203a1e6b2e833b0d6b402958d58f9ffaaff4969539f213634f17600ee0220192594a5c60f70e5a97dc48fec06df0d3b17c44850162d3d552c7d8653d159a001483045022072020e687ce937828827e85bc916716a9099a510e7fbd96a2836617afa370108022100ce737ad7b46c249cda2b09cb065ea16078b9a3a31f6fc6b63385f645abfdafdf01493046022100c30c5f6e943a78d502216e019821545b940b940784e83051945d89c92ec245f0022100b5c76266878ee8f29f65401fb0af6ba3941641740d846cb551059c0ad25b798c01ab532103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea21032462c60ebc21f4d38b3c4ccb33be77b57ae72762be12887252db18fd6225befb53aeffffffff0150c300000000000017142c68bb496b123d39920fcfdc206daa08bbe58506b17500000000 -010000000290c5e425bfba62bd5b294af0414d8fa3ed580c5ca6f351ccc23e360b14ff7f470100000091004730440220739d9ab2c3e7089e7bd311f267a65dc0ea00f49619cb61ec016a5038016ed71202201b88257809b623d471e429787c36e0a9bcd2a058fc0c75fd9c25f905657e3b9e01ab512103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea52aeffffffffdd7f3ce640a2fb04dbe24630aa06e4299fbb1d3fe585fe4f80be4a96b5ff0a0d01000000b400483045022100a28d2ace2f1cb4b2a58d26a5f1a2cc15cdd4cf1c65cee8e4521971c7dc60021c0220476a5ad62bfa7c18f9174d9e5e29bc0062df543e2c336ae2c77507e462bbf95701ab512103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea21032462c60ebc21f4d38b3c4ccb33be77b57ae72762be12887252db18fd6225befb53aeffffffff02e0fd1c00000000001976a9148501106ab5492387998252403d70857acfa1586488ac50c3000000000000171499050637f553f03cc0f82bbfe98dc99f10526311b17500000000 -0100000001bab3b61c5a7facd63a090addb0a4ea1863ccb0f8d6d8d5c1d7b747b5aa9b17bc000000006b483045022056eaab9d21789a762c7aefdf84d90daf35f7d98bc917c83a1ae6fa24d44f2b94022100a8e1d45d4bc51ad3a192b1b9d582a4711971b0e957012a303950b83eda3d306c01210375228faaa97a02433f4f126ba8d5a295b92466608acf8d13740130d5bbf9cdb4ffffffff0240771b00000000001976a914bb05d829af3b31730e69b7eeb83c1c0d21d362eb88ac50c3000000000000171452cf84e83d1dc919ef4ada30c44cf4349ee55af9b17500000000 diff --git a/test/data/merkle300025.raw b/test/data/merkle300025.raw new file mode 100644 index 000000000..731536477 Binary files /dev/null and b/test/data/merkle300025.raw differ diff --git a/test/data/mnemonic-english.json b/test/data/mnemonic-english.json new file mode 100644 index 000000000..e650854a2 --- /dev/null +++ b/test/data/mnemonic-english.json @@ -0,0 +1,170 @@ +[ + [ + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "TREZOR", + "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", + "xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF" + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "TREZOR", + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", + "xprv9s21ZrQH143K2gA81bYFHqU68xz1cX2APaSq5tt6MFSLeXnCKV1RVUJt9FWNTbrrryem4ZckN8k4Ls1H6nwdvDTvnV7zEXs2HgPezuVccsq" + ], + [ + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "TREZOR", + "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", + "xprv9s21ZrQH143K2shfP28KM3nr5Ap1SXjz8gc2rAqqMEynmjt6o1qboCDpxckqXavCwdnYds6yBHZGKHv7ef2eTXy461PXUjBFQg6PrwY4Gzq" + ], + [ + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "TREZOR", + "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", + "xprv9s21ZrQH143K2V4oox4M8Zmhi2Fjx5XK4Lf7GKRvPSgydU3mjZuKGCTg7UPiBUD7ydVPvSLtg9hjp7MQTYsW67rZHAXeccqYqrsx8LcXnyd" + ], + [ + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "TREZOR", + "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", + "xprv9s21ZrQH143K3mEDrypcZ2usWqFgzKB6jBBx9B6GfC7fu26X6hPRzVjzkqkPvDqp6g5eypdk6cyhGnBngbjeHTe4LsuLG1cCmKJka5SMkmU" + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "TREZOR", + "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", + "xprv9s21ZrQH143K3Lv9MZLj16np5GzLe7tDKQfVusBni7toqJGcnKRtHSxUwbKUyUWiwpK55g1DUSsw76TF1T93VT4gz4wt5RM23pkaQLnvBh7" + ], + [ + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "TREZOR", + "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", + "xprv9s21ZrQH143K3VPCbxbUtpkh9pRG371UCLDz3BjceqP1jz7XZsQ5EnNkYAEkfeZp62cDNj13ZTEVG1TEro9sZ9grfRmcYWLBhCocViKEJae" + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "TREZOR", + "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", + "xprv9s21ZrQH143K36Ao5jHRVhFGDbLP6FCx8BEEmpru77ef3bmA928BxsqvVM27WnvvyfWywiFN8K6yToqMaGYfzS6Db1EHAXT5TuyCLBXUfdm" + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "TREZOR", + "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", + "xprv9s21ZrQH143K32qBagUJAMU2LsHg3ka7jqMcV98Y7gVeVyNStwYS3U7yVVoDZ4btbRNf4h6ibWpY22iRmXq35qgLs79f312g2kj5539ebPM" + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "TREZOR", + "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", + "xprv9s21ZrQH143K3Y1sd2XVu9wtqxJRvybCfAetjUrMMco6r3v9qZTBeXiBZkS8JxWbcGJZyio8TrZtm6pkbzG8SYt1sxwNLh3Wx7to5pgiVFU" + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "TREZOR", + "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", + "xprv9s21ZrQH143K3CSnQNYC3MqAAqHwxeTLhDbhF43A4ss4ciWNmCY9zQGvAKUSqVUf2vPHBTSE1rB2pg4avopqSiLVzXEU8KziNnVPauTqLRo" + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "TREZOR", + "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", + "xprv9s21ZrQH143K2WFF16X85T2QCpndrGwx6GueB72Zf3AHwHJaknRXNF37ZmDrtHrrLSHvbuRejXcnYxoZKvRquTPyp2JiNG3XcjQyzSEgqCB" + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic", + "TREZOR", + "274ddc525802f7c828d8ef7ddbcdc5304e87ac3535913611fbbfa986d0c9e5476c91689f9c8a54fd55bd38606aa6a8595ad213d4c9c9f9aca3fb217069a41028", + "xprv9s21ZrQH143K2oZ9stBYpoaZ2ktHj7jLz7iMqpgg1En8kKFTXJHsjxry1JbKH19YrDTicVwKPehFKTbmaxgVEc5TpHdS1aYhB2s9aFJBeJH" + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog", + "TREZOR", + "628c3827a8823298ee685db84f55caa34b5cc195a778e52d45f59bcf75aba68e4d7590e101dc414bc1bbd5737666fbbef35d1f1903953b66624f910feef245ac", + "xprv9s21ZrQH143K3uT8eQowUjsxrmsA9YUuQQK1RLqFufzybxD6DH6gPY7NjJ5G3EPHjsWDrs9iivSbmvjc9DQJbJGatfa9pv4MZ3wjr8qWPAK" + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length", + "TREZOR", + "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440", + "xprv9s21ZrQH143K2XTAhys3pMNcGn261Fi5Ta2Pw8PwaVPhg3D8DWkzWQwjTJfskj8ofb81i9NP2cUNKxwjueJHHMQAnxtivTA75uUFqPFeWzk" + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "scheme spot photo card baby mountain device kick cradle pact join borrow", + "TREZOR", + "ea725895aaae8d4c1cf682c1bfd2d358d52ed9f0f0591131b559e2724bb234fca05aa9c02c57407e04ee9dc3b454aa63fbff483a8b11de949624b9f1831a9612", + "xprv9s21ZrQH143K3FperxDp8vFsFycKCRcJGAFmcV7umQmcnMZaLtZRt13QJDsoS5F6oYT6BB4sS6zmTmyQAEkJKxJ7yByDNtRe5asP2jFGhT6" + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave", + "TREZOR", + "fd579828af3da1d32544ce4db5c73d53fc8acc4ddb1e3b251a31179cdb71e853c56d2fcb11aed39898ce6c34b10b5382772db8796e52837b54468aeb312cfc3d", + "xprv9s21ZrQH143K3R1SfVZZLtVbXEB9ryVxmVtVMsMwmEyEvgXN6Q84LKkLRmf4ST6QrLeBm3jQsb9gx1uo23TS7vo3vAkZGZz71uuLCcywUkt" + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside", + "TREZOR", + "72be8e052fc4919d2adf28d5306b5474b0069df35b02303de8c1729c9538dbb6fc2d731d5f832193cd9fb6aeecbc469594a70e3dd50811b5067f3b88b28c3e8d", + "xprv9s21ZrQH143K2WNnKmssvZYM96VAr47iHUQUTUyUXH3sAGNjhJANddnhw3i3y3pBbRAVk5M5qUGFr4rHbEWwXgX4qrvrceifCYQJbbFDems" + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "cat swing flag economy stadium alone churn speed unique patch report train", + "TREZOR", + "deb5f45449e615feff5640f2e49f933ff51895de3b4381832b3139941c57b59205a42480c52175b6efcffaa58a2503887c1e8b363a707256bdd2b587b46541f5", + "xprv9s21ZrQH143K4G28omGMogEoYgDQuigBo8AFHAGDaJdqQ99QKMQ5J6fYTMfANTJy6xBmhvsNZ1CJzRZ64PWbnTFUn6CDV2FxoMDLXdk95DQ" + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access", + "TREZOR", + "4cbdff1ca2db800fd61cae72a57475fdc6bab03e441fd63f96dabd1f183ef5b782925f00105f318309a7e9c3ea6967c7801e46c8a58082674c860a37b93eda02", + "xprv9s21ZrQH143K3wtsvY8L2aZyxkiWULZH4vyQE5XkHTXkmx8gHo6RUEfH3Jyr6NwkJhvano7Xb2o6UqFKWHVo5scE31SGDCAUsgVhiUuUDyh" + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform", + "TREZOR", + "26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d", + "xprv9s21ZrQH143K3rEfqSM4QZRVmiMuSWY9wugscmaCjYja3SbUD3KPEB1a7QXJoajyR2T1SiXU7rFVRXMV9XdYVSZe7JoUXdP4SRHTxsT1nzm" + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "vessel ladder alter error federal sibling chat ability sun glass valve picture", + "TREZOR", + "2aaa9242daafcee6aa9d7269f17d4efe271e1b9a529178d7dc139cd18747090bf9d60295d0ce74309a78852a9caadf0af48aae1c6253839624076224374bc63f", + "xprv9s21ZrQH143K2QWV9Wn8Vvs6jbqfF1YbTCdURQW9dLFKDovpKaKrqS3SEWsXCu6ZNky9PSAENg6c9AQYHcg4PjopRGGKmdD313ZHszymnps" + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump", + "TREZOR", + "7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88", + "xprv9s21ZrQH143K4aERa2bq7559eMCCEs2QmmqVjUuzfy5eAeDX4mqZffkYwpzGQRE2YEEeLVRoH4CSHxianrFaVnMN2RYaPUZJhJx8S5j6puX" + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold", + "TREZOR", + "01f5bced59dec48e362f2c45b5de68b9fd6c92c6634f44d6d40aab69056506f0e35524a518034ddc1192e1dacd32c1ed3eaa3c3b131c88ed8e7e54c49a5d0998", + "xprv9s21ZrQH143K39rnQJknpH1WEPFJrzmAqqasiDcVrNuk926oizzJDDQkdiTvNPr2FYDYzWgiMiC63YmfPAa2oPyNB23r2g7d1yiK6WpqaQS" + ] +] diff --git a/test/data/mnemonic-japanese.json b/test/data/mnemonic-japanese.json new file mode 100644 index 000000000..a5764fdf5 --- /dev/null +++ b/test/data/mnemonic-japanese.json @@ -0,0 +1,170 @@ +[ + [ + "00000000000000000000000000000000", + "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", + "メートルガバヴァぱばぐゞちぢ十人十色", + "a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55", + "xprv9s21ZrQH143K258jAiWPAM6JYT9hLA91MV3AZUKfxmLZJCjCHeSjBvMbDy8C1mJ2FL5ytExyS97FAe6pQ6SD5Jt9SwHaLorA8i5Eojokfo1" + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ", + "メートルガバヴァぱばぐゞちぢ十人十色", + "aee025cbe6ca256862f889e48110a6a382365142f7d16f2b9545285b3af64e542143a577e9c144e101a6bdca18f8d97ec3366ebf5b088b1c1af9bc31346e60d9", + "xprv9s21ZrQH143K3ra1D6uGQyST9UqtUscH99GK8MBh5RrgPkrQo83QG4o6H2YktwSKvoZRVXDQZQrSyCDpHdA2j8i3PW5M9LkauaaTKwym1Wf" + ], + [ + "80808080808080808080808080808080", + "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あかちゃん", + "メートルガバヴァぱばぐゞちぢ十人十色", + "e51736736ebdf77eda23fa17e31475fa1d9509c78f1deb6b4aacfbd760a7e2ad769c714352c95143b5c1241985bcb407df36d64e75dd5a2b78ca5d2ba82a3544", + "xprv9s21ZrQH143K2aDKfG8hpfvRXzANmyBQWoqoUXWaSwVZcKtnmX5xTVkkHAdD9yykuuBcagjCFK6iLcBdHHxXC1g3TT9xHSu4PW6SRf3KvVy" + ], + [ + "ffffffffffffffffffffffffffffffff", + "われる われる われる われる われる われる われる われる われる われる われる ろんぶん", + "メートルガバヴァぱばぐゞちぢ十人十色", + "4cd2ef49b479af5e1efbbd1e0bdc117f6a29b1010211df4f78e2ed40082865793e57949236c43b9fe591ec70e5bb4298b8b71dc4b267bb96ed4ed282c8f7761c", + "xprv9s21ZrQH143K4WxYzpW3izjoq6e51NSZgN6AHxoKxZStsxBvtxuQDxPyvb8o4pSbxYPCyJGKewMxrHWvTBY6WEFX4svSzB2ezmatzzJW9wi" + ], + [ + "000000000000000000000000000000000000000000000000", + "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あらいぐま", + "メートルガバヴァぱばぐゞちぢ十人十色", + "d99e8f1ce2d4288d30b9c815ae981edd923c01aa4ffdc5dee1ab5fe0d4a3e13966023324d119105aff266dac32e5cd11431eeca23bbd7202ff423f30d6776d69", + "xprv9s21ZrQH143K2pqcK1QdBVm9r4gL4yQX6KFTqHWctvfZa9Wjhxow63ZGpSB27mVo1BBH4D1NoTo3gVAHAeqmhm5Z9SuC8xJmFYBFz978rza" + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れいぎ", + "メートルガバヴァぱばぐゞちぢ十人十色", + "eaaf171efa5de4838c758a93d6c86d2677d4ccda4a064a7136344e975f91fe61340ec8a615464b461d67baaf12b62ab5e742f944c7bd4ab6c341fbafba435716", + "xprv9s21ZrQH143K34NWKwHe5cBVDYuoKZ6iiqWczDMwGA9Ut57iCCTksDTnxE5AH3qHHvfcgwpRhyj4G7Y6FEewjVoQqq4gHN6CetyFdd3q4CR" + ], + [ + "808080808080808080808080808080808080808080808080", + "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら いきなり", + "メートルガバヴァぱばぐゞちぢ十人十色", + "aec0f8d3167a10683374c222e6e632f2940c0826587ea0a73ac5d0493b6a632590179a6538287641a9fc9df8e6f24e01bf1be548e1f74fd7407ccd72ecebe425", + "xprv9s21ZrQH143K4RABcYmYKbZybgJrvpcnricsuNaZvsGVo7pupfELFY6TJw5G5XVswQodBzaRtfPkTi6aVCmC349A3yYzAZLfT7emP8m1RFX" + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる りんご", + "メートルガバヴァぱばぐゞちぢ十人十色", + "f0f738128a65b8d1854d68de50ed97ac1831fc3a978c569e415bbcb431a6a671d4377e3b56abd518daa861676c4da75a19ccb41e00c37d086941e471a4374b95", + "xprv9s21ZrQH143K2ThaKxBDxUByy4gNwULJyqKQzZXyF3aLyGdknnP18KvKVZwCvBJGXaAsKd7oh2ypLbjyDn4bDY1iiSPvNkKsVAGQGj7G3PZ" + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん いってい", + "メートルガバヴァぱばぐゞちぢ十人十色", + "23f500eec4a563bf90cfda87b3e590b211b959985c555d17e88f46f7183590cd5793458b094a4dccc8f05807ec7bd2d19ce269e20568936a751f6f1ec7c14ddd", + "xprv9s21ZrQH143K3skSyXVw9CTTUHgKnsysvKiJw9MQjvTSY6ysTk4sFz58htMAcqHrjLdnUhqxRtmRy5AMJyWGeuQrDGSSfmcNh7cbfnrbDty" + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん まんきつ", + "メートルガバヴァぱばぐゞちぢ十人十色", + "cd354a40aa2e241e8f306b3b752781b70dfd1c69190e510bc1297a9c5738e833bcdc179e81707d57263fb7564466f73d30bf979725ff783fb3eb4baa86560b05", + "xprv9s21ZrQH143K2y9p1D6KuxqypMjbiBKkiALERahpxvb46x9giqkvmv5KxGvGJZG2mdcMunmHaazYyEqYmkx9SnfndimSmgJv5EL24X1DGqV" + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる うめる", + "メートルガバヴァぱばぐゞちぢ十人十色", + "6b7cd1b2cdfeeef8615077cadd6a0625f417f287652991c80206dbd82db17bf317d5c50a80bd9edd836b39daa1b6973359944c46d3fcc0129198dc7dc5cd0e68", + "xprv9s21ZrQH143K2TuQM4HcbBBtvC19SaDgqn6cL16KTaPEazB26iCDfxABvBi9driWcbnF4rcLVpkx5iGG7zH2QcN7qNxL4cpb7mQ2G3ByAv7" + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる らいう", + "メートルガバヴァぱばぐゞちぢ十人十色", + "a44ba7054ac2f9226929d56505a51e13acdaa8a9097923ca07ea465c4c7e294c038f3f4e7e4b373726ba0057191aced6e48ac8d183f3a11569c426f0de414623", + "xprv9s21ZrQH143K3XTGpC53cWswvhg6GVQ1dE1yty6F9VhBcE7rnXmStuKwtaZNXRxw5N7tsh1REyAxun1S5BCYvhD5pNwxWUMMZaHwjTmXFdb" + ], + [ + "77c2b00716cec7213839159e404db50d", + "せまい うちがわ あずき かろう めずらしい だんち ますく おさめる ていぼう あたる すあな えしゃく", + "メートルガバヴァぱばぐゞちぢ十人十色", + "344cef9efc37d0cb36d89def03d09144dd51167923487eec42c487f7428908546fa31a3c26b7391a2b3afe7db81b9f8c5007336b58e269ea0bd10749a87e0193", + "xprv9s21ZrQH143K2fhvZfecKw8znj6QkGGV2F2t17BWA6VnanejVWBjQeV5DspseWdSvN49rrFpocPGt7aSGk9R5wJfC1LAwFMt6hV9qS7yGKR" + ], + [ + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "ぬすむ ふっかつ うどん こうりつ しつじ りょうり おたがい せもたれ あつめる いちりゅう はんしゃ ごますり そんけい たいちょう らしんばん ぶんせき やすみ ほいく", + "メートルガバヴァぱばぐゞちぢ十人十色", + "b14e7d35904cb8569af0d6a016cee7066335a21c1c67891b01b83033cadb3e8a034a726e3909139ecd8b2eb9e9b05245684558f329b38480e262c1d6bc20ecc4", + "xprv9s21ZrQH143K25BDHG8fiLEPvKD9QCWqqs8V4yz2NeZXHbDgnAYW1EL5k8KWcn1kGKmsHrqbNvePJaYWEgkEMjJEepwTFfVzzyYRN7cyJgM" + ], + [ + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "くのう てぬぐい そんかい すろっと ちきゅう ほあん とさか はくしゅ ひびく みえる そざい てんすう たんぴん くしょう すいようび みけん きさらぎ げざん ふくざつ あつかう はやい くろう おやゆび こすう", + "メートルガバヴァぱばぐゞちぢ十人十色", + "32e78dce2aff5db25aa7a4a32b493b5d10b4089923f3320c8b287a77e512455443298351beb3f7eb2390c4662a2e566eec5217e1a37467af43b46668d515e41b", + "xprv9s21ZrQH143K2gbMb94GNwdogai6fA3vTrALH8eoNJKqPWn9KyeBMhUQLpsN5ePJkZdHsPmyDsECNLRaYiposqDDqsbk3ANk9hbsSgmVq7G" + ], + [ + "0460ef47585604c5660618db2e6a7e7f", + "あみもの いきおい ふいうち にげる ざんしょ じかん ついか はたん ほあん すんぽう てちがい わかめ", + "メートルガバヴァぱばぐゞちぢ十人十色", + "0acf902cd391e30f3f5cb0605d72a4c849342f62bd6a360298c7013d714d7e58ddf9c7fdf141d0949f17a2c9c37ced1d8cb2edabab97c4199b142c829850154b", + "xprv9s21ZrQH143K2Ec1okKMST9mN52SKEybSCeacWpAvPHMS5zFfMDfgwpJVXa96sd2sybGuJWE34CtSVYn42FBWLmFgmGeEmRvDriPnZVjWnU" + ], + [ + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "すろっと にくしみ なやむ たとえる へいこう すくう きない けってい とくべつ ねっしん いたみ せんせい おくりがな まかい とくい けあな いきおい そそぐ", + "メートルガバヴァぱばぐゞちぢ十人十色", + "9869e220bec09b6f0c0011f46e1f9032b269f096344028f5006a6e69ea5b0b8afabbb6944a23e11ebd021f182dd056d96e4e3657df241ca40babda532d364f73", + "xprv9s21ZrQH143K2KKucNRqjGFooHw87xXFQpZGNZ1W7Vwtkr2YMkXFuxnMvqc8cegm8jkrVswEWuNEsGtFkaEedAG2cRTTtsz1bM6o8fCu3Pg" + ], + [ + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "かほご きうい ゆたか みすえる もらう がっこう よそう ずっと ときどき したうけ にんか はっこう つみき すうじつ よけい くげん もくてき まわり せめる げざい にげる にんたい たんそく ほそく", + "メートルガバヴァぱばぐゞちぢ十人十色", + "713b7e70c9fbc18c831bfd1f03302422822c3727a93a5efb9659bec6ad8d6f2c1b5c8ed8b0b77775feaf606e9d1cc0a84ac416a85514ad59f5541ff5e0382481", + "xprv9s21ZrQH143K2MXrVTP5hyWW9js9D8qipo9vVRTKYPCB8Mtw4XE57uepG7wuHRk3ZJLGAq1tdJ4So8hYHu4gBaJ4NANPjb1CJCpDd3e9H87" + ], + [ + "eaebabb2383351fd31d703840b32e9e2", + "めいえん さのう めだつ すてる きぬごし ろんぱ はんこ まける たいおう さかいし ねんいり はぶらし", + "メートルガバヴァぱばぐゞちぢ十人十色", + "06e1d5289a97bcc95cb4a6360719131a786aba057d8efd603a547bd254261c2a97fcd3e8a4e766d5416437e956b388336d36c7ad2dba4ee6796f0249b10ee961", + "xprv9s21ZrQH143K3ZVFWWSR9XVXY8EMqCNdj7YUx4DKdcCFitEsSH18aPcufobUfP3w9xz1XTUThwC4cYuf8VWvSwYWs8aTTAi7mr9jDsGHYLU" + ], + [ + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "せんぱい おしえる ぐんかん もらう きあい きぼう やおや いせえび のいず じゅしん よゆう きみつ さといも ちんもく ちわわ しんせいじ とめる はちみつ", + "メートルガバヴァぱばぐゞちぢ十人十色", + "1fef28785d08cbf41d7a20a3a6891043395779ed74503a5652760ee8c24dfe60972105ee71d5168071a35ab7b5bd2f8831f75488078a90f0926c8e9171b2bc4a", + "xprv9s21ZrQH143K3CXbNxjnq5iemN7AzZrtE71rvBAuZ4BnebovyS2hK3yjbAzsX6mrdxK8fa4kXPjnCC9FHpwgaPwZuCbrUJ4sj6xdPPYNeKK" + ], + [ + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "こころ いどう きあつ そうがんきょう へいあん せつりつ ごうせい はいち いびき きこく あんい おちつく きこえる けんとう たいこ すすめる はっけん ていど はんおん いんさつ うなぎ しねま れいぼう みつかる", + "メートルガバヴァぱばぐゞちぢ十人十色", + "43de99b502e152d4c198542624511db3007c8f8f126a30818e856b2d8a20400d29e7a7e3fdd21f909e23be5e3c8d9aee3a739b0b65041ff0b8637276703f65c2", + "xprv9s21ZrQH143K2WyZ5cAUSqkC89FeL4mrEG9N9VEhh9pR2g6SQjWbXNufkfBwwaZtMfpDzip9fZjm3huvMEJASWviaGqG1A6bDmoSQzd3YFy" + ], + [ + "18ab19a9f54a9274f03e5209a2ac8a91", + "うりきれ さいせい じゆう むろん とどける ぐうたら はいれつ ひけつ いずれ うちあわせ おさめる おたく", + "メートルガバヴァぱばぐゞちぢ十人十色", + "3d711f075ee44d8b535bb4561ad76d7d5350ea0b1f5d2eac054e869ff7963cdce9581097a477d697a2a9433a0c6884bea10a2193647677977c9820dd0921cbde", + "xprv9s21ZrQH143K49xMPBpnqsaXt6EECMPzVAvr18EiiJMHfgEedw28JiSCpB5DLGQB19NU2iiG4g7vVnLC6jn75B4n3LHCPwhpU6o7Srd6jYt" + ], + [ + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "うりきれ うねる せっさたくま きもち めんきょ へいたく たまご ぜっく びじゅつかん さんそ むせる せいじ ねくたい しはらい せおう ねんど たんまつ がいけん", + "メートルガバヴァぱばぐゞちぢ十人十色", + "753ec9e333e616e9471482b4b70a18d413241f1e335c65cd7996f32b66cf95546612c51dcf12ead6f805f9ee3d965846b894ae99b24204954be80810d292fcdd", + "xprv9s21ZrQH143K2WyY1Me9W7T8Wg7yQa9WFVAEn1vhoDkkP43dBVhsagabzEKMaz7UNtczbKkNowDLXSyVipJXVEBcpYJGBJ6ZaVDXNGoLStz" + ], + [ + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "うちゅう ふそく ひしょ がちょう うけもつ めいそう みかん そざい いばる うけとる さんま さこつ おうさま ぱんつ しひょう めした たはつ いちぶ つうじょう てさぎょう きつね みすえる いりぐち かめれおん", + "メートルガバヴァぱばぐゞちぢ十人十色", + "346b7321d8c04f6f37b49fdf062a2fddc8e1bf8f1d33171b65074531ec546d1d3469974beccb1a09263440fc92e1042580a557fdce314e27ee4eabb25fa5e5fe", + "xprv9s21ZrQH143K2qVq43Phs1xyVc6jSxXHWJ6CDJjod3cgyEin7hgeQV6Dkw6s1LSfMYxoah4bPAnW4wmXfDUS9ghBEM18xoY634CBtX8HPrA" + ] +] diff --git a/test/data/mnemonic1.json b/test/data/mnemonic1.json deleted file mode 100644 index 5c02e37c1..000000000 --- a/test/data/mnemonic1.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "english": [ - [ - "00000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", - "xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF" - ], - [ - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank yellow", - "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", - "xprv9s21ZrQH143K2gA81bYFHqU68xz1cX2APaSq5tt6MFSLeXnCKV1RVUJt9FWNTbrrryem4ZckN8k4Ls1H6nwdvDTvnV7zEXs2HgPezuVccsq" - ], - [ - "80808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", - "xprv9s21ZrQH143K2shfP28KM3nr5Ap1SXjz8gc2rAqqMEynmjt6o1qboCDpxckqXavCwdnYds6yBHZGKHv7ef2eTXy461PXUjBFQg6PrwY4Gzq" - ], - [ - "ffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", - "xprv9s21ZrQH143K2V4oox4M8Zmhi2Fjx5XK4Lf7GKRvPSgydU3mjZuKGCTg7UPiBUD7ydVPvSLtg9hjp7MQTYsW67rZHAXeccqYqrsx8LcXnyd" - ], - [ - "000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", - "xprv9s21ZrQH143K3mEDrypcZ2usWqFgzKB6jBBx9B6GfC7fu26X6hPRzVjzkqkPvDqp6g5eypdk6cyhGnBngbjeHTe4LsuLG1cCmKJka5SMkmU" - ], - [ - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", - "xprv9s21ZrQH143K3Lv9MZLj16np5GzLe7tDKQfVusBni7toqJGcnKRtHSxUwbKUyUWiwpK55g1DUSsw76TF1T93VT4gz4wt5RM23pkaQLnvBh7" - ], - [ - "808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", - "xprv9s21ZrQH143K3VPCbxbUtpkh9pRG371UCLDz3BjceqP1jz7XZsQ5EnNkYAEkfeZp62cDNj13ZTEVG1TEro9sZ9grfRmcYWLBhCocViKEJae" - ], - [ - "ffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", - "xprv9s21ZrQH143K36Ao5jHRVhFGDbLP6FCx8BEEmpru77ef3bmA928BxsqvVM27WnvvyfWywiFN8K6yToqMaGYfzS6Db1EHAXT5TuyCLBXUfdm" - ], - [ - "0000000000000000000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", - "xprv9s21ZrQH143K32qBagUJAMU2LsHg3ka7jqMcV98Y7gVeVyNStwYS3U7yVVoDZ4btbRNf4h6ibWpY22iRmXq35qgLs79f312g2kj5539ebPM" - ], - [ - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", - "xprv9s21ZrQH143K3Y1sd2XVu9wtqxJRvybCfAetjUrMMco6r3v9qZTBeXiBZkS8JxWbcGJZyio8TrZtm6pkbzG8SYt1sxwNLh3Wx7to5pgiVFU" - ], - [ - "8080808080808080808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", - "xprv9s21ZrQH143K3CSnQNYC3MqAAqHwxeTLhDbhF43A4ss4ciWNmCY9zQGvAKUSqVUf2vPHBTSE1rB2pg4avopqSiLVzXEU8KziNnVPauTqLRo" - ], - [ - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", - "xprv9s21ZrQH143K2WFF16X85T2QCpndrGwx6GueB72Zf3AHwHJaknRXNF37ZmDrtHrrLSHvbuRejXcnYxoZKvRquTPyp2JiNG3XcjQyzSEgqCB" - ], - [ - "9e885d952ad362caeb4efe34a8e91bd2", - "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic", - "274ddc525802f7c828d8ef7ddbcdc5304e87ac3535913611fbbfa986d0c9e5476c91689f9c8a54fd55bd38606aa6a8595ad213d4c9c9f9aca3fb217069a41028", - "xprv9s21ZrQH143K2oZ9stBYpoaZ2ktHj7jLz7iMqpgg1En8kKFTXJHsjxry1JbKH19YrDTicVwKPehFKTbmaxgVEc5TpHdS1aYhB2s9aFJBeJH" - ], - [ - "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", - "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog", - "628c3827a8823298ee685db84f55caa34b5cc195a778e52d45f59bcf75aba68e4d7590e101dc414bc1bbd5737666fbbef35d1f1903953b66624f910feef245ac", - "xprv9s21ZrQH143K3uT8eQowUjsxrmsA9YUuQQK1RLqFufzybxD6DH6gPY7NjJ5G3EPHjsWDrs9iivSbmvjc9DQJbJGatfa9pv4MZ3wjr8qWPAK" - ], - [ - "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", - "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length", - "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440", - "xprv9s21ZrQH143K2XTAhys3pMNcGn261Fi5Ta2Pw8PwaVPhg3D8DWkzWQwjTJfskj8ofb81i9NP2cUNKxwjueJHHMQAnxtivTA75uUFqPFeWzk" - ], - [ - "c0ba5a8e914111210f2bd131f3d5e08d", - "scheme spot photo card baby mountain device kick cradle pact join borrow", - "ea725895aaae8d4c1cf682c1bfd2d358d52ed9f0f0591131b559e2724bb234fca05aa9c02c57407e04ee9dc3b454aa63fbff483a8b11de949624b9f1831a9612", - "xprv9s21ZrQH143K3FperxDp8vFsFycKCRcJGAFmcV7umQmcnMZaLtZRt13QJDsoS5F6oYT6BB4sS6zmTmyQAEkJKxJ7yByDNtRe5asP2jFGhT6" - ], - [ - "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", - "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave", - "fd579828af3da1d32544ce4db5c73d53fc8acc4ddb1e3b251a31179cdb71e853c56d2fcb11aed39898ce6c34b10b5382772db8796e52837b54468aeb312cfc3d", - "xprv9s21ZrQH143K3R1SfVZZLtVbXEB9ryVxmVtVMsMwmEyEvgXN6Q84LKkLRmf4ST6QrLeBm3jQsb9gx1uo23TS7vo3vAkZGZz71uuLCcywUkt" - ], - [ - "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", - "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside", - "72be8e052fc4919d2adf28d5306b5474b0069df35b02303de8c1729c9538dbb6fc2d731d5f832193cd9fb6aeecbc469594a70e3dd50811b5067f3b88b28c3e8d", - "xprv9s21ZrQH143K2WNnKmssvZYM96VAr47iHUQUTUyUXH3sAGNjhJANddnhw3i3y3pBbRAVk5M5qUGFr4rHbEWwXgX4qrvrceifCYQJbbFDems" - ], - [ - "23db8160a31d3e0dca3688ed941adbf3", - "cat swing flag economy stadium alone churn speed unique patch report train", - "deb5f45449e615feff5640f2e49f933ff51895de3b4381832b3139941c57b59205a42480c52175b6efcffaa58a2503887c1e8b363a707256bdd2b587b46541f5", - "xprv9s21ZrQH143K4G28omGMogEoYgDQuigBo8AFHAGDaJdqQ99QKMQ5J6fYTMfANTJy6xBmhvsNZ1CJzRZ64PWbnTFUn6CDV2FxoMDLXdk95DQ" - ], - [ - "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", - "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access", - "4cbdff1ca2db800fd61cae72a57475fdc6bab03e441fd63f96dabd1f183ef5b782925f00105f318309a7e9c3ea6967c7801e46c8a58082674c860a37b93eda02", - "xprv9s21ZrQH143K3wtsvY8L2aZyxkiWULZH4vyQE5XkHTXkmx8gHo6RUEfH3Jyr6NwkJhvano7Xb2o6UqFKWHVo5scE31SGDCAUsgVhiUuUDyh" - ], - [ - "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", - "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform", - "26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d", - "xprv9s21ZrQH143K3rEfqSM4QZRVmiMuSWY9wugscmaCjYja3SbUD3KPEB1a7QXJoajyR2T1SiXU7rFVRXMV9XdYVSZe7JoUXdP4SRHTxsT1nzm" - ], - [ - "f30f8c1da665478f49b001d94c5fc452", - "vessel ladder alter error federal sibling chat ability sun glass valve picture", - "2aaa9242daafcee6aa9d7269f17d4efe271e1b9a529178d7dc139cd18747090bf9d60295d0ce74309a78852a9caadf0af48aae1c6253839624076224374bc63f", - "xprv9s21ZrQH143K2QWV9Wn8Vvs6jbqfF1YbTCdURQW9dLFKDovpKaKrqS3SEWsXCu6ZNky9PSAENg6c9AQYHcg4PjopRGGKmdD313ZHszymnps" - ], - [ - "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", - "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump", - "7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88", - "xprv9s21ZrQH143K4aERa2bq7559eMCCEs2QmmqVjUuzfy5eAeDX4mqZffkYwpzGQRE2YEEeLVRoH4CSHxianrFaVnMN2RYaPUZJhJx8S5j6puX" - ], - [ - "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", - "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold", - "01f5bced59dec48e362f2c45b5de68b9fd6c92c6634f44d6d40aab69056506f0e35524a518034ddc1192e1dacd32c1ed3eaa3c3b131c88ed8e7e54c49a5d0998", - "xprv9s21ZrQH143K39rnQJknpH1WEPFJrzmAqqasiDcVrNuk926oizzJDDQkdiTvNPr2FYDYzWgiMiC63YmfPAa2oPyNB23r2g7d1yiK6WpqaQS" - ] - ] -} diff --git a/test/data/mnemonic2.json b/test/data/mnemonic2.json deleted file mode 100644 index bd0ec471d..000000000 --- a/test/data/mnemonic2.json +++ /dev/null @@ -1,193 +0,0 @@ -[ - { - "entropy": "00000000000000000000000000000000", - "mnemonic": "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55", - "bip32_xprv": "xprv9s21ZrQH143K258jAiWPAM6JYT9hLA91MV3AZUKfxmLZJCjCHeSjBvMbDy8C1mJ2FL5ytExyS97FAe6pQ6SD5Jt9SwHaLorA8i5Eojokfo1" - }, - - { - "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "mnemonic": "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "aee025cbe6ca256862f889e48110a6a382365142f7d16f2b9545285b3af64e542143a577e9c144e101a6bdca18f8d97ec3366ebf5b088b1c1af9bc31346e60d9", - "bip32_xprv": "xprv9s21ZrQH143K3ra1D6uGQyST9UqtUscH99GK8MBh5RrgPkrQo83QG4o6H2YktwSKvoZRVXDQZQrSyCDpHdA2j8i3PW5M9LkauaaTKwym1Wf" - }, - - { - "entropy": "80808080808080808080808080808080", - "mnemonic": "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あかちゃん", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "e51736736ebdf77eda23fa17e31475fa1d9509c78f1deb6b4aacfbd760a7e2ad769c714352c95143b5c1241985bcb407df36d64e75dd5a2b78ca5d2ba82a3544", - "bip32_xprv": "xprv9s21ZrQH143K2aDKfG8hpfvRXzANmyBQWoqoUXWaSwVZcKtnmX5xTVkkHAdD9yykuuBcagjCFK6iLcBdHHxXC1g3TT9xHSu4PW6SRf3KvVy" - }, - - { - "entropy": "ffffffffffffffffffffffffffffffff", - "mnemonic": "われる われる われる われる われる われる われる われる われる われる われる ろんぶん", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "4cd2ef49b479af5e1efbbd1e0bdc117f6a29b1010211df4f78e2ed40082865793e57949236c43b9fe591ec70e5bb4298b8b71dc4b267bb96ed4ed282c8f7761c", - "bip32_xprv": "xprv9s21ZrQH143K4WxYzpW3izjoq6e51NSZgN6AHxoKxZStsxBvtxuQDxPyvb8o4pSbxYPCyJGKewMxrHWvTBY6WEFX4svSzB2ezmatzzJW9wi" - }, - - { - "entropy": "000000000000000000000000000000000000000000000000", - "mnemonic": "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あらいぐま", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "d99e8f1ce2d4288d30b9c815ae981edd923c01aa4ffdc5dee1ab5fe0d4a3e13966023324d119105aff266dac32e5cd11431eeca23bbd7202ff423f30d6776d69", - "bip32_xprv": "xprv9s21ZrQH143K2pqcK1QdBVm9r4gL4yQX6KFTqHWctvfZa9Wjhxow63ZGpSB27mVo1BBH4D1NoTo3gVAHAeqmhm5Z9SuC8xJmFYBFz978rza" - }, - - { - "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "mnemonic": "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れいぎ", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "eaaf171efa5de4838c758a93d6c86d2677d4ccda4a064a7136344e975f91fe61340ec8a615464b461d67baaf12b62ab5e742f944c7bd4ab6c341fbafba435716", - "bip32_xprv": "xprv9s21ZrQH143K34NWKwHe5cBVDYuoKZ6iiqWczDMwGA9Ut57iCCTksDTnxE5AH3qHHvfcgwpRhyj4G7Y6FEewjVoQqq4gHN6CetyFdd3q4CR" - }, - - { - "entropy": "808080808080808080808080808080808080808080808080", - "mnemonic": "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら いきなり", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "aec0f8d3167a10683374c222e6e632f2940c0826587ea0a73ac5d0493b6a632590179a6538287641a9fc9df8e6f24e01bf1be548e1f74fd7407ccd72ecebe425", - "bip32_xprv": "xprv9s21ZrQH143K4RABcYmYKbZybgJrvpcnricsuNaZvsGVo7pupfELFY6TJw5G5XVswQodBzaRtfPkTi6aVCmC349A3yYzAZLfT7emP8m1RFX" - }, - - { - "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffff", - "mnemonic": "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる りんご", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "f0f738128a65b8d1854d68de50ed97ac1831fc3a978c569e415bbcb431a6a671d4377e3b56abd518daa861676c4da75a19ccb41e00c37d086941e471a4374b95", - "bip32_xprv": "xprv9s21ZrQH143K2ThaKxBDxUByy4gNwULJyqKQzZXyF3aLyGdknnP18KvKVZwCvBJGXaAsKd7oh2ypLbjyDn4bDY1iiSPvNkKsVAGQGj7G3PZ" - }, - - { - "entropy": "0000000000000000000000000000000000000000000000000000000000000000", - "mnemonic": "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん いってい", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "23f500eec4a563bf90cfda87b3e590b211b959985c555d17e88f46f7183590cd5793458b094a4dccc8f05807ec7bd2d19ce269e20568936a751f6f1ec7c14ddd", - "bip32_xprv": "xprv9s21ZrQH143K3skSyXVw9CTTUHgKnsysvKiJw9MQjvTSY6ysTk4sFz58htMAcqHrjLdnUhqxRtmRy5AMJyWGeuQrDGSSfmcNh7cbfnrbDty" - }, - - { - "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "mnemonic": "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん まんきつ", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "cd354a40aa2e241e8f306b3b752781b70dfd1c69190e510bc1297a9c5738e833bcdc179e81707d57263fb7564466f73d30bf979725ff783fb3eb4baa86560b05", - "bip32_xprv": "xprv9s21ZrQH143K2y9p1D6KuxqypMjbiBKkiALERahpxvb46x9giqkvmv5KxGvGJZG2mdcMunmHaazYyEqYmkx9SnfndimSmgJv5EL24X1DGqV" - }, - - { - "entropy": "8080808080808080808080808080808080808080808080808080808080808080", - "mnemonic": "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる うめる", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "6b7cd1b2cdfeeef8615077cadd6a0625f417f287652991c80206dbd82db17bf317d5c50a80bd9edd836b39daa1b6973359944c46d3fcc0129198dc7dc5cd0e68", - "bip32_xprv": "xprv9s21ZrQH143K2TuQM4HcbBBtvC19SaDgqn6cL16KTaPEazB26iCDfxABvBi9driWcbnF4rcLVpkx5iGG7zH2QcN7qNxL4cpb7mQ2G3ByAv7" - }, - - { - "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "mnemonic": "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる らいう", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "a44ba7054ac2f9226929d56505a51e13acdaa8a9097923ca07ea465c4c7e294c038f3f4e7e4b373726ba0057191aced6e48ac8d183f3a11569c426f0de414623", - "bip32_xprv": "xprv9s21ZrQH143K3XTGpC53cWswvhg6GVQ1dE1yty6F9VhBcE7rnXmStuKwtaZNXRxw5N7tsh1REyAxun1S5BCYvhD5pNwxWUMMZaHwjTmXFdb" - }, - - { - "entropy": "77c2b00716cec7213839159e404db50d", - "mnemonic": "せまい うちがわ あずき かろう めずらしい だんち ますく おさめる ていぼう あたる すあな えしゃく", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "344cef9efc37d0cb36d89def03d09144dd51167923487eec42c487f7428908546fa31a3c26b7391a2b3afe7db81b9f8c5007336b58e269ea0bd10749a87e0193", - "bip32_xprv": "xprv9s21ZrQH143K2fhvZfecKw8znj6QkGGV2F2t17BWA6VnanejVWBjQeV5DspseWdSvN49rrFpocPGt7aSGk9R5wJfC1LAwFMt6hV9qS7yGKR" - }, - - { - "entropy": "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "mnemonic": "ぬすむ ふっかつ うどん こうりつ しつじ りょうり おたがい せもたれ あつめる いちりゅう はんしゃ ごますり そんけい たいちょう らしんばん ぶんせき やすみ ほいく", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "b14e7d35904cb8569af0d6a016cee7066335a21c1c67891b01b83033cadb3e8a034a726e3909139ecd8b2eb9e9b05245684558f329b38480e262c1d6bc20ecc4", - "bip32_xprv": "xprv9s21ZrQH143K25BDHG8fiLEPvKD9QCWqqs8V4yz2NeZXHbDgnAYW1EL5k8KWcn1kGKmsHrqbNvePJaYWEgkEMjJEepwTFfVzzyYRN7cyJgM" - }, - - { - "entropy": "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "mnemonic": "くのう てぬぐい そんかい すろっと ちきゅう ほあん とさか はくしゅ ひびく みえる そざい てんすう たんぴん くしょう すいようび みけん きさらぎ げざん ふくざつ あつかう はやい くろう おやゆび こすう", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "32e78dce2aff5db25aa7a4a32b493b5d10b4089923f3320c8b287a77e512455443298351beb3f7eb2390c4662a2e566eec5217e1a37467af43b46668d515e41b", - "bip32_xprv": "xprv9s21ZrQH143K2gbMb94GNwdogai6fA3vTrALH8eoNJKqPWn9KyeBMhUQLpsN5ePJkZdHsPmyDsECNLRaYiposqDDqsbk3ANk9hbsSgmVq7G" - }, - - { - "entropy": "0460ef47585604c5660618db2e6a7e7f", - "mnemonic": "あみもの いきおい ふいうち にげる ざんしょ じかん ついか はたん ほあん すんぽう てちがい わかめ", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "0acf902cd391e30f3f5cb0605d72a4c849342f62bd6a360298c7013d714d7e58ddf9c7fdf141d0949f17a2c9c37ced1d8cb2edabab97c4199b142c829850154b", - "bip32_xprv": "xprv9s21ZrQH143K2Ec1okKMST9mN52SKEybSCeacWpAvPHMS5zFfMDfgwpJVXa96sd2sybGuJWE34CtSVYn42FBWLmFgmGeEmRvDriPnZVjWnU" - }, - - { - "entropy": "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "mnemonic": "すろっと にくしみ なやむ たとえる へいこう すくう きない けってい とくべつ ねっしん いたみ せんせい おくりがな まかい とくい けあな いきおい そそぐ", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "9869e220bec09b6f0c0011f46e1f9032b269f096344028f5006a6e69ea5b0b8afabbb6944a23e11ebd021f182dd056d96e4e3657df241ca40babda532d364f73", - "bip32_xprv": "xprv9s21ZrQH143K2KKucNRqjGFooHw87xXFQpZGNZ1W7Vwtkr2YMkXFuxnMvqc8cegm8jkrVswEWuNEsGtFkaEedAG2cRTTtsz1bM6o8fCu3Pg" - }, - - { - "entropy": "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "mnemonic": "かほご きうい ゆたか みすえる もらう がっこう よそう ずっと ときどき したうけ にんか はっこう つみき すうじつ よけい くげん もくてき まわり せめる げざい にげる にんたい たんそく ほそく", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "713b7e70c9fbc18c831bfd1f03302422822c3727a93a5efb9659bec6ad8d6f2c1b5c8ed8b0b77775feaf606e9d1cc0a84ac416a85514ad59f5541ff5e0382481", - "bip32_xprv": "xprv9s21ZrQH143K2MXrVTP5hyWW9js9D8qipo9vVRTKYPCB8Mtw4XE57uepG7wuHRk3ZJLGAq1tdJ4So8hYHu4gBaJ4NANPjb1CJCpDd3e9H87" - }, - - { - "entropy": "eaebabb2383351fd31d703840b32e9e2", - "mnemonic": "めいえん さのう めだつ すてる きぬごし ろんぱ はんこ まける たいおう さかいし ねんいり はぶらし", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "06e1d5289a97bcc95cb4a6360719131a786aba057d8efd603a547bd254261c2a97fcd3e8a4e766d5416437e956b388336d36c7ad2dba4ee6796f0249b10ee961", - "bip32_xprv": "xprv9s21ZrQH143K3ZVFWWSR9XVXY8EMqCNdj7YUx4DKdcCFitEsSH18aPcufobUfP3w9xz1XTUThwC4cYuf8VWvSwYWs8aTTAi7mr9jDsGHYLU" - }, - - { - "entropy": "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "mnemonic": "せんぱい おしえる ぐんかん もらう きあい きぼう やおや いせえび のいず じゅしん よゆう きみつ さといも ちんもく ちわわ しんせいじ とめる はちみつ", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "1fef28785d08cbf41d7a20a3a6891043395779ed74503a5652760ee8c24dfe60972105ee71d5168071a35ab7b5bd2f8831f75488078a90f0926c8e9171b2bc4a", - "bip32_xprv": "xprv9s21ZrQH143K3CXbNxjnq5iemN7AzZrtE71rvBAuZ4BnebovyS2hK3yjbAzsX6mrdxK8fa4kXPjnCC9FHpwgaPwZuCbrUJ4sj6xdPPYNeKK" - }, - - { - "entropy": "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "mnemonic": "こころ いどう きあつ そうがんきょう へいあん せつりつ ごうせい はいち いびき きこく あんい おちつく きこえる けんとう たいこ すすめる はっけん ていど はんおん いんさつ うなぎ しねま れいぼう みつかる", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "43de99b502e152d4c198542624511db3007c8f8f126a30818e856b2d8a20400d29e7a7e3fdd21f909e23be5e3c8d9aee3a739b0b65041ff0b8637276703f65c2", - "bip32_xprv": "xprv9s21ZrQH143K2WyZ5cAUSqkC89FeL4mrEG9N9VEhh9pR2g6SQjWbXNufkfBwwaZtMfpDzip9fZjm3huvMEJASWviaGqG1A6bDmoSQzd3YFy" - }, - - { - "entropy": "18ab19a9f54a9274f03e5209a2ac8a91", - "mnemonic": "うりきれ さいせい じゆう むろん とどける ぐうたら はいれつ ひけつ いずれ うちあわせ おさめる おたく", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "3d711f075ee44d8b535bb4561ad76d7d5350ea0b1f5d2eac054e869ff7963cdce9581097a477d697a2a9433a0c6884bea10a2193647677977c9820dd0921cbde", - "bip32_xprv": "xprv9s21ZrQH143K49xMPBpnqsaXt6EECMPzVAvr18EiiJMHfgEedw28JiSCpB5DLGQB19NU2iiG4g7vVnLC6jn75B4n3LHCPwhpU6o7Srd6jYt" - }, - - { - "entropy": "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "mnemonic": "うりきれ うねる せっさたくま きもち めんきょ へいたく たまご ぜっく びじゅつかん さんそ むせる せいじ ねくたい しはらい せおう ねんど たんまつ がいけん", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "753ec9e333e616e9471482b4b70a18d413241f1e335c65cd7996f32b66cf95546612c51dcf12ead6f805f9ee3d965846b894ae99b24204954be80810d292fcdd", - "bip32_xprv": "xprv9s21ZrQH143K2WyY1Me9W7T8Wg7yQa9WFVAEn1vhoDkkP43dBVhsagabzEKMaz7UNtczbKkNowDLXSyVipJXVEBcpYJGBJ6ZaVDXNGoLStz" - }, - - { - "entropy": "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "mnemonic": "うちゅう ふそく ひしょ がちょう うけもつ めいそう みかん そざい いばる うけとる さんま さこつ おうさま ぱんつ しひょう めした たはつ いちぶ つうじょう てさぎょう きつね みすえる いりぐち かめれおん", - "passphrase": "メートルガバヴァぱばぐゞちぢ十人十色", - "seed": "346b7321d8c04f6f37b49fdf062a2fddc8e1bf8f1d33171b65074531ec546d1d3469974beccb1a09263440fc92e1042580a557fdce314e27ee4eabb25fa5e5fe", - "bip32_xprv": "xprv9s21ZrQH143K2qVq43Phs1xyVc6jSxXHWJ6CDJjod3cgyEin7hgeQV6Dkw6s1LSfMYxoah4bPAnW4wmXfDUS9ghBEM18xoY634CBtX8HPrA" - } -] diff --git a/test/data/script_tests.json b/test/data/script-tests.json similarity index 99% rename from test/data/script_tests.json rename to test/data/script-tests.json index 5c054ed3e..698e89823 100644 --- a/test/data/script_tests.json +++ b/test/data/script-tests.json @@ -240,7 +240,7 @@ ["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", "Discouraged NOPs are allowed if not executed"], -["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above NOP10 invalid if executed"], +["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above MAX_OPCODE invalid if executed"], ["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], @@ -349,7 +349,7 @@ ["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], ["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC", "OK"], ["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], -["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["549755813888", "0x06 0x000000008000 EQUAL", "P2SH,STRICTENC", "OK"], ["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], ["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "OK", "Numbers are little-endian with the MSB being a sign bit"], ["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC", "OK"], @@ -878,7 +878,7 @@ "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], ["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"], -["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above NOP10 invalid if executed"], +["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above MAX_OPCODE invalid if executed"], ["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], @@ -1001,7 +1001,7 @@ ["1","RESERVED", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED is reserved"], ["1","RESERVED1", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED1 is reserved"], ["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"], -["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == OP_NOP10 + 1"], +["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == MAX_OPCODE + 1"], ["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], ["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], @@ -2506,7 +2506,7 @@ ], ["CHECKSEQUENCEVERIFY tests"], -["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"], +["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on an empty stack"], ["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], ["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], ["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], diff --git a/test/data/sighash.json b/test/data/sighash-tests.json similarity index 100% rename from test/data/sighash.json rename to test/data/sighash-tests.json diff --git a/test/data/tx_invalid.json b/test/data/tx-invalid.json similarity index 99% rename from test/data/tx_invalid.json rename to test/data/tx-invalid.json index f7d9e1847..2235bd0ae 100644 --- a/test/data/tx_invalid.json +++ b/test/data/tx-invalid.json @@ -1,7 +1,7 @@ [ ["The following are deserialized transactions which are invalid."], ["They are in the form"], -["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], +["[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],"], ["serializedTransaction, verifyFlags]"], ["Objects that are only a single string (like this one) are ignored"], diff --git a/test/data/tx_valid.json b/test/data/tx-valid.json similarity index 99% rename from test/data/tx_valid.json rename to test/data/tx-valid.json index 2f299aa5f..e6b382af1 100644 --- a/test/data/tx_valid.json +++ b/test/data/tx-valid.json @@ -1,7 +1,7 @@ [ ["The following are deserialized transactions which are valid."], ["They are in the form"], -["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], +["[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],"], ["serializedTransaction, verifyFlags]"], ["Objects that are only a single string (like this one) are ignored"], @@ -53,7 +53,7 @@ ["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"], ["It results in signing the constant 1, instead of something generated based on the transaction,"], ["when the input doing the signing has an index greater than the maximum output index"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]], +[[["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"], ["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"]], "01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"], ["An invalid P2SH Transaction"], @@ -174,7 +174,7 @@ [[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], "01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], -["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."], +["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."], ["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"], [[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"], @@ -334,9 +334,9 @@ "0100000000010100010000000000000000000000000000000000000000000000000000000000000000000023220020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000", "P2SH,WITNESS"], ["Witness with SigHash Single|AnyoneCanPay"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100], +[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100], ["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000], -["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100], +["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100], ["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]], "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "P2SH,WITNESS"], @@ -359,9 +359,9 @@ "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"], ["Witness with SigHash None|AnyoneCanPay"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100], +[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100], +["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100], ["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000], -["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100], ["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]], "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"], @@ -390,9 +390,9 @@ "01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"], ["Witness with SigHash All|AnyoneCanPay"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100], +[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100], +["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100], ["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000], -["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100], ["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]], "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"], @@ -458,8 +458,8 @@ "0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "P2SH,WITNESS"], ["Witness Single|AnyoneCanPay does not hash input's position (permutation)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000], -["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001], +["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000]], "0100000000010200010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff02e9030000000000000151e80300000000000001510248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "P2SH,WITNESS"], ["Non witness Single|AnyoneCanPay hash input's position"], @@ -478,7 +478,7 @@ ["1b2a9a426ba603ba357ce7773cb5805cb9c7c2b386d100d1fc9263513188e680", 0, "0x00 0x20 0xd9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537", 16777215]], "01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "P2SH,WITNESS"], -["BIP143 example: Same as the previous example with input-output paris swapped"], +["BIP143 example: Same as the previous example with input-output pairs swapped"], [[["1b2a9a426ba603ba357ce7773cb5805cb9c7c2b386d100d1fc9263513188e680", 0, "0x00 0x20 0xd9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537", 16777215], ["01c0cf7fba650638e55eb91261b183251fbb466f90dff17f10086817c542b5e9", 0, "0x00 0x20 0xba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d", 16777215]], "0100000000010280e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffffe9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff0280969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac80969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "P2SH,WITNESS"], diff --git a/test/data/tx1-undo.raw b/test/data/tx1-undo.raw new file mode 100644 index 000000000..20d8a61c3 Binary files /dev/null and b/test/data/tx1-undo.raw differ diff --git a/test/data/tx1.hex b/test/data/tx1.hex deleted file mode 100644 index 8fad376cd..000000000 --- a/test/data/tx1.hex +++ /dev/null @@ -1,2 +0,0 @@ -01000000018177482b65ec42fc43c6b2ad13955d7fdec00edb5dc5ac483d9e31eb06a5a5d5010000006c493046022100955062369843b52db91eb9c1b8fb5ed20b346a62841edfb2ba2097d2a9bc31810221009ace1c91398620b4d1bfa559ca2abcaf6c1a524e606bb5fedf74c9a123ae4ec8012103046d258651af2fbb6acb63414a604314ce94d644a0efd8832ca5275f2bc207c6ffffffff05404b4c0000000000475221033423007d8f263819a2e42becaaf5b06f34cb09919e06304349d950668209eaed21021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae404b4c00000000002752010021021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae404b4c00000000004752210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452aeb0f0c304000000001976a9146cce12229300b733cdf0c7ce3079c7503b080fca88ac404b4c000000000047522102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee521021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae00000000 -01000000017133b604e8aaa0414a2f3f4c093258acbacd7063cca964cf1dcd3c9afd8be086010000006c493046022100c28bbd00b6ab9af8cf1038139003988f800744d82ed168c39fdcf5958f3348ef022100b7f626763f39d795cc23dc31bb74a6a5b90527c5e909c28b29bbcd3a438aa36101210211b60f23135a806aff2c8f0fbbe620c16ba05a9ca4772735c08a16407f185b34ffffffff02b01df505000000001976a9144e96e751b8f837983046adfc528b11d1dc8200ae88ac00e1f505000000001976a914f5223c1cf62c09a4789c6bdfebaf77b8b7b4dc8f88ac00000000 diff --git a/test/data/tx1.raw b/test/data/tx1.raw new file mode 100644 index 000000000..d253c365d Binary files /dev/null and b/test/data/tx1.raw differ diff --git a/test/data/tx10-undo.raw b/test/data/tx10-undo.raw new file mode 100644 index 000000000..26e503545 Binary files /dev/null and b/test/data/tx10-undo.raw differ diff --git a/test/data/tx10.raw b/test/data/tx10.raw new file mode 100644 index 000000000..194a39f41 Binary files /dev/null and b/test/data/tx10.raw differ diff --git a/test/data/tx2-undo.raw b/test/data/tx2-undo.raw new file mode 100644 index 000000000..fb053b408 Binary files /dev/null and b/test/data/tx2-undo.raw differ diff --git a/test/data/tx2.hex b/test/data/tx2.hex deleted file mode 100644 index 463ffea1c..000000000 --- a/test/data/tx2.hex +++ /dev/null @@ -1,2 +0,0 @@ -00000000014ae41d5402fafe7b5c8968bcb588ffe91f282edd9f0773e7abedf5fffd4f77ea000000006b483045022100e3d075434dbce66fce6c1843ebb84c56541f542e7c4c29878b7a38de739e7a9a02202f626ccf7d507291ebc7879f573cb5d229e34b8738a47cb5424d9f14e3d54b2f012103ac81c3203de55b31478da413d9bb68b99dc8e33176f9f48e5efcc0900bb41b4affffffff024e61bc00000000001976a914ab37bf4a3af9bc16025b9c64e82f85838bbc792088aca2583905000000001976a914978cdeb4fa9e180044a62fcc345da48e4e14ce6c88ac00000000 -0100000002b84833440fb981852d469b12321dc5d30bb71977100ac78a2db1560ae3b65eec010000006a473044022031e0b888652a5c8988b01af7fd1226a0015e38b505868d343e4fe0713b9dd8cc02206c6eeae02976d03147f9fb483ca12a22d16178feee7ab691dc0dd829c375a58e012102d22f286d17a07ac48ad9d22a85db5638082de4bc9fc14f94266bed6318cfffc7ffffffff612b726b05e36cdda64bae4aac34eaf0e4a5ca9a20a4a3ce1d1d2f31d7b94a90000000006b48304502205adf9a67e21c6430cbdd6b2b3037a3f23a393ad25d148dc3068afb01c4a7b8d8022100eabc84aeca4e637bc068a451a98d03f5ad6368e4a701ec4bc6e2548f7e17dc94012103ac81c3203de55b31478da413d9bb68b99dc8e33176f9f48e5efcc0900bb41b4affffffff0200e1f505000000001976a914059fd71b64ece424b1fe97e00082e163ff224ee488aca0f01900000000001976a9146580541e8b9cb88c1659e44f2597b99081ee59eb88ac00000000 diff --git a/test/data/tx2.raw b/test/data/tx2.raw new file mode 100644 index 000000000..58b7192e4 Binary files /dev/null and b/test/data/tx2.raw differ diff --git a/test/data/tx3-undo.raw b/test/data/tx3-undo.raw new file mode 100644 index 000000000..3eab36fa6 Binary files /dev/null and b/test/data/tx3-undo.raw differ diff --git a/test/data/tx3.hex b/test/data/tx3.hex deleted file mode 100644 index 4511bf0b8..000000000 --- a/test/data/tx3.hex +++ /dev/null @@ -1,3 +0,0 @@ -01000000022f196cf1e5bd426a04f07b882c893b5b5edebad67da6eb50f066c372ed736d5f000000006a47304402201f81ac31b52cb4b1ceb83f97d18476f7339b74f4eecd1a32c251d4c3cccfffa402203c9143c18810ce072969e4132fdab91408816c96b423b2be38eec8a3582ade36012102aa5a2b334bd8f135f11bc5c477bf6307ff98ed52d3ed10f857d5c89adf5b02beffffffffff8755f073f1170c0d519457ffc4acaa7cb2988148163b5dc457fae0fe42aa19000000009200483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a530347304402206da827fb26e569eb740641f9c1a7121ee59141703cbe0f903a22cc7d9a7ec7ac02204729f989b5348b3669ab020b8c4af01acc4deaba7c0d9f8fa9e06b2106cbbfeb01ffffffff010000000000000000016a00000000 -010000000143d4b858145e44fbd121dbc592ae931b459f9ec99418a83e8cb6d94330a80c24010000006b483045022100f85c9fceb6d4d38c82a9121acbf68ffffe784017b05554b586464fdbe473340d0220077780b2022c2d97752961c2cb03ed9202cbe57647510746c6bd31276c8a3c5201210314ffdda8717bc586284c05f37192990f774c391e2088516d2983094d3a33e7c3ffffffff02a0860100000000001976a91419660c27383b347112e92caba64fb1d07e9f63bf88ac40c33800000000001976a914825537afe6d73324f862027690651a64c688dfb788ac00000000 -01000000017a2133643a513a004ff4d09bbcc7a05d7ee7d3a1d28889f0c06d06f9db1d1d8000000000fd4d0200473044022011cb94542051b8be5563b39da022d7531673ed4b53b6b3f8536794150f7d75e802205a6774c0630964457c2d4a087e5a23167155f661082746dc711ba348ca4d4187014d01025121033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b5faeffffffff01a08601000000000091483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53037552210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7152ae00000000 diff --git a/test/data/tx3.raw b/test/data/tx3.raw new file mode 100644 index 000000000..d4e3254eb Binary files /dev/null and b/test/data/tx3.raw differ diff --git a/test/data/tx4-undo.raw b/test/data/tx4-undo.raw new file mode 100644 index 000000000..37c4edaea Binary files /dev/null and b/test/data/tx4-undo.raw differ diff --git a/test/data/tx4.hex b/test/data/tx4.hex deleted file mode 100644 index 7e03fd091..000000000 --- a/test/data/tx4.hex +++ /dev/null @@ -1,2 +0,0 @@ -01000000018759d7397a86d6c42dfe2c55612e523d171e51708fec9e289118deb5ba99400101000000dc00493046022100da3264579decba370d0b5d896c5f4664dfdf06119cc3ca5cef937389e61b5bf1022100a5584aa704578d35080129edb22d2bea7a24f16f0603cc22a9390cdc0a8f6e6301483045022018478cf5c7ef4cf0b0b6583937bba83b76bf87461825f44130dbb854111a62d8022100e431be966081676b2d785a3260e2a50e250d8a2f5d8364309fe1195dfa87a31d01475221030c341a91e5de82732d6bfb1c3676585b817096cd8bf076cf0ea88c339b9815072102f3f450d36aced52de6023ca5e9d7e256d5c5183f3316211d53bb151c3585222e52ae000000000104c70300000000001976a914a532649591196c7ff3ebd5783c29c9a08d54a3a288ac370c0500 -0100000001c6ada6066f14a0cd4dc39f086f1f7637b76bfc08da5dc25f8179b0ccfc5d09f7000000006a473044022067934a2152ab5fe96119d702fc48322b967aee669a14e9da8913481d4b7f133402207e444ee1987fcb25ebcb9d98add22e3948ac847a67b306dba106d8e6ba48781001210297812667d2a62d7bbcf17e2d2ade2ade548a9464e9e8e29b42a777f85c93a48effffffff02f4ad2600000000001976a91454987f4e1ea17ec34a489d82ae9d39f6928e61cd88ac14ee03000000000017a914195bde4cd150acf910b5c83a024fd2d9f33306af8700000000 diff --git a/test/data/tx4.raw b/test/data/tx4.raw new file mode 100644 index 000000000..5d80e89c1 Binary files /dev/null and b/test/data/tx4.raw differ diff --git a/test/data/tx5.raw b/test/data/tx5.raw new file mode 100644 index 000000000..322863574 Binary files /dev/null and b/test/data/tx5.raw differ diff --git a/test/data/tx6-undo.raw b/test/data/tx6-undo.raw new file mode 100644 index 000000000..b7ea2b2a4 Binary files /dev/null and b/test/data/tx6-undo.raw differ diff --git a/test/data/tx6.raw b/test/data/tx6.raw new file mode 100644 index 000000000..02c7cdbcc Binary files /dev/null and b/test/data/tx6.raw differ diff --git a/test/data/tx7-undo.raw b/test/data/tx7-undo.raw new file mode 100644 index 000000000..4c284f22e Binary files /dev/null and b/test/data/tx7-undo.raw differ diff --git a/test/data/tx7.raw b/test/data/tx7.raw new file mode 100644 index 000000000..eac2bab39 Binary files /dev/null and b/test/data/tx7.raw differ diff --git a/test/data/tx8.raw b/test/data/tx8.raw new file mode 100644 index 000000000..d00a83113 Binary files /dev/null and b/test/data/tx8.raw differ diff --git a/test/data/tx9.raw b/test/data/tx9.raw new file mode 100644 index 000000000..c48315556 Binary files /dev/null and b/test/data/tx9.raw differ diff --git a/test/data/undo1087400.raw b/test/data/undo1087400.raw deleted file mode 100644 index be1c4b583..000000000 Binary files a/test/data/undo1087400.raw and /dev/null differ diff --git a/test/data/undo928828.raw b/test/data/undo928828.raw deleted file mode 100644 index a0641c090..000000000 Binary files a/test/data/undo928828.raw and /dev/null differ diff --git a/test/data/undo928927.raw b/test/data/undo928927.raw deleted file mode 100644 index 2fb303f04..000000000 Binary files a/test/data/undo928927.raw and /dev/null differ diff --git a/test/data/wtx.hex b/test/data/wtx.hex deleted file mode 100644 index 722a4e60a..000000000 --- a/test/data/wtx.hex +++ /dev/null @@ -1,2 +0,0 @@ - -01000000000105758639e01c9ed6b5da154981068168bc55fae24ca4a3474b86b994730404f71b0000000000ffffffff8e08f2ae45276fb70132275e29556ee181b16ebf8225161872af465e31a998300000000000ffffffffb680de242354a98265128461f2cb5001c05e64e2d118b08c03868b859f280758000000006b483045022100b9c598b62a7133e98c956882b56eb4d8ca6aabfe80140e336d9cb5df008b101402204fb16b8dd602eedd61a43143240b7e8dc7da4ebe9add486f1ec9532a2244cfa301210246afb382a5d5769c173bc88b9d9e97909cee408c04ddc62c91bdf8fa68781ba1ffffffff6186acc1567feb25794411812b1f084201a8eece69a32428e117c2fcd23663620000000000ffffffff4eac6b7560fca8f732123de3a601898a389f0f2a4355c7952eecc52f6138646f0000000000fffffffffdbc07c019a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc119a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc219a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc319a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc419a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc519a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc619a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc719a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc819a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc919a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd019a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd119a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd219a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd319a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd419a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd519a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd619a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd719a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd819a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd919a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe019a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe119a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe219a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe319a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe419a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe519a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe619a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe719a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe819a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe919a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff019a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff119a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff219a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff319a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff419a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff519a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff619a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff719a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff819a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff919a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff19a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f001aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f011aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f021aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f031aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f041aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f051aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f061aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f071aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f081aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f091aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f101aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f111aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f121aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f131aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f141aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f151aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f161aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f171aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f181aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f191aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f201aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f211aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f221aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f231aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f241aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f251aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f261aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f271aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f281aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f291aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f301aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f311aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f321aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f331aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f341aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f351aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f361aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f371aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f381aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f391aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f401aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f411aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f421aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f431aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f441aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f451aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f461aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f471aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f481aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f491aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f501aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f511aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f521aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f531aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f541aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f551aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f561aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f571aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f581aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f591aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f601aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f611aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f621aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f631aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f641aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f651aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f661aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f671aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f681aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f691aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f701aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f711aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f721aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f731aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f741aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f751aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f761aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f771aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f781aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f791aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f801aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f811aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f821aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f831aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f841aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f851aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f861aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f871aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f881aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f891aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f901aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f911aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f921aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f931aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f941aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f951aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f961aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f971aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f981aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f991aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa01aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa11aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa21aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa31aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa41aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa51aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa61aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa71aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa81aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa91aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb01aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb11aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb21aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb31aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb41aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb51aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb61aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb71aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb81aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb91aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc01aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc11aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc21aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc31aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc41aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc51aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc61aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc71aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc81aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc91aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd01aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd11aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd21aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd31aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd41aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd51aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd61aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd71aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd81aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd91aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe01aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe11aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe21aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe31aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe41aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe51aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe61aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe71aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe81aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe91aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff01aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff11aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff21aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff31aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff41aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff51aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff61aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff71aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff81aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff91aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff1aa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f001ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f011ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f021ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f031ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f041ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f051ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f061ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f071ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f081ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f091ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f101ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f111ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f121ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f131ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f141ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f151ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f161ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f171ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f181ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f191ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f201ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f211ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f221ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f231ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f241ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f251ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f261ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f271ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f281ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f291ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f301ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f311ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f321ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f331ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f341ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f351ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f361ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f371ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f381ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f391ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f401ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f411ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f421ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f431ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f441ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f451ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f461ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f471ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f481ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f491ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f501ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f511ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f521ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f531ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f541ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f551ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f561ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f571ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f581ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f591ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f601ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f611ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f621ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f631ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f641ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f651ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f661ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f671ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f681ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f691ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f701ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f711ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f721ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f731ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f741ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f751ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f761ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f771ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f781ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f791ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f801ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f811ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f821ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f831ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f841ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f851ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f861ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f871ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f881ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f891ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f901ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f911ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f921ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f931ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f941ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f951ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f961ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f971ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f981ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f991ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa01ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa11ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa21ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa31ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa41ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa51ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa61ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa71ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa81ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa91ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb01ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb11ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb21ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb31ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb41ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb51ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb61ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb71ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb81ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb91ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc01ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc11ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc21ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc31ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc41ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc51ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc61ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc71ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc81ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc91ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd01ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd11ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd21ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd31ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd41ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd51ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd61ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd71ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd81ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd91ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe01ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe11ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe21ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe31ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe41ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe51ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe61ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe71ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe81ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe91ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff01ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff11ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff21ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff31ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff41ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff51ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff61ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff71ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff81ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff91ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff1ba60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f001ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f011ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f021ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f031ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f041ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f051ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f061ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f071ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f081ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f091ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f101ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f111ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f121ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f131ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f141ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f151ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f161ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f171ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f181ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f191ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f201ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f211ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f221ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f231ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f241ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f251ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f261ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f271ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f281ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f291ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f301ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f311ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f321ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f331ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f341ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f351ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f361ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f371ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f381ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f391ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f401ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f411ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f421ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f431ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f441ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f451ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f461ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f471ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f481ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f491ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f501ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f511ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f521ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f531ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f541ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f551ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f561ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f571ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f581ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f591ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f601ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f611ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f621ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f631ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f641ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f651ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f661ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f671ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f681ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f691ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f701ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f711ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f721ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f731ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f741ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f751ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f761ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f771ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f781ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f791ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f801ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f811ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f821ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f831ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f841ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f851ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f861ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f871ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f881ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f891ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f901ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f911ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f921ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f931ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f941ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f951ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f961ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f971ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f981ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f991ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa01ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa11ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa21ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa31ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa41ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa51ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa61ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa71ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa81ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa91ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb01ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb11ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb21ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb31ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb41ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb51ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb61ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb71ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb81ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb91ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc01ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc11ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc21ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc31ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc41ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc51ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc61ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc71ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc81ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc91ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd01ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd11ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd21ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd31ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd41ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd51ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd61ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd71ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd81ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd91ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe01ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe11ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe21ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe31ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe41ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe51ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe61ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe71ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe81ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe91ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff01ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff11ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff21ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff31ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff41ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff51ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff61ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff71ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff81ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff91ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff1ca60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f001da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f011da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f021da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f031da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f041da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f051da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f061da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f071da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f081da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f091da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f101da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f111da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f121da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f131da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f141da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f151da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f161da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f171da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f181da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f191da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f201da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f211da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f221da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f231da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f241da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f251da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f261da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f271da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f281da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f291da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f301da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f311da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f321da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f331da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f341da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f351da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f361da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f371da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f381da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f391da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f401da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f411da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f421da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f431da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f441da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f451da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f461da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f471da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f481da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f491da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f501da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f511da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f521da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f531da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f541da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f551da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f561da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f571da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f581da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f591da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f601da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f611da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f621da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f631da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f641da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f651da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f661da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f671da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f681da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f691da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f701da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f711da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f721da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f731da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f741da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f751da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f761da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f771da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f781da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f791da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f801da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f811da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f821da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f831da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f841da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f851da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f861da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f871da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f881da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f891da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f901da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f911da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f921da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f931da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f941da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f951da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f961da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f971da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f981da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f991da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa01da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa11da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa21da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa31da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa41da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa51da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa61da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa71da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa81da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa91da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb01da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb11da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb21da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb31da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb41da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb51da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb61da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb71da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb81da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb91da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc01da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc11da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc21da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc31da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc41da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc51da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc61da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc71da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc81da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc91da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd01da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd11da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd21da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd31da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd41da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd51da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd61da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd71da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd81da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd91da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe01da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe11da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe21da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe31da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe41da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe51da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe61da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe71da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe81da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe91da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff01da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff11da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff21da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff31da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff41da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff51da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff61da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff71da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff81da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff91da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff1da60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f001ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f011ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f021ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f031ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f041ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f051ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f061ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f071ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f081ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f091ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f101ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f111ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f121ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f131ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f141ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f151ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f161ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f171ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f181ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f191ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f201ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f211ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f221ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f231ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f241ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f251ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f261ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f271ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f281ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f291ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f301ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f311ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f321ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f331ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f341ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f351ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f361ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f371ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f381ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f391ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f401ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f411ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f421ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f431ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f441ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f451ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f461ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f471ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f481ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f491ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f501ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f511ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f521ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f531ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f541ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f551ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f561ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f571ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f581ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f591ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f601ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f611ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f621ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f631ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f641ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f651ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f661ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f671ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f681ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f691ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f701ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f711ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f721ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f731ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f741ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f751ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f761ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f771ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f781ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f791ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f801ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f811ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f821ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f831ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f841ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f851ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f861ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f871ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f881ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f891ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f901ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f911ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f921ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f931ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f941ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f951ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f961ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f971ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f981ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f991ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa01ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa11ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa21ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa31ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa41ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa51ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa61ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa71ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa81ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa91ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb01ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb11ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb21ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb31ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb41ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb51ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb61ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb71ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb81ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb91ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc01ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc11ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc21ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc31ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc41ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc51ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc61ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc71ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc81ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc91ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd01ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd11ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd21ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd31ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd41ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd51ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd61ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd71ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd81ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd91ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe01ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe11ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe21ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe31ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe41ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe51ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe61ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe71ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe81ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe91ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff01ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff11ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff21ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff31ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff41ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff51ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff61ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff71ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff81ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff91ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff1ea60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f001fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f011fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f021fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f031fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f041fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f051fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f061fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f071fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f081fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f091fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f101fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f111fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f121fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f131fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f141fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f151fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f161fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f171fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f181fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f191fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f201fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f211fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f221fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f231fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f241fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f251fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f261fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f271fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f281fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f291fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f301fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f311fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f321fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f331fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f341fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f351fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f361fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f371fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f381fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f391fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f401fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f411fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f421fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f431fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f441fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f451fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f461fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f471fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f481fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f491fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f501fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f511fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f521fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f531fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f541fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f551fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f561fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f571fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f581fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f591fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f601fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f611fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f621fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f631fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f641fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f651fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f661fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f671fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f681fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f691fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f701fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f711fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f721fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f731fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f741fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f751fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f761fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f771fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f781fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f791fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f801fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f811fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f821fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f831fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f841fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f851fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f861fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f871fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f881fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f891fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f901fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f911fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f921fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f931fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f941fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f951fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f961fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f971fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f981fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f991fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa01fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa11fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa21fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa31fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa41fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa51fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa61fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa71fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa81fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa91fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb01fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb11fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb21fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb31fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb41fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb51fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb61fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb71fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb81fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb91fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc01fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc11fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc21fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc31fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc41fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc51fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc61fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc71fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc81fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc91fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd01fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd11fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd21fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd31fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd41fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd51fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd61fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd71fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd81fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd91fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe01fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe11fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe21fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe31fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe41fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe51fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe61fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe71fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe81fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe91fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff01fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff11fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff21fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff31fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff41fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff51fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff61fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff71fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff81fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff91fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff1fa60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f8f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9a20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9b20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9c20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9d20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9e20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f9f20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fa920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faa20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fab20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fac20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fad20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fae20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60faf20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fb920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fba20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbb20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbc20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbd20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbe20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fbf20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fc920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fca20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcb20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcc20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcd20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fce20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fcf20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fd920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fda20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdb20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdc20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdd20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fde20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fdf20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fe920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fea20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60feb20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fec20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fed20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fee20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fef20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff020a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff120a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff220a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff320a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff420a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff520a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff620a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff720a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff820a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ff920a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffa20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffb20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffc20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffd20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60ffe20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60fff20a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f0f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f1f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f2f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f3f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f4f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f5f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6b21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6c21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6d21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6e21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f6f21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7021a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7121a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7221a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7321a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7421a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7521a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7621a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7721a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7821a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7921a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f7a21a60200000000160014af0c43441decf74cfc1572ac622d960f13d8c60f706aa20a000000001600143ef5ab3a3e3976c0a43831ae73bc48d4a4e0926b02483045022100aafaf192595d702294e6bc39df99afa0b226f8bd62b3ba47d4e414f9d153dcb202202432665875d514fc4cff12156cf9570cdc9ae9e295ecbd8ca508e90502638a8f01210244baf40086479a840fe7f50133c5ac3da9683bf17af3f0aa7cfadaaeba15a09a02483045022100efb2e2f79656933cda5361130238920fd34168c63d609c70cdbc7f05b2331fb802200ee8182293f533431d0293dc1072fb6baa53b8c99ca471ce08b93a744bee189401210202e4e426a9d3fe9e689736df81ce4f9953ecfc4978970f9d422f35cd4101d0d60002483045022100f64642de8f58b4c1ca3b552f6858e655ca1a7801d1109fb08667f344980da3ee02204aa0a4bd3d6014dd8b12386b295c13c1252c15c5816fd02dc804173a54a44e44012102c1919b9a59ed7edf82d9dc6941c0bc78b13e6586d1a176895e181a5b77c832070247304402207c51807aab7d272d8dbe749d3e45b42a0dcecd1c2285512ab095bbaa4e4c17a802201af484192a86901582ed0c4b9fc34f28d74fcfd6bee4acb2f3aa655820a0f1b301210377c6c9511d1d325a4686515dea1a0012ef9f5ff269e8491e45332328ddea19e000000000 diff --git a/test/gcs-test.js b/test/gcs-test.js index 179d79e4e..38ecf0143 100644 --- a/test/gcs-test.js +++ b/test/gcs-test.js @@ -1,6 +1,9 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const fs = require('../lib/utils/fs'); const GCSFilter = require('../lib/utils/gcs'); const random = require('../lib/crypto/random'); @@ -8,76 +11,78 @@ const Block = require('../lib/primitives/block'); const Outpoint = require('../lib/primitives/outpoint'); const Address = require('../lib/primitives/address'); -let raw = fs.readFileSync(`${__dirname}/data/block928927.raw`); -let block = Block.fromRaw(raw); +const raw = fs.readFileSync(`${__dirname}/data/block928927.raw`); +const block = Block.fromRaw(raw); + +const key = random.randomBytes(16); +const P = 20; + +const contents1 = [ + Buffer.from('Alex', 'ascii'), + Buffer.from('Bob', 'ascii'), + Buffer.from('Charlie', 'ascii'), + Buffer.from('Dick', 'ascii'), + Buffer.from('Ed', 'ascii'), + Buffer.from('Frank', 'ascii'), + Buffer.from('George', 'ascii'), + Buffer.from('Harry', 'ascii'), + Buffer.from('Ilya', 'ascii'), + Buffer.from('John', 'ascii'), + Buffer.from('Kevin', 'ascii'), + Buffer.from('Larry', 'ascii'), + Buffer.from('Michael', 'ascii'), + Buffer.from('Nate', 'ascii'), + Buffer.from('Owen', 'ascii'), + Buffer.from('Paul', 'ascii'), + Buffer.from('Quentin', 'ascii') +]; + +const contents2 = [ + Buffer.from('Alice', 'ascii'), + Buffer.from('Betty', 'ascii'), + Buffer.from('Charmaine', 'ascii'), + Buffer.from('Donna', 'ascii'), + Buffer.from('Edith', 'ascii'), + Buffer.from('Faina', 'ascii'), + Buffer.from('Georgia', 'ascii'), + Buffer.from('Hannah', 'ascii'), + Buffer.from('Ilsbeth', 'ascii'), + Buffer.from('Jennifer', 'ascii'), + Buffer.from('Kayla', 'ascii'), + Buffer.from('Lena', 'ascii'), + Buffer.from('Michelle', 'ascii'), + Buffer.from('Natalie', 'ascii'), + Buffer.from('Ophelia', 'ascii'), + Buffer.from('Peggy', 'ascii'), + Buffer.from('Queenie', 'ascii') +]; + +const op1 = new Outpoint( + '4cba1d1753ed19dbeafffb1a6c805d20e4af00b194a8f85353163cef83319c2c', + 4); + +const op2 = new Outpoint( + 'b7c3c4bce1a23baef2da05f9b7e4bff813449ec7e80f980ec7e4cacfadcd3314', + 3); + +const op3 = new Outpoint( + '4cba1d1753ed19dbeafffb1a6c805d20e4af00b194a8f85353163cef83319c2c', + 400); + +const op4 = new Outpoint( + 'b7c3c4bce1a23baef2da05f9b7e4bff813449ec7e80f980ec7e4cacfadcd3314', + 300); + +const addr1 = new Address('bc1qmyrddmxglk49ye2wd29wefaavw7es8k5d555lx'); +const addr2 = new Address('bc1q4645ycu0l9pnvxaxnhemushv0w4cd9flkqh95j'); + +let filter1 = null; +let filter2 = null; +let filter3 = null; +let filter4 = null; +let filter5 = null; describe('GCS', function() { - let key = random.randomBytes(16); - let P = 20; - let filter1, filter2, filter3, filter4, filter5; - let contents1, contents2; - let op1, op2, op3, op4; - let addr1, addr2; - - contents1 = [ - Buffer.from('Alex', 'ascii'), - Buffer.from('Bob', 'ascii'), - Buffer.from('Charlie', 'ascii'), - Buffer.from('Dick', 'ascii'), - Buffer.from('Ed', 'ascii'), - Buffer.from('Frank', 'ascii'), - Buffer.from('George', 'ascii'), - Buffer.from('Harry', 'ascii'), - Buffer.from('Ilya', 'ascii'), - Buffer.from('John', 'ascii'), - Buffer.from('Kevin', 'ascii'), - Buffer.from('Larry', 'ascii'), - Buffer.from('Michael', 'ascii'), - Buffer.from('Nate', 'ascii'), - Buffer.from('Owen', 'ascii'), - Buffer.from('Paul', 'ascii'), - Buffer.from('Quentin', 'ascii') - ]; - - contents2 = [ - Buffer.from('Alice', 'ascii'), - Buffer.from('Betty', 'ascii'), - Buffer.from('Charmaine', 'ascii'), - Buffer.from('Donna', 'ascii'), - Buffer.from('Edith', 'ascii'), - Buffer.from('Faina', 'ascii'), - Buffer.from('Georgia', 'ascii'), - Buffer.from('Hannah', 'ascii'), - Buffer.from('Ilsbeth', 'ascii'), - Buffer.from('Jennifer', 'ascii'), - Buffer.from('Kayla', 'ascii'), - Buffer.from('Lena', 'ascii'), - Buffer.from('Michelle', 'ascii'), - Buffer.from('Natalie', 'ascii'), - Buffer.from('Ophelia', 'ascii'), - Buffer.from('Peggy', 'ascii'), - Buffer.from('Queenie', 'ascii') - ]; - - op1 = new Outpoint( - '4cba1d1753ed19dbeafffb1a6c805d20e4af00b194a8f85353163cef83319c2c', - 4); - - op2 = new Outpoint( - 'b7c3c4bce1a23baef2da05f9b7e4bff813449ec7e80f980ec7e4cacfadcd3314', - 3); - - op3 = new Outpoint( - '4cba1d1753ed19dbeafffb1a6c805d20e4af00b194a8f85353163cef83319c2c', - 400); - - op4 = new Outpoint( - 'b7c3c4bce1a23baef2da05f9b7e4bff813449ec7e80f980ec7e4cacfadcd3314', - 300); - - addr1 = new Address('bc1qmyrddmxglk49ye2wd29wefaavw7es8k5d555lx'); - addr2 = new Address('bc1q4645ycu0l9pnvxaxnhemushv0w4cd9flkqh95j'); - it('should test GCS filter build', () => { filter1 = GCSFilter.fromItems(P, key, contents1); assert(filter1); @@ -95,20 +100,20 @@ describe('GCS', function() { }); it('should test GCS filter metadata', () => { - assert.equal(filter1.p, P); - assert.equal(filter1.n, contents1.length); - assert.equal(filter1.p, filter2.p); - assert.equal(filter1.n, filter2.n); - assert.deepEqual(filter1.data, filter2.data); - assert.equal(filter1.p, filter3.p); - assert.equal(filter1.n, filter3.n); - assert.deepEqual(filter1.data, filter3.data); - assert.equal(filter1.p, filter4.p); - assert.equal(filter1.n, filter4.n); - assert.deepEqual(filter1.data, filter4.data); - assert.equal(filter1.p, filter5.p); - assert.equal(filter1.n, filter5.n); - assert.deepEqual(filter1.data, filter5.data); + assert.strictEqual(filter1.p, P); + assert.strictEqual(filter1.n, contents1.length); + assert.strictEqual(filter1.p, filter2.p); + assert.strictEqual(filter1.n, filter2.n); + assert.bufferEqual(filter1.data, filter2.data); + assert.strictEqual(filter1.p, filter3.p); + assert.strictEqual(filter1.n, filter3.n); + assert.bufferEqual(filter1.data, filter3.data); + assert.strictEqual(filter1.p, filter4.p); + assert.strictEqual(filter1.n, filter4.n); + assert.bufferEqual(filter1.data, filter4.data); + assert.strictEqual(filter1.p, filter5.p); + assert.strictEqual(filter1.n, filter5.n); + assert.bufferEqual(filter1.data, filter5.data); }); it('should test GCS filter match', () => { @@ -132,25 +137,23 @@ describe('GCS', function() { }); it('should test GCS filter matchAny', () => { - let c, match; - - match = filter1.matchAny(key, contents2); + let match = filter1.matchAny(key, contents2); assert(!match); match = filter2.matchAny(key, contents2); assert(!match); - c = contents2.slice(); - c.push(Buffer.from('Nate')); + const contents = contents2.slice(); + contents.push(Buffer.from('Nate')); - match = filter1.matchAny(key, c); + match = filter1.matchAny(key, contents); assert(match); - match = filter2.matchAny(key, c); + match = filter2.matchAny(key, contents); assert(match); }); it('should test GCS filter fromBlock', () => { - let key = block.hash().slice(0, 16); - let filter = GCSFilter.fromBlock(block); + const key = block.hash().slice(0, 16); + const filter = GCSFilter.fromBlock(block); assert(filter.match(key, op1.toRaw())); assert(filter.match(key, op2.toRaw())); assert(!filter.match(key, op3.toRaw())); @@ -163,8 +166,8 @@ describe('GCS', function() { }); it('should test GCS filter fromExtended', () => { - let key = block.hash().slice(0, 16); - let filter = GCSFilter.fromExtended(block); + const key = block.hash().slice(0, 16); + const filter = GCSFilter.fromExtended(block); assert(!filter.match(key, op1.toRaw())); assert(filter.match(key, block.txs[0].hash())); assert(filter.match(key, block.txs[1].hash())); diff --git a/test/hd-test.js b/test/hd-test.js index fb2a5db06..7b1293c59 100644 --- a/test/hd-test.js +++ b/test/hd-test.js @@ -1,6 +1,9 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const HD = require('../lib/hd'); const base58 = require('../lib/utils/base58'); const pbkdf2 = require('../lib/crypto/pbkdf2'); @@ -8,73 +11,73 @@ const vectors = require('./data/hd.json'); const vector1 = vectors.vector1; const vector2 = vectors.vector2; -function ub58(data) { - return base58.decode(data).toString('hex'); -} +let master = null; +let child = null; -function equal(a, b) { - assert.equal(a, b); - assert.equal(ub58(a), ub58(b)); +function base58Equal(a, b) { + assert.strictEqual(a, b); + assert.bufferEqual(base58.decode(a), base58.decode(b)); } describe('HD', function() { - let master, child1, child2, child3, child4, child5, child6; - it('should create a pbkdf2 seed', () => { - let seed = pbkdf2.derive(vectors.phrase, 'mnemonicfoo', 2048, 64, 'sha512'); - assert.equal(seed.toString('hex'), vectors.seed); + const seed = pbkdf2.derive( + vectors.phrase, 'mnemonicfoo', 2048, 64, 'sha512'); + assert.strictEqual(seed.toString('hex'), vectors.seed); }); it('should create master private key', () => { - master = HD.PrivateKey.fromSeed(Buffer.from(vectors.seed, 'hex')); - assert.equal(master.toBase58(), vectors.master_priv); - assert.equal(master.toPublic().toBase58(), vectors.master_pub); + const seed = Buffer.from(vectors.seed, 'hex'); + const key = HD.PrivateKey.fromSeed(seed); + assert.strictEqual(key.toBase58(), vectors.master_priv); + assert.strictEqual(key.toPublic().toBase58(), vectors.master_pub); + master = key; }); it('should derive(0) child from master', () => { - child1 = master.derive(0); - assert.equal(child1.toBase58(), vectors.child1_priv); - assert.equal(child1.toPublic().toBase58(), vectors.child1_pub); + const child1 = master.derive(0); + assert.strictEqual(child1.toBase58(), vectors.child1_priv); + assert.strictEqual(child1.toPublic().toBase58(), vectors.child1_pub); }); it('should derive(1) child from master public key', () => { - child2 = master.toPublic().derive(1); - assert.equal(child2.toBase58(), vectors.child2_pub); + const child2 = master.toPublic().derive(1); + assert.strictEqual(child2.toBase58(), vectors.child2_pub); }); it('should derive(1) child from master', () => { - child3 = master.derive(1); - assert.equal(child3.toBase58(), vectors.child3_priv); - assert.equal(child3.toPublic().toBase58(), vectors.child3_pub); + const child3 = master.derive(1); + assert.strictEqual(child3.toBase58(), vectors.child3_priv); + assert.strictEqual(child3.toPublic().toBase58(), vectors.child3_pub); }); it('should derive(2) child from master', () => { - child4 = master.derive(2); - assert.equal(child4.toBase58(), vectors.child4_priv); - assert.equal(child4.toPublic().toBase58(), vectors.child4_pub); + const child4 = master.derive(2); + assert.strictEqual(child4.toBase58(), vectors.child4_priv); + assert.strictEqual(child4.toPublic().toBase58(), vectors.child4_pub); + child = child4; }); it('should derive(0) child from child(2)', () => { - child5 = child4.derive(0); - assert.equal(child5.toBase58(), vectors.child5_priv); - assert.equal(child5.toPublic().toBase58(), vectors.child5_pub); + const child5 = child.derive(0); + assert.strictEqual(child5.toBase58(), vectors.child5_priv); + assert.strictEqual(child5.toPublic().toBase58(), vectors.child5_pub); }); it('should derive(1) child from child(2)', () => { - child6 = child4.derive(1); - assert.equal(child6.toBase58(), vectors.child6_priv); - assert.equal(child6.toPublic().toBase58(), vectors.child6_pub); + const child6 = child.derive(1); + assert.strictEqual(child6.toBase58(), vectors.child6_priv); + assert.strictEqual(child6.toPublic().toBase58(), vectors.child6_pub); }); it('should derive correctly when private key has leading zeros', () => { - let key = HD.PrivateKey.fromBase58(vectors.zero_priv); - let child; + const key = HD.PrivateKey.fromBase58(vectors.zero_priv); - assert.equal(key.privateKey.toString('hex'), + assert.strictEqual(key.privateKey.toString('hex'), '00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd'); - child = key.derivePath('m/44\'/0\'/0\'/0/0\''); - assert.equal(child.privateKey.toString('hex'), + const child = key.derivePath('m/44\'/0\'/0\'/0/0\''); + assert.strictEqual(child.privateKey.toString('hex'), '3348069561d2a0fb925e74bf198762acc47dce7db27372257d2d959a9e6f8aeb'); }); @@ -86,31 +89,38 @@ describe('HD', function() { HD.PublicKey.fromBase58(master.toPublic().toBase58()); }); - it('should deserialize and reserialize', () => { - let key = HD.generate(); - assert.equal(HD.fromJSON(key.toJSON()).toBase58(), key.toBase58()); + it('should deserialize and reserialize json', () => { + const key = HD.generate(); + const json = key.toJSON(); + base58Equal(HD.fromJSON(json).toBase58(), key.toBase58()); }); - [vector1, vector2].forEach((vector) => { - let master; + for (const vector of [vector1, vector2]) { + let master = null; it('should create from a seed', () => { - master = HD.PrivateKey.fromSeed(Buffer.from(vector.seed, 'hex')); - equal(master.toBase58(), vector.m.prv); - equal(master.toPublic().toBase58(), vector.m.pub); - }); + const seed = Buffer.from(vector.seed, 'hex'); + const key = HD.PrivateKey.fromSeed(seed); + const pub = key.toPublic(); - Object.keys(vector).forEach((path) => { - let kp = vector[path]; + base58Equal(key.toBase58(), vector.m.prv); + base58Equal(pub.toBase58(), vector.m.pub); + master = key; + }); + + for (const path of Object.keys(vector)) { if (path === 'seed' || path === 'm') - return; + continue; + + const kp = vector[path]; it(`should derive ${path} from master`, () => { - let key = master.derivePath(path); - equal(key.toBase58(), kp.prv); - equal(key.toPublic().toBase58(), kp.pub); + const key = master.derivePath(path); + const pub = key.toPublic(); + base58Equal(key.toBase58(), kp.prv); + base58Equal(pub.toBase58(), kp.pub); }); - }); - }); + } + } }); diff --git a/test/hkdf-test.js b/test/hkdf-test.js new file mode 100644 index 000000000..8a43dcc6f --- /dev/null +++ b/test/hkdf-test.js @@ -0,0 +1,84 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + +'use strict'; + +const assert = require('./util/assert'); +const hkdf = require('../lib/crypto/hkdf'); + +describe('HKDF', function() { + it('should do proper hkdf (1)', () => { + // https://tools.ietf.org/html/rfc5869 + const alg = 'sha256'; + const ikm = Buffer.from( + '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'); + const salt = Buffer.from('000102030405060708090a0b0c', 'hex'); + const info = Buffer.from('f0f1f2f3f4f5f6f7f8f9', 'hex'); + const len = 42; + + const prkE = Buffer.from( + '077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5', + 'hex'); + + const okmE = Buffer.from('' + + '3cb25f25faacd57a90434f64d0362f2a2d2d0a90' + + 'cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865', + 'hex'); + + const prk = hkdf.extract(ikm, salt, alg); + const okm = hkdf.expand(prk, info, len, alg); + + assert.bufferEqual(prk, prkE); + assert.bufferEqual(okm, okmE); + }); + + it('should do proper hkdf (2)', () => { + const alg = 'sha256'; + + const ikm = Buffer.from('' + + '000102030405060708090a0b0c0d0e0f' + + '101112131415161718191a1b1c1d1e1f' + + '202122232425262728292a2b2c2d2e2f' + + '303132333435363738393a3b3c3d3e3f' + + '404142434445464748494a4b4c4d4e4f', + 'hex'); + + const salt = Buffer.from('' + + '606162636465666768696a6b6c6d6e6f' + + '707172737475767778797a7b7c7d7e7f' + + '808182838485868788898a8b8c8d8e8f' + + '909192939495969798999a9b9c9d9e9f' + + 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf', + 'hex'); + + const info = Buffer.from('' + + 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' + + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' + + 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' + + 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' + + 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', + 'hex'); + + const len = 82; + + const prkE = Buffer.from('' + + '06a6b88c5853361a06104c9ceb35b45c' + + 'ef760014904671014a193f40c15fc244', + 'hex'); + + const okmE = Buffer.from('' + + 'b11e398dc80327a1c8e7f78c596a4934' + + '4f012eda2d4efad8a050cc4c19afa97c' + + '59045a99cac7827271cb41c65e590e09' + + 'da3275600c2f09b8367793a9aca3db71' + + 'cc30c58179ec3e87c14c01d5c1f3434f' + + '1d87', + 'hex'); + + const prk = hkdf.extract(ikm, salt, alg); + const okm = hkdf.expand(prk, info, len, alg); + + assert.bufferEqual(prk, prkE); + assert.bufferEqual(okm, okmE); + }); +}); diff --git a/test/http-test.js b/test/http-test.js index 5b6cbf224..748f20422 100644 --- a/test/http-test.js +++ b/test/http-test.js @@ -1,6 +1,9 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const consensus = require('../lib/protocol/consensus'); const encoding = require('../lib/utils/encoding'); const co = require('../lib/utils/co'); @@ -11,27 +14,27 @@ const MTX = require('../lib/primitives/mtx'); const HTTP = require('../lib/http'); const FullNode = require('../lib/node/fullnode'); const pkg = require('../lib/pkg'); -const plugin = require('../lib/wallet/plugin'); - -describe('HTTP', function() { - let node, wallet, walletdb, addr, hash; - node = new FullNode({ - network: 'regtest', - apiKey: 'foo', - walletAuth: true, - db: 'memory' - }); +const node = new FullNode({ + network: 'regtest', + apiKey: 'foo', + walletAuth: true, + db: 'memory', + workers: true, + plugins: [require('../lib/wallet/plugin')] +}); - wallet = new HTTP.Wallet({ - network: 'regtest', - apiKey: 'foo' - }); +const wallet = new HTTP.Wallet({ + network: 'regtest', + apiKey: 'foo' +}); - walletdb = node.use(plugin); +const wdb = node.require('walletdb'); - node.on('error', () => {}); +let addr = null; +let hash = null; +describe('HTTP', function() { this.timeout(15000); it('should open node', async () => { @@ -40,76 +43,76 @@ describe('HTTP', function() { }); it('should create wallet', async () => { - let info = await wallet.create({ id: 'test' }); - assert.equal(info.id, 'test'); + const info = await wallet.create({ id: 'test' }); + assert.strictEqual(info.id, 'test'); }); it('should get info', async () => { - let info = await wallet.client.getInfo(); - assert.equal(info.network, node.network.type); - assert.equal(info.version, pkg.version); - assert.equal(info.pool.agent, node.pool.options.agent); - assert.equal(typeof info.chain, 'object'); - assert.equal(info.chain.height, 0); + const info = await wallet.client.getInfo(); + assert.strictEqual(info.network, node.network.type); + assert.strictEqual(info.version, pkg.version); + assert.typeOf(info.pool, 'object'); + assert.strictEqual(info.pool.agent, node.pool.options.agent); + assert.typeOf(info.chain, 'object'); + assert.strictEqual(info.chain.height, 0); }); it('should get wallet info', async () => { - let info = await wallet.getInfo(); - assert.equal(info.id, 'test'); - addr = info.account.receiveAddress; - assert.equal(typeof addr, 'string'); - addr = Address.fromString(addr); + const info = await wallet.getInfo(); + assert.strictEqual(info.id, 'test'); + assert.typeOf(info.account, 'object'); + const str = info.account.receiveAddress; + assert.typeOf(str, 'string'); + addr = Address.fromString(str); }); it('should fill with funds', async () => { - let tx, balance, receive, details; + const mtx = new MTX(); + mtx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0)); + mtx.addOutput(addr, 50460); + mtx.addOutput(addr, 50460); + mtx.addOutput(addr, 50460); + mtx.addOutput(addr, 50460); - // Coinbase - tx = new MTX(); - tx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0)); - tx.addOutput(addr, 50460); - tx.addOutput(addr, 50460); - tx.addOutput(addr, 50460); - tx.addOutput(addr, 50460); - tx = tx.toTX(); + const tx = mtx.toTX(); + let balance = null; wallet.once('balance', (b) => { balance = b; }); + let receive = null; wallet.once('address', (r) => { receive = r[0]; }); + let details = null; wallet.once('tx', (d) => { details = d; }); - await walletdb.addTX(tx); + await wdb.addTX(tx); await co.timeout(300); assert(receive); - assert.equal(receive.id, 'test'); - assert.equal(receive.type, 'pubkeyhash'); - assert.equal(receive.branch, 0); + assert.strictEqual(receive.id, 'test'); + assert.strictEqual(receive.type, 'pubkeyhash'); + assert.strictEqual(receive.branch, 0); assert(balance); - assert.equal(balance.confirmed, 0); - assert.equal(balance.unconfirmed, 201840); + assert.strictEqual(balance.confirmed, 0); + assert.strictEqual(balance.unconfirmed, 201840); assert(details); - assert.equal(details.hash, tx.rhash()); + assert.strictEqual(details.hash, tx.txid()); }); it('should get balance', async () => { - let balance = await wallet.getBalance(); - assert.equal(balance.confirmed, 0); - assert.equal(balance.unconfirmed, 201840); + const balance = await wallet.getBalance(); + assert.strictEqual(balance.confirmed, 0); + assert.strictEqual(balance.unconfirmed, 201840); }); it('should send a tx', async () => { - let value = 0; - let options, tx; - - options = { + const options = { rate: 10000, outputs: [{ value: 10000, @@ -117,83 +120,87 @@ describe('HTTP', function() { }] }; - tx = await wallet.send(options); + const tx = await wallet.send(options); assert(tx); - assert.equal(tx.inputs.length, 1); - assert.equal(tx.outputs.length, 2); + assert.strictEqual(tx.inputs.length, 1); + assert.strictEqual(tx.outputs.length, 2); + let value = 0; value += tx.outputs[0].value; value += tx.outputs[1].value; - assert.equal(value, 48190); + + assert.strictEqual(value, 48190); hash = tx.hash; }); it('should get a tx', async () => { - let tx = await wallet.getTX(hash); + const tx = await wallet.getTX(hash); assert(tx); - assert.equal(tx.hash, hash); + assert.strictEqual(tx.hash, hash); }); it('should generate new api key', async () => { - let t = wallet.token.toString('hex'); - let token = await wallet.retoken(null); - assert(token.length === 64); - assert.notEqual(token, t); + const old = wallet.token.toString('hex'); + const token = await wallet.retoken(null); + assert.strictEqual(token.length, 64); + assert.notStrictEqual(token, old); }); it('should get balance', async () => { - let balance = await wallet.getBalance(); - assert.equal(balance.unconfirmed, 199570); + const balance = await wallet.getBalance(); + assert.strictEqual(balance.unconfirmed, 199570); }); it('should execute an rpc call', async () => { - let info = await wallet.client.rpc.execute('getblockchaininfo', []); - assert.equal(info.blocks, 0); + const info = await wallet.client.rpc.execute('getblockchaininfo', []); + assert.strictEqual(info.blocks, 0); }); it('should execute an rpc call with bool parameter', async () => { - let info = await wallet.client.rpc.execute('getrawmempool', [true]); + const info = await wallet.client.rpc.execute('getrawmempool', [true]); assert.deepStrictEqual(info, {}); }); it('should create account', async () => { - let info = await wallet.createAccount('foo1'); + const info = await wallet.createAccount('foo1'); assert(info); assert(info.initialized); - assert.equal(info.name, 'foo1'); - assert.equal(info.accountIndex, 1); - assert.equal(info.m, 1); - assert.equal(info.n, 1); + assert.strictEqual(info.name, 'foo1'); + assert.strictEqual(info.accountIndex, 1); + assert.strictEqual(info.m, 1); + assert.strictEqual(info.n, 1); }); it('should create account', async () => { - let info = await wallet.createAccount('foo2', { + const info = await wallet.createAccount('foo2', { type: 'multisig', m: 1, n: 2 }); assert(info); assert(!info.initialized); - assert.equal(info.name, 'foo2'); - assert.equal(info.accountIndex, 2); - assert.equal(info.m, 1); - assert.equal(info.n, 2); + assert.strictEqual(info.name, 'foo2'); + assert.strictEqual(info.accountIndex, 2); + assert.strictEqual(info.m, 1); + assert.strictEqual(info.n, 2); }); it('should get a block template', async () => { - let json = await wallet.client.rpc.execute('getblocktemplate', []); + const json = await wallet.client.rpc.execute('getblocktemplate', []); assert.deepStrictEqual(json, { - capabilities: [ 'proposal' ], - mutable: [ 'time', 'transactions', 'prevblock' ], + capabilities: ['proposal'], + mutable: ['time', 'transactions', 'prevblock'], version: 536870912, rules: [], vbavailable: {}, vbrequired: 0, height: 1, - previousblockhash: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', - target: '7fffff0000000000000000000000000000000000000000000000000000000000', + previousblockhash: + '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', + target: + '7fffff0000000000000000000000000000000000000000000000000000000000', bits: '207fffff', noncerange: '00000000ffffffff', curtime: json.curtime, @@ -202,7 +209,9 @@ describe('HTTP', function() { expires: json.expires, sigoplimit: 20000, sizelimit: 1000000, - longpollid: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22060000000000', + longpollid: + '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206' + + '0000000000', submitold: false, coinbaseaux: { flags: '6d696e65642062792062636f696e' }, coinbasevalue: 5000000000, @@ -211,10 +220,10 @@ describe('HTTP', function() { }); it('should send a block template proposal', async () => { - let attempt = await node.miner.createBlock(); - let block = attempt.toBlock(); - let hex = block.toRaw().toString('hex'); - let json = await wallet.client.rpc.execute('getblocktemplate', [{ + const attempt = await node.miner.createBlock(); + const block = attempt.toBlock(); + const hex = block.toRaw().toString('hex'); + const json = await wallet.client.rpc.execute('getblocktemplate', [{ mode: 'proposal', data: hex }]); @@ -222,7 +231,9 @@ describe('HTTP', function() { }); it('should validate an address', async () => { - let json = await wallet.client.rpc.execute('validateaddress', [addr.toString()]); + const json = await wallet.client.rpc.execute('validateaddress', [ + addr.toString() + ]); assert.deepStrictEqual(json, { isvalid: true, address: addr.toString(), diff --git a/test/key-address-test.js b/test/key-address-test.js deleted file mode 100644 index a7674277c..000000000 --- a/test/key-address-test.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -const assert = require('assert'); -const keyring = require('../lib/primitives/keyring'); - -describe('Keyring Address', function() { - let ukey = keyring.fromSecret('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss'); - let ckey = keyring.fromSecret('L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1'); - - it('check uncompressed public key', () => { - assert.equal( - '04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b' - + '8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235', - ukey.getPublicKey('hex')); - }); - - it('check uncompressed public key to address', () => { - assert.equal( - '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN', - ukey.getKeyAddress('base58')); - }); - - it('check uncompressed secret', () => { - assert.equal( - '5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss', - ukey.toSecret()); - }); - - it('check compressed public key', () => { - assert.equal( - '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd', - ckey.getPublicKey('hex')); - }); - - it('check compressed public key to address', () => { - assert.equal( - '1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV', - ckey.getKeyAddress('base58')); - }); - - it('check compressed secret', () => { - assert.equal( - 'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1', - ckey.toSecret()); - }); -}); diff --git a/test/keyring-test.js b/test/keyring-test.js new file mode 100644 index 000000000..87cc0c2f7 --- /dev/null +++ b/test/keyring-test.js @@ -0,0 +1,52 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + +'use strict'; + +const assert = require('./util/assert'); +const KeyRing = require('../lib/primitives/keyring'); + +const uncompressed = KeyRing.fromSecret( + '5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss'); + +const compressed = KeyRing.fromSecret( + 'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1'); + +describe('KeyRing', function() { + it('should get uncompressed public key', () => { + assert.strictEqual( + '04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b' + + '8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235', + uncompressed.getPublicKey('hex')); + }); + + it('should get uncompressed public key address', () => { + assert.strictEqual( + '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN', + uncompressed.getKeyAddress('base58')); + }); + + it('should get uncompressed WIF', () => { + assert.strictEqual( + '5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss', + uncompressed.toSecret()); + }); + + it('should get compressed public key', () => { + assert.strictEqual( + '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd', + compressed.getPublicKey('hex')); + }); + + it('should get compressed public key address', () => { + assert.strictEqual( + '1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV', + compressed.getKeyAddress('base58')); + }); + + it('should get compressed WIF', () => { + assert.strictEqual( + 'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1', + compressed.toSecret()); + }); +}); diff --git a/test/mempool-test.js b/test/mempool-test.js index be134bf10..635673371 100644 --- a/test/mempool-test.js +++ b/test/mempool-test.js @@ -1,10 +1,14 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const encoding = require('../lib/utils/encoding'); const random = require('../lib/crypto/random'); const MempoolEntry = require('../lib/mempool/mempoolentry'); const Mempool = require('../lib/mempool/mempool'); +const WorkerPool = require('../lib/workers/workerpool'); const Chain = require('../lib/blockchain/chain'); const MTX = require('../lib/primitives/mtx'); const Coin = require('../lib/primitives/coin'); @@ -14,38 +18,50 @@ const Outpoint = require('../lib/primitives/outpoint'); const Script = require('../lib/script/script'); const Witness = require('../lib/script/witness'); const MemWallet = require('./util/memwallet'); +const ALL = Script.hashType.ALL; -describe('Mempool', function() { - let chain = new Chain({ db: 'memory' }); - let mempool = new Mempool({ chain: chain, db: 'memory' }); - let wallet = new MemWallet(); - let cached; +const workers = new WorkerPool({ + enabled: true +}); - this.timeout(5000); +const chain = new Chain({ + db: 'memory', + workers +}); + +const mempool = new Mempool({ + chain, + db: 'memory', + workers +}); - function dummy(prev, prevHash) { - let fund, coin, entry; +const wallet = new MemWallet(); - if (!prevHash) - prevHash = encoding.ONE_HASH.toString('hex'); +let cachedTX = null; - coin = new Coin(); - coin.height = 0; - coin.value = 0; - coin.script = prev; - coin.hash = prevHash; - coin.index = 0; +function dummyInput(script, hash) { + const coin = new Coin(); + coin.height = 0; + coin.value = 0; + coin.script = script; + coin.hash = hash; + coin.index = 0; - fund = new MTX(); - fund.addCoin(coin); - fund.addOutput(prev, 70000); + const fund = new MTX(); + fund.addCoin(coin); + fund.addOutput(script, 70000); - entry = MempoolEntry.fromTX(fund.toTX(), fund.view, 0); + const [tx, view] = fund.commit(); - mempool.trackEntry(entry, fund.view); + const entry = MempoolEntry.fromTX(tx, view, 0); - return Coin.fromTX(fund, 0, -1); - } + mempool.trackEntry(entry, view); + + return Coin.fromTX(fund, 0, -1); +} + +describe('Mempool', function() { + this.timeout(5000); it('should open mempool', async () => { await mempool.open(); @@ -53,152 +69,152 @@ describe('Mempool', function() { }); it('should handle incoming orphans and TXs', async () => { - let kp = KeyRing.generate(); - let w = wallet; - let t1, t2, t3, t4, f1, fake, prev, sig, balance, txs; + const key = KeyRing.generate(); + + const t1 = new MTX(); + t1.addOutput(wallet.getAddress(), 50000); + t1.addOutput(wallet.getAddress(), 10000); + + const script = Script.fromPubkey(key.publicKey); - t1 = new MTX(); - t1.addOutput(w.getAddress(), 50000); - t1.addOutput(w.getAddress(), 10000); + t1.addCoin(dummyInput(script, encoding.ONE_HASH.toString('hex'))); - prev = Script.fromPubkey(kp.publicKey); - t1.addCoin(dummy(prev)); - sig = t1.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); - t1.inputs[0].script = new Script([sig]); + const sig = t1.signature(0, script, 70000, key.privateKey, ALL, 0); + + t1.inputs[0].script = Script.fromItems([sig]); // balance: 51000 - w.sign(t1); - t1 = t1.toTX(); + wallet.sign(t1); - t2 = new MTX(); + const t2 = new MTX(); t2.addTX(t1, 0); // 50000 - t2.addOutput(w.getAddress(), 20000); - t2.addOutput(w.getAddress(), 20000); + t2.addOutput(wallet.getAddress(), 20000); + t2.addOutput(wallet.getAddress(), 20000); // balance: 49000 - w.sign(t2); - t2 = t2.toTX(); + wallet.sign(t2); - t3 = new MTX(); + const t3 = new MTX(); t3.addTX(t1, 1); // 10000 t3.addTX(t2, 0); // 20000 - t3.addOutput(w.getAddress(), 23000); + t3.addOutput(wallet.getAddress(), 23000); // balance: 47000 - w.sign(t3); - t3 = t3.toTX(); + wallet.sign(t3); - t4 = new MTX(); + const t4 = new MTX(); t4.addTX(t2, 1); // 24000 t4.addTX(t3, 0); // 23000 - t4.addOutput(w.getAddress(), 11000); - t4.addOutput(w.getAddress(), 11000); + t4.addOutput(wallet.getAddress(), 11000); + t4.addOutput(wallet.getAddress(), 11000); // balance: 22000 - w.sign(t4); - t4 = t4.toTX(); + wallet.sign(t4); - f1 = new MTX(); + const f1 = new MTX(); f1.addTX(t4, 1); // 11000 f1.addOutput(new Address(), 9000); // balance: 11000 - w.sign(f1); - f1 = f1.toTX(); + wallet.sign(f1); - fake = new MTX(); + const fake = new MTX(); fake.addTX(t1, 1); // 1000 (already redeemed) - fake.addOutput(w.getAddress(), 6000); // 6000 instead of 500 + fake.addOutput(wallet.getAddress(), 6000); // 6000 instead of 500 // Script inputs but do not sign - w.template(fake); + wallet.template(fake); // Fake signature - fake.inputs[0].script.set(0, encoding.ZERO_SIG); - fake.inputs[0].script.compile(); - fake = fake.toTX(); + const input = fake.inputs[0]; + input.script.setData(0, encoding.ZERO_SIG); + input.script.compile(); // balance: 11000 - await mempool.addTX(fake); - await mempool.addTX(t4); + { + await mempool.addTX(fake.toTX()); + await mempool.addTX(t4.toTX()); - balance = mempool.getBalance(); - assert.equal(balance, 70000); // note: funding balance + const balance = mempool.getBalance(); + assert.strictEqual(balance, 70000); + } - await mempool.addTX(t1); + { + await mempool.addTX(t1.toTX()); - balance = mempool.getBalance(); - assert.equal(balance, 60000); + const balance = mempool.getBalance(); + assert.strictEqual(balance, 60000); + } - await mempool.addTX(t2); + { + await mempool.addTX(t2.toTX()); - balance = mempool.getBalance(); - assert.equal(balance, 50000); + const balance = mempool.getBalance(); + assert.strictEqual(balance, 50000); + } - await mempool.addTX(t3); + { + await mempool.addTX(t3.toTX()); - balance = mempool.getBalance(); - assert.equal(balance, 22000); + const balance = mempool.getBalance(); + assert.strictEqual(balance, 22000); + } - await mempool.addTX(f1); + { + await mempool.addTX(f1.toTX()); - balance = mempool.getBalance(); - assert.equal(balance, 20000); + const balance = mempool.getBalance(); + assert.strictEqual(balance, 20000); + } - txs = mempool.getHistory(); + const txs = mempool.getHistory(); assert(txs.some((tx) => { return tx.hash('hex') === f1.hash('hex'); })); }); it('should handle locktime', async () => { - let w = wallet; - let kp = KeyRing.generate(); - let tx, prev, prevHash, sig; + const key = KeyRing.generate(); - tx = new MTX(); - tx.addOutput(w.getAddress(), 50000); - tx.addOutput(w.getAddress(), 10000); + const tx = new MTX(); + tx.addOutput(wallet.getAddress(), 50000); + tx.addOutput(wallet.getAddress(), 10000); - prev = Script.fromPubkey(kp.publicKey); - prevHash = random.randomBytes(32).toString('hex'); + const prev = Script.fromPubkey(key.publicKey); + const prevHash = random.randomBytes(32).toString('hex'); - tx.addCoin(dummy(prev, prevHash)); + tx.addCoin(dummyInput(prev, prevHash)); tx.setLocktime(200); chain.tip.height = 200; - sig = tx.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); - tx.inputs[0].script = new Script([sig]); - - tx = tx.toTX(); + const sig = tx.signature(0, prev, 70000, key.privateKey, ALL, 0); + tx.inputs[0].script = Script.fromItems([sig]); - await mempool.addTX(tx); + await mempool.addTX(tx.toTX()); chain.tip.height = 0; }); it('should handle invalid locktime', async () => { - let w = wallet; - let kp = KeyRing.generate(); - let tx, prev, prevHash, sig, err; + const key = KeyRing.generate(); - tx = new MTX(); - tx.addOutput(w.getAddress(), 50000); - tx.addOutput(w.getAddress(), 10000); + const tx = new MTX(); + tx.addOutput(wallet.getAddress(), 50000); + tx.addOutput(wallet.getAddress(), 10000); - prev = Script.fromPubkey(kp.publicKey); - prevHash = random.randomBytes(32).toString('hex'); + const prev = Script.fromPubkey(key.publicKey); + const prevHash = random.randomBytes(32).toString('hex'); - tx.addCoin(dummy(prev, prevHash)); + tx.addCoin(dummyInput(prev, prevHash)); tx.setLocktime(200); chain.tip.height = 200 - 1; - sig = tx.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); - tx.inputs[0].script = new Script([sig]); - tx = tx.toTX(); + const sig = tx.signature(0, prev, 70000, key.privateKey, ALL, 0); + tx.inputs[0].script = Script.fromItems([sig]); + let err; try { - await mempool.addTX(tx); + await mempool.addTX(tx.toTX()); } catch (e) { err = e; } @@ -209,31 +225,29 @@ describe('Mempool', function() { }); it('should not cache a malleated wtx with mutated sig', async () => { - let w = wallet; - let kp = KeyRing.generate(); - let tx, prev, prevHash, prevs, sig, err; + const key = KeyRing.generate(); - kp.witness = true; + key.witness = true; - tx = new MTX(); - tx.addOutput(w.getAddress(), 50000); - tx.addOutput(w.getAddress(), 10000); + const tx = new MTX(); + tx.addOutput(wallet.getAddress(), 50000); + tx.addOutput(wallet.getAddress(), 10000); - prev = Script.fromProgram(0, kp.getKeyHash()); - prevHash = random.randomBytes(32).toString('hex'); + const prev = Script.fromProgram(0, key.getKeyHash()); + const prevHash = random.randomBytes(32).toString('hex'); - tx.addCoin(dummy(prev, prevHash)); + tx.addCoin(dummyInput(prev, prevHash)); - prevs = Script.fromPubkeyhash(kp.getKeyHash()); + const prevs = Script.fromPubkeyhash(key.getKeyHash()); - sig = tx.signature(0, prevs, 70000, kp.privateKey, Script.hashType.ALL, 1); + const sig = tx.signature(0, prevs, 70000, key.privateKey, ALL, 1); sig[sig.length - 1] = 0; - tx.inputs[0].witness = new Witness([sig, kp.publicKey]); - tx = tx.toTX(); + tx.inputs[0].witness = new Witness([sig, key.publicKey]); + let err; try { - await mempool.addTX(tx); + await mempool.addTX(tx.toTX()); } catch (e) { err = e; } @@ -243,26 +257,24 @@ describe('Mempool', function() { }); it('should not cache a malleated tx with unnecessary witness', async () => { - let w = wallet; - let kp = KeyRing.generate(); - let tx, prev, prevHash, sig, err; + const key = KeyRing.generate(); - tx = new MTX(); - tx.addOutput(w.getAddress(), 50000); - tx.addOutput(w.getAddress(), 10000); + const tx = new MTX(); + tx.addOutput(wallet.getAddress(), 50000); + tx.addOutput(wallet.getAddress(), 10000); - prev = Script.fromPubkey(kp.publicKey); - prevHash = random.randomBytes(32).toString('hex'); + const prev = Script.fromPubkey(key.publicKey); + const prevHash = random.randomBytes(32).toString('hex'); - tx.addCoin(dummy(prev, prevHash)); + tx.addCoin(dummyInput(prev, prevHash)); - sig = tx.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); - tx.inputs[0].script = new Script([sig]); + const sig = tx.signature(0, prev, 70000, key.privateKey, ALL, 0); + tx.inputs[0].script = Script.fromItems([sig]); tx.inputs[0].witness.push(Buffer.alloc(0)); - tx = tx.toTX(); + let err; try { - await mempool.addTX(tx); + await mempool.addTX(tx.toTX()); } catch (e) { err = e; } @@ -272,25 +284,22 @@ describe('Mempool', function() { }); it('should not cache a malleated wtx with wit removed', async () => { - let w = wallet; - let kp = KeyRing.generate(); - let tx, prev, prevHash, err; + const key = KeyRing.generate(); - kp.witness = true; + key.witness = true; - tx = new MTX(); - tx.addOutput(w.getAddress(), 50000); - tx.addOutput(w.getAddress(), 10000); + const tx = new MTX(); + tx.addOutput(wallet.getAddress(), 50000); + tx.addOutput(wallet.getAddress(), 10000); - prev = Script.fromProgram(0, kp.getKeyHash()); - prevHash = random.randomBytes(32).toString('hex'); + const prev = Script.fromProgram(0, key.getKeyHash()); + const prevHash = random.randomBytes(32).toString('hex'); - tx.addCoin(dummy(prev, prevHash)); - - tx = tx.toTX(); + tx.addCoin(dummyInput(prev, prevHash)); + let err; try { - await mempool.addTX(tx); + await mempool.addTX(tx.toTX()); } catch (e) { err = e; } @@ -301,23 +310,20 @@ describe('Mempool', function() { }); it('should cache non-malleated tx without sig', async () => { - let w = wallet; - let kp = KeyRing.generate(); - let tx, prev, prevHash, err; - - tx = new MTX(); - tx.addOutput(w.getAddress(), 50000); - tx.addOutput(w.getAddress(), 10000); + const key = KeyRing.generate(); - prev = Script.fromPubkey(kp.publicKey); - prevHash = random.randomBytes(32).toString('hex'); + const tx = new MTX(); + tx.addOutput(wallet.getAddress(), 50000); + tx.addOutput(wallet.getAddress(), 10000); - tx.addCoin(dummy(prev, prevHash)); + const prev = Script.fromPubkey(key.publicKey); + const prevHash = random.randomBytes(32).toString('hex'); - tx = tx.toTX(); + tx.addCoin(dummyInput(prev, prevHash)); + let err; try { - await mempool.addTX(tx); + await mempool.addTX(tx.toTX()); } catch (e) { err = e; } @@ -325,21 +331,20 @@ describe('Mempool', function() { assert(err); assert(!err.malleated); assert(mempool.hasReject(tx.hash())); - cached = tx; + + cachedTX = tx; }); it('should clear reject cache', async () => { - let w = wallet; - let tx; - - tx = new MTX(); + const tx = new MTX(); tx.addOutpoint(new Outpoint()); - tx.addOutput(w.getAddress(), 50000); - tx = tx.toTX(); + tx.addOutput(wallet.getAddress(), 50000); + + assert(mempool.hasReject(cachedTX.hash())); + + await mempool.addBlock({ height: 1 }, [tx.toTX()]); - assert(mempool.hasReject(cached.hash())); - await mempool.addBlock({ height: 1 }, [tx]); - assert(!mempool.hasReject(cached.hash())); + assert(!mempool.hasReject(cachedTX.hash())); }); it('should destroy mempool', async () => { diff --git a/test/mnemonic-test.js b/test/mnemonic-test.js index bd5186e3d..10429cee3 100644 --- a/test/mnemonic-test.js +++ b/test/mnemonic-test.js @@ -1,63 +1,69 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); -const HD = require('../lib/hd'); +const assert = require('./util/assert'); +const Mnemonic = require('../lib/hd/mnemonic'); +const HDPrivateKey = require('../lib/hd/private'); -const mnemonic1 = require('./data/mnemonic1').english; -const mnemonic2 = require('./data/mnemonic2'); +const tests = { + english: require('./data/mnemonic-english.json'), + japanese: require('./data/mnemonic-japanese.json') +}; describe('Mnemonic', function() { - mnemonic1.forEach((data, i) => { - let entropy = Buffer.from(data[0], 'hex'); - let phrase = data[1]; - let seed = Buffer.from(data[2], 'hex'); - let xpriv = data[3]; - it(`should create an english mnemonic (${i})`, () => { - let mnemonic, key; - - mnemonic = new HD.Mnemonic({ - language: 'english', - entropy: entropy, - passphrase: 'TREZOR' - }); + for (const language of Object.keys(tests)) { + const test = tests[language]; + let i = 0; - assert.equal(mnemonic.getPhrase(), phrase); - assert.equal(mnemonic.toSeed().toString('hex'), seed.toString('hex')); + for (const data of test) { + const entropy = Buffer.from(data[0], 'hex'); + const phrase = data[1]; + const passphrase = data[2]; + const seed = Buffer.from(data[3], 'hex'); + const xpriv = data[4]; - key = HD.fromMnemonic(mnemonic); - assert.equal(key.toBase58(), xpriv); - }); - }); + it(`should create a ${language} mnemonic from entropy (${i})`, () => { + const mnemonic = new Mnemonic({ + language, + entropy, + passphrase + }); + + assert.strictEqual(mnemonic.getPhrase(), phrase); + assert.bufferEqual(mnemonic.getEntropy(), entropy); + assert.bufferEqual(mnemonic.toSeed(), seed); - mnemonic2.forEach((data, i) => { - let entropy = Buffer.from(data.entropy, 'hex'); - let phrase = data.mnemonic; - let seed = Buffer.from(data.seed, 'hex'); - let passphrase = data.passphrase; - let xpriv = data.bip32_xprv; - it(`should create a japanese mnemonic (${i})`, () => { - let mnemonic, key; - - mnemonic = new HD.Mnemonic({ - language: 'japanese', - entropy: entropy, - passphrase: passphrase + const key = HDPrivateKey.fromMnemonic(mnemonic); + assert.strictEqual(key.toBase58(), xpriv); }); - assert.equal(mnemonic.getPhrase(), phrase); - assert.equal(mnemonic.toSeed().toString('hex'), seed.toString('hex')); + it(`should create a ${language} mnemonic from phrase (${i})`, () => { + const mnemonic = new Mnemonic({ + language, + phrase, + passphrase + }); - key = HD.fromMnemonic(mnemonic); - assert.equal(key.toBase58(), xpriv); - }); - }); + assert.strictEqual(mnemonic.getPhrase(), phrase); + assert.bufferEqual(mnemonic.getEntropy(), entropy); + assert.bufferEqual(mnemonic.toSeed(), seed); + + const key = HDPrivateKey.fromMnemonic(mnemonic); + assert.strictEqual(key.toBase58(), xpriv); + }); + + i += 1; + } + } it('should verify phrase', () => { - let m1 = new HD.Mnemonic(); - let m2 = HD.Mnemonic.fromPhrase(m1.getPhrase()); - assert.deepEqual(m2.getEntropy(), m1.getEntropy()); - assert.equal(m2.bits, m1.bits); - assert.equal(m2.language, m1.language); - assert.deepEqual(m2.toSeed(), m1.toSeed()); + const m1 = new Mnemonic(); + const m2 = Mnemonic.fromPhrase(m1.getPhrase()); + assert.bufferEqual(m2.getEntropy(), m1.getEntropy()); + assert.strictEqual(m2.bits, m1.bits); + assert.strictEqual(m2.language, m1.language); + assert.bufferEqual(m2.toSeed(), m1.toSeed()); }); }); diff --git a/test/node-test.js b/test/node-test.js index f94c27aa7..a7dc5dea4 100644 --- a/test/node-test.js +++ b/test/node-test.js @@ -1,57 +1,89 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); -const BN = require('../lib/crypto/bn'); +const assert = require('./util/assert'); const consensus = require('../lib/protocol/consensus'); const co = require('../lib/utils/co'); const Coin = require('../lib/primitives/coin'); const Script = require('../lib/script/script'); +const Opcode = require('../lib/script/opcode'); const FullNode = require('../lib/node/fullnode'); const MTX = require('../lib/primitives/mtx'); const TX = require('../lib/primitives/tx'); const Address = require('../lib/primitives/address'); -const plugin = require('../lib/wallet/plugin'); -describe('Node', function() { - let node = new FullNode({ - db: 'memory', - apiKey: 'foo', - network: 'regtest', - workers: true - }); - let chain = node.chain; - let walletdb = node.use(plugin); - let miner = node.miner; - let wallet, tip1, tip2, cb1, cb2; - let tx1, tx2; +const node = new FullNode({ + db: 'memory', + apiKey: 'foo', + network: 'regtest', + workers: true, + plugins: [require('../lib/wallet/plugin')] +}); - node.on('error', () => {}); +const chain = node.chain; +const miner = node.miner; +const wdb = node.require('walletdb'); - this.timeout(5000); +let wallet = null; +let tip1 = null; +let tip2 = null; +let cb1 = null; +let cb2 = null; +let tx1 = null; +let tx2 = null; - async function mineBlock(tip, tx) { - let job = await miner.createJob(tip); - let rtx; +async function mineBlock(tip, tx) { + const job = await miner.createJob(tip); - if (!tx) - return await job.mineAsync(); + if (!tx) + return await job.mineAsync(); - rtx = new MTX(); + const spend = new MTX(); - rtx.addTX(tx, 0); + spend.addTX(tx, 0); - rtx.addOutput(wallet.getReceive(), 25 * 1e8); - rtx.addOutput(wallet.getChange(), 5 * 1e8); + spend.addOutput(wallet.getReceive(), 25 * 1e8); + spend.addOutput(wallet.getChange(), 5 * 1e8); - rtx.setLocktime(chain.height); + spend.setLocktime(chain.height); - await wallet.sign(rtx); + await wallet.sign(spend); - job.addTX(rtx.toTX(), rtx.view); - job.refresh(); + job.addTX(spend.toTX(), spend.view); + job.refresh(); - return await job.mineAsync(); - } + return await job.mineAsync(); +} + +async function mineCSV(fund) { + const job = await miner.createJob(); + const spend = new MTX(); + + spend.addOutput({ + script: [ + Opcode.fromInt(1), + Opcode.fromSymbol('checksequenceverify') + ], + value: 10 * 1e8 + }); + + spend.addTX(fund, 0); + spend.setLocktime(chain.height); + + await wallet.sign(spend); + + const [tx, view] = spend.commit(); + + job.addTX(tx, view); + job.refresh(); + + return await job.mineAsync(); +} + +describe('Node', function() { + this.timeout(5000); it('should open chain and miner', async () => { miner.mempool = null; @@ -60,32 +92,30 @@ describe('Node', function() { }); it('should open walletdb', async () => { - wallet = await walletdb.create(); + wallet = await wdb.create(); miner.addresses.length = 0; miner.addAddress(wallet.getReceive()); }); it('should mine a block', async () => { - let block = await miner.mineBlock(); + const block = await miner.mineBlock(); assert(block); await chain.add(block); }); it('should mine competing chains', async () => { - let i, block1, block2; - - for (i = 0; i < 10; i++) { - block1 = await mineBlock(tip1, cb1); + for (let i = 0; i < 10; i++) { + const block1 = await mineBlock(tip1, cb1); cb1 = block1.txs[0]; - block2 = await mineBlock(tip2, cb2); + const block2 = await mineBlock(tip2, cb2); cb2 = block2.txs[0]; await chain.add(block1); await chain.add(block2); - assert(chain.tip.hash === block1.hash('hex')); + assert.strictEqual(chain.tip.hash, block1.hash('hex')); tip1 = await chain.db.getEntry(block1.hash('hex')); tip2 = await chain.db.getEntry(block2.hash('hex')); @@ -93,42 +123,38 @@ describe('Node', function() { assert(tip1); assert(tip2); - assert(!(await tip2.isMainChain())); + assert(!await tip2.isMainChain()); await co.wait(); } }); it('should have correct chain value', () => { - assert.equal(chain.db.state.value, 55000000000); - assert.equal(chain.db.state.coin, 20); - assert.equal(chain.db.state.tx, 21); + assert.strictEqual(chain.db.state.value, 55000000000); + assert.strictEqual(chain.db.state.coin, 20); + assert.strictEqual(chain.db.state.tx, 21); }); it('should have correct balance', async () => { - let balance; - await co.timeout(100); - balance = await wallet.getBalance(); - assert.equal(balance.unconfirmed, 550 * 1e8); - assert.equal(balance.confirmed, 550 * 1e8); + const balance = await wallet.getBalance(); + assert.strictEqual(balance.unconfirmed, 550 * 1e8); + assert.strictEqual(balance.confirmed, 550 * 1e8); }); it('should handle a reorg', async () => { - let entry, block, forked; + assert.strictEqual(wdb.state.height, chain.height); + assert.strictEqual(chain.height, 11); - assert.equal(walletdb.state.height, chain.height); - assert.equal(chain.height, 11); - - entry = await chain.db.getEntry(tip2.hash); + const entry = await chain.db.getEntry(tip2.hash); assert(entry); - assert(chain.height === entry.height); + assert.strictEqual(chain.height, entry.height); - block = await miner.mineBlock(entry); + const block = await miner.mineBlock(entry); assert(block); - forked = false; + let forked = false; chain.once('reorganize', () => { forked = true; }); @@ -136,50 +162,47 @@ describe('Node', function() { await chain.add(block); assert(forked); - assert(chain.tip.hash === block.hash('hex')); + assert.strictEqual(chain.tip.hash, block.hash('hex')); assert(chain.tip.chainwork.cmp(tip1.chainwork) > 0); }); it('should have correct chain value', () => { - assert.equal(chain.db.state.value, 60000000000); - assert.equal(chain.db.state.coin, 21); - assert.equal(chain.db.state.tx, 22); + assert.strictEqual(chain.db.state.value, 60000000000); + assert.strictEqual(chain.db.state.coin, 21); + assert.strictEqual(chain.db.state.tx, 22); }); it('should have correct balance', async () => { - let balance; - await co.timeout(100); - balance = await wallet.getBalance(); - assert.equal(balance.unconfirmed, 1100 * 1e8); - assert.equal(balance.confirmed, 600 * 1e8); + const balance = await wallet.getBalance(); + assert.strictEqual(balance.unconfirmed, 1100 * 1e8); + assert.strictEqual(balance.confirmed, 600 * 1e8); }); it('should check main chain', async () => { - let result = await tip1.isMainChain(); + const result = await tip1.isMainChain(); assert(!result); }); it('should mine a block after a reorg', async () => { - let block = await mineBlock(null, cb2); - let entry, result; + const block = await mineBlock(null, cb2); await chain.add(block); - entry = await chain.db.getEntry(block.hash('hex')); + const entry = await chain.db.getEntry(block.hash('hex')); assert(entry); - assert(chain.tip.hash === entry.hash); + assert.strictEqual(chain.tip.hash, entry.hash); - result = await entry.isMainChain(); + const result = await entry.isMainChain(); assert(result); }); it('should prevent double spend on new chain', async () => { - let block = await mineBlock(null, cb2); - let tip = chain.tip; - let err; + const block = await mineBlock(null, cb2); + const tip = chain.tip; + let err; try { await chain.add(block); } catch (e) { @@ -187,15 +210,15 @@ describe('Node', function() { } assert(err); - assert.equal(err.reason, 'bad-txns-inputs-missingorspent'); - assert(chain.tip === tip); + assert.strictEqual(err.reason, 'bad-txns-inputs-missingorspent'); + assert.strictEqual(chain.tip, tip); }); - it('should fail to mine a block with coins on an alternate chain', async () => { - let block = await mineBlock(null, cb1); - let tip = chain.tip; - let err; + it('should fail to mine block with coins on an alternate chain', async () => { + const block = await mineBlock(null, cb1); + const tip = chain.tip; + let err; try { await chain.add(block); } catch (e) { @@ -203,197 +226,170 @@ describe('Node', function() { } assert(err); - assert.equal(err.reason, 'bad-txns-inputs-missingorspent'); - assert(chain.tip === tip); + assert.strictEqual(err.reason, 'bad-txns-inputs-missingorspent'); + assert.strictEqual(chain.tip, tip); }); it('should have correct chain value', () => { - assert.equal(chain.db.state.value, 65000000000); - assert.equal(chain.db.state.coin, 23); - assert.equal(chain.db.state.tx, 24); + assert.strictEqual(chain.db.state.value, 65000000000); + assert.strictEqual(chain.db.state.coin, 23); + assert.strictEqual(chain.db.state.tx, 24); }); it('should get coin', async () => { - let block, tx, output, coin; + const block1 = await mineBlock(); + await chain.add(block1); - block = await mineBlock(); - await chain.add(block); - - block = await mineBlock(null, block.txs[0]); - await chain.add(block); + const block2 = await mineBlock(null, block1.txs[0]); + await chain.add(block2); - tx = block.txs[1]; - output = Coin.fromTX(tx, 1, chain.height); + const tx = block2.txs[1]; + const output = Coin.fromTX(tx, 1, chain.height); - coin = await chain.db.getCoin(tx.hash('hex'), 1); + const coin = await chain.db.getCoin(tx.hash('hex'), 1); - assert.deepEqual(coin.toRaw(), output.toRaw()); + assert.bufferEqual(coin.toRaw(), output.toRaw()); }); it('should get balance', async () => { - let balance, txs; - await co.timeout(100); - balance = await wallet.getBalance(); - assert.equal(balance.unconfirmed, 1250 * 1e8); - assert.equal(balance.confirmed, 750 * 1e8); + const balance = await wallet.getBalance(); + assert.strictEqual(balance.unconfirmed, 1250 * 1e8); + assert.strictEqual(balance.confirmed, 750 * 1e8); assert(wallet.account.receiveDepth >= 7); assert(wallet.account.changeDepth >= 6); - assert.equal(walletdb.state.height, chain.height); + assert.strictEqual(wdb.state.height, chain.height); - txs = await wallet.getHistory(); - assert.equal(txs.length, 45); + const txs = await wallet.getHistory(); + assert.strictEqual(txs.length, 45); }); it('should get tips and remove chains', async () => { - let tips = await chain.db.getTips(); + { + const tips = await chain.db.getTips(); - assert.notEqual(tips.indexOf(chain.tip.hash), -1); - assert.equal(tips.length, 2); + assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + assert.strictEqual(tips.length, 2); + } await chain.db.removeChains(); - tips = await chain.db.getTips(); + { + const tips = await chain.db.getTips(); - assert.notEqual(tips.indexOf(chain.tip.hash), -1); - assert.equal(tips.length, 1); + assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + assert.strictEqual(tips.length, 1); + } }); it('should rescan for transactions', async () => { let total = 0; - await chain.db.scan(0, walletdb.filter, (block, txs) => { + await chain.db.scan(0, wdb.filter, async (block, txs) => { total += txs.length; - return Promise.resolve(); }); - assert.equal(total, 26); + assert.strictEqual(total, 26); }); it('should activate csv', async () => { - let deployments = chain.network.deployments; - let i, block, prev, state, cache; + const deployments = chain.network.deployments; - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert(state === 0); + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 0); - for (i = 0; i < 417; i++) { - block = await miner.mineBlock(); + for (let i = 0; i < 417; i++) { + const block = await miner.mineBlock(); await chain.add(block); switch (chain.height) { - case 144: - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert(state === 1); + case 144: { + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 1); break; - case 288: - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert(state === 2); + } + case 288: { + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 2); break; - case 432: - prev = await chain.tip.getPrevious(); - state = await chain.getState(prev, deployments.csv); - assert(state === 3); + } + case 432: { + const prev = await chain.tip.getPrevious(); + const state = await chain.getState(prev, deployments.csv); + assert.strictEqual(state, 3); break; + } } } - assert(chain.height === 432); + assert.strictEqual(chain.height, 432); assert(chain.state.hasCSV()); - cache = await chain.db.getStateCache(); - assert.deepEqual(cache, chain.db.stateCache); - assert.equal(chain.db.stateCache.updates.length, 0); + const cache = await chain.db.getStateCache(); + assert.deepStrictEqual(cache, chain.db.stateCache); + assert.strictEqual(chain.db.stateCache.updates.length, 0); assert(await chain.db.verifyDeployments()); }); - async function mineCSV(tx) { - let job = await miner.createJob(); - let redeemer; - - redeemer = new MTX(); - - redeemer.addOutput({ - script: [ - Script.array(new BN(1)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY - ], - value: 10 * 1e8 - }); - - redeemer.addTX(tx, 0); - - redeemer.setLocktime(chain.height); - - await wallet.sign(redeemer); - - job.addTX(redeemer.toTX(), redeemer.view); - job.refresh(); - - return await job.mineAsync(); - } - it('should test csv', async () => { - let tx = (await chain.db.getBlock(chain.height)).txs[0]; - let block = await mineCSV(tx); - let csv, job, redeemer; + const tx = (await chain.db.getBlock(chain.height)).txs[0]; + const csvBlock = await mineCSV(tx); - await chain.add(block); + await chain.add(csvBlock); - csv = block.txs[1]; + const csv = csvBlock.txs[1]; - redeemer = new MTX(); + const spend = new MTX(); - redeemer.addOutput({ + spend.addOutput({ script: [ - Script.array(new BN(2)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY + Opcode.fromInt(2), + Opcode.fromSymbol('checksequenceverify') ], value: 10 * 1e8 }); - redeemer.addTX(csv, 0); - redeemer.setSequence(0, 1, false); + spend.addTX(csv, 0); + spend.setSequence(0, 1, false); - job = await miner.createJob(); + const job = await miner.createJob(); - job.addTX(redeemer.toTX(), redeemer.view); + job.addTX(spend.toTX(), spend.view); job.refresh(); - block = await job.mineAsync(); + const block = await job.mineAsync(); await chain.add(block); }); it('should fail csv with bad sequence', async () => { - let csv = (await chain.db.getBlock(chain.height)).txs[1]; - let block, job, redeemer, err; + const csv = (await chain.db.getBlock(chain.height)).txs[1]; + const spend = new MTX(); - redeemer = new MTX(); - - redeemer.addOutput({ + spend.addOutput({ script: [ - Script.array(new BN(1)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY + Opcode.fromInt(1), + Opcode.fromSymbol('checksequenceverify') ], value: 10 * 1e8 }); - redeemer.addTX(csv, 0); - redeemer.setSequence(0, 1, false); + spend.addTX(csv, 0); + spend.setSequence(0, 1, false); - job = await miner.createJob(); + const job = await miner.createJob(); - job.addTX(redeemer.toTX(), redeemer.view); + job.addTX(spend.toTX(), spend.view); job.refresh(); - block = await job.mineAsync(); + const block = await job.mineAsync(); + let err; try { await chain.add(block); } catch (e) { @@ -405,40 +401,40 @@ describe('Node', function() { }); it('should mine a block', async () => { - let block = await miner.mineBlock(); + const block = await miner.mineBlock(); assert(block); await chain.add(block); }); it('should fail csv lock checks', async () => { - let tx = (await chain.db.getBlock(chain.height)).txs[0]; - let block = await mineCSV(tx); - let csv, job, redeemer, err; + const tx = (await chain.db.getBlock(chain.height)).txs[0]; + const csvBlock = await mineCSV(tx); - await chain.add(block); + await chain.add(csvBlock); - csv = block.txs[1]; + const csv = csvBlock.txs[1]; - redeemer = new MTX(); + const spend = new MTX(); - redeemer.addOutput({ + spend.addOutput({ script: [ - Script.array(new BN(2)), - Script.opcodes.OP_CHECKSEQUENCEVERIFY + Opcode.fromInt(2), + Opcode.fromSymbol('checksequenceverify') ], value: 10 * 1e8 }); - redeemer.addTX(csv, 0); - redeemer.setSequence(0, 2, false); + spend.addTX(csv, 0); + spend.setSequence(0, 2, false); - job = await miner.createJob(); + const job = await miner.createJob(); - job.addTX(redeemer.toTX(), redeemer.view); + job.addTX(spend.toTX(), spend.view); job.refresh(); - block = await job.mineAsync(); + const block = await job.mineAsync(); + let err; try { await chain.add(block); } catch (e) { @@ -446,12 +442,12 @@ describe('Node', function() { } assert(err); - assert.equal(err.reason, 'bad-txns-nonfinal'); + assert.strictEqual(err.reason, 'bad-txns-nonfinal'); }); it('should rescan for transactions', async () => { - await walletdb.rescan(0); - assert.equal(wallet.txdb.state.confirmed, 1289250000000); + await wdb.rescan(0); + assert.strictEqual(wallet.txdb.state.confirmed, 1289250000000); }); it('should reset miner mempool', async () => { @@ -459,17 +455,15 @@ describe('Node', function() { }); it('should not get a block template', async () => { - let json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'getblocktemplate' }, {}); assert(json.error); - assert.equal(json.error.code, -8); + assert.strictEqual(json.error.code, -8); }); it('should get a block template', async () => { - let json; - - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'getblocktemplate', params: [ {rules: ['segwit']} @@ -477,22 +471,24 @@ describe('Node', function() { id: '1' }, {}); - assert(typeof json.result.curtime === 'number'); - assert(typeof json.result.mintime === 'number'); - assert(typeof json.result.maxtime === 'number'); - assert(typeof json.result.expires === 'number'); + assert.typeOf(json.result, 'object'); + assert.typeOf(json.result.curtime, 'number'); + assert.typeOf(json.result.mintime, 'number'); + assert.typeOf(json.result.maxtime, 'number'); + assert.typeOf(json.result.expires, 'number'); assert.deepStrictEqual(json, { result: { - capabilities: [ 'proposal' ], - mutable: [ 'time', 'transactions', 'prevblock' ], + capabilities: ['proposal'], + mutable: ['time', 'transactions', 'prevblock'], version: 536870912, - rules: [ 'csv', '!segwit', 'testdummy' ], + rules: ['csv', '!segwit', 'testdummy'], vbavailable: {}, vbrequired: 0, height: 437, previousblockhash: node.chain.tip.rhash(), - target: '7fffff0000000000000000000000000000000000000000000000000000000000', + target: + '7fffff0000000000000000000000000000000000000000000000000000000000', bits: '207fffff', noncerange: '00000000ffffffff', curtime: json.result.curtime, @@ -507,7 +503,9 @@ describe('Node', function() { coinbaseaux: { flags: '6d696e65642062792062636f696e' }, coinbasevalue: 1250000000, coinbasetxn: undefined, - default_witness_commitment: '6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9', + default_witness_commitment: + '6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962' + + 'b48bebd836974e8cf9', transactions: [] }, error: null, @@ -516,16 +514,15 @@ describe('Node', function() { }); it('should send a block template proposal', async () => { - let attempt = await node.miner.createBlock(); - let block, hex, json; + const attempt = await node.miner.createBlock(); attempt.refresh(); - block = attempt.toBlock(); + const block = attempt.toBlock(); - hex = block.toRaw().toString('hex'); + const hex = block.toRaw().toString('hex'); - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'getblocktemplate', params: [{ mode: 'proposal', @@ -534,31 +531,29 @@ describe('Node', function() { }, {}); assert(!json.error); - assert(json.result === null); + assert.strictEqual(json.result, null); }); it('should submit a block', async () => { - let block = await node.miner.mineBlock(); - let hex = block.toRaw().toString('hex'); - let json; + const block = await node.miner.mineBlock(); + const hex = block.toRaw().toString('hex'); - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'submitblock', params: [hex] }, {}); assert(!json.error); - assert(json.result === null); - assert.equal(node.chain.tip.hash, block.hash('hex')); + assert.strictEqual(json.result, null); + assert.strictEqual(node.chain.tip.hash, block.hash('hex')); }); it('should validate an address', async () => { - let addr = new Address(); - let json; + const addr = new Address(); addr.network = node.network; - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'validateaddress', params: [addr.toString()] }, {}); @@ -573,9 +568,7 @@ describe('Node', function() { }); it('should add transaction to mempool', async () => { - let mtx, tx, missing; - - mtx = await wallet.createTX({ + const mtx = await wallet.createTX({ rate: 100000, outputs: [{ value: 100000, @@ -587,21 +580,20 @@ describe('Node', function() { assert(mtx.isSigned()); - tx1 = mtx; - tx = mtx.toTX(); + const tx = mtx.toTX(); await wallet.db.addTX(tx); - missing = await node.mempool.addTX(tx); - assert(!missing || missing.length === 0); + const missing = await node.mempool.addTX(tx); + assert(!missing); - assert.equal(node.mempool.map.size, 1); + assert.strictEqual(node.mempool.map.size, 1); + + tx1 = mtx; }); it('should add lesser transaction to mempool', async () => { - let mtx, tx, missing; - - mtx = await wallet.createTX({ + const mtx = await wallet.createTX({ rate: 1000, outputs: [{ value: 50000, @@ -613,25 +605,22 @@ describe('Node', function() { assert(mtx.isSigned()); - tx2 = mtx; - tx = mtx.toTX(); + const tx = mtx.toTX(); await wallet.db.addTX(tx); - missing = await node.mempool.addTX(tx); - assert(!missing || missing.length === 0); + const missing = await node.mempool.addTX(tx); + assert(!missing); - assert.equal(node.mempool.map.size, 2); + assert.strictEqual(node.mempool.map.size, 2); + + tx2 = mtx; }); it('should get a block template', async () => { - let fees = 0; - let weight = 0; - let i, item, json, result; - node.rpc.refreshBlock(); - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'getblocktemplate', params: [ {rules: ['segwit']} @@ -642,57 +631,54 @@ describe('Node', function() { assert(!json.error); assert(json.result); - result = json.result; + const result = json.result; + + let fees = 0; + let weight = 0; - for (i = 0; i < result.transactions.length; i++) { - item = result.transactions[i]; + for (const item of result.transactions) { fees += item.fee; weight += item.weight; } - assert.equal(result.transactions.length, 2); - assert.equal(fees, tx1.getFee() + tx2.getFee()); - assert.equal(weight, tx1.getWeight() + tx2.getWeight()); - assert.equal(result.transactions[0].hash, tx1.txid()); - assert.equal(result.transactions[1].hash, tx2.txid()); - assert.equal(result.coinbasevalue, 125e7 + fees); + assert.strictEqual(result.transactions.length, 2); + assert.strictEqual(fees, tx1.getFee() + tx2.getFee()); + assert.strictEqual(weight, tx1.getWeight() + tx2.getWeight()); + assert.strictEqual(result.transactions[0].hash, tx1.txid()); + assert.strictEqual(result.transactions[1].hash, tx2.txid()); + assert.strictEqual(result.coinbasevalue, 125e7 + fees); }); it('should get raw transaction', async () => { - let json, tx; - - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'getrawtransaction', params: [tx2.txid()], id: '1' }, {}); assert(!json.error); - tx = TX.fromRaw(json.result, 'hex'); - assert.equal(tx.txid(), tx2.txid()); + const tx = TX.fromRaw(json.result, 'hex'); + assert.strictEqual(tx.txid(), tx2.txid()); }); it('should prioritise transaction', async () => { - let json; - - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'prioritisetransaction', params: [tx2.txid(), 0, 10000000], id: '1' }, {}); assert(!json.error); - assert(json.result === true); + assert.strictEqual(json.result, true); }); it('should get a block template', async () => { let fees = 0; let weight = 0; - let i, item, json, result; node.rpc.refreshBlock(); - json = await node.rpc.call({ + const json = await node.rpc.call({ method: 'getblocktemplate', params: [ {rules: ['segwit']} @@ -703,20 +689,19 @@ describe('Node', function() { assert(!json.error); assert(json.result); - result = json.result; + const result = json.result; - for (i = 0; i < result.transactions.length; i++) { - item = result.transactions[i]; + for (const item of result.transactions) { fees += item.fee; weight += item.weight; } - assert.equal(result.transactions.length, 2); - assert.equal(fees, tx1.getFee() + tx2.getFee()); - assert.equal(weight, tx1.getWeight() + tx2.getWeight()); - assert.equal(result.transactions[0].hash, tx2.txid()); - assert.equal(result.transactions[1].hash, tx1.txid()); - assert.equal(result.coinbasevalue, 125e7 + fees); + assert.strictEqual(result.transactions.length, 2); + assert.strictEqual(fees, tx1.getFee() + tx2.getFee()); + assert.strictEqual(weight, tx1.getWeight() + tx2.getWeight()); + assert.strictEqual(result.transactions[0].hash, tx2.txid()); + assert.strictEqual(result.transactions[1].hash, tx1.txid()); + assert.strictEqual(result.coinbasevalue, 125e7 + fees); }); it('should cleanup', async () => { diff --git a/test/protocol-test.js b/test/protocol-test.js index b40f38fcb..4f4082111 100644 --- a/test/protocol-test.js +++ b/test/protocol-test.js @@ -1,6 +1,10 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ +/* eslint indent: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const Network = require('../lib/protocol/network'); const util = require('../lib/utils/util'); const NetAddress = require('../lib/primitives/netaddress'); @@ -8,34 +12,43 @@ const TX = require('../lib/primitives/tx'); const Framer = require('../lib/net/framer'); const Parser = require('../lib/net/parser'); const packets = require('../lib/net/packets'); +const common = require('./util/common'); const network = Network.get('main'); +const tx8 = common.readTX('tx8'); +const tx9 = common.readTX('tx9'); + describe('Protocol', function() { - let pkg = require('../lib/pkg'); - let agent = `/bcoin:${pkg.version}/`; - let parser, framer, v1, v2, hosts; + const pkg = require('../lib/pkg'); + const agent = `/bcoin:${pkg.version}/`; + let parser, framer; beforeEach(() => { parser = new Parser(); framer = new Framer(); }); - function packetTest(command, payload, test) { - it(`should encode/decode ${command}`, (cb) => { - let ver = Buffer.from(framer.packet(command, payload.toRaw())); + function packetTest(cmd, payload, test) { + it(`should encode/decode ${cmd}`, (cb) => { parser.once('packet', (packet) => { - assert.equal(packet.cmd, command); - test(packet); + try { + assert.strictEqual(packet.cmd, cmd); + test(packet); + } catch (e) { + cb(e); + return; + } cb(); }); - parser.feed(ver); + const raw = framer.packet(cmd, payload.toRaw()); + parser.feed(raw); }); } - v1 = packets.VersionPacket.fromOptions({ + const v1 = packets.VersionPacket.fromOptions({ version: 300, services: 1, - ts: network.now(), + time: network.now(), remote: new NetAddress(), local: new NetAddress(), nonce: util.nonce(), @@ -45,16 +58,16 @@ describe('Protocol', function() { }); packetTest('version', v1, (payload) => { - assert.equal(payload.version, 300); - assert.equal(payload.agent, agent); - assert.equal(payload.height, 0); - assert.equal(payload.noRelay, false); + assert.strictEqual(payload.version, 300); + assert.strictEqual(payload.agent, agent); + assert.strictEqual(payload.height, 0); + assert.strictEqual(payload.noRelay, false); }); - v2 = packets.VersionPacket.fromOptions({ + const v2 = packets.VersionPacket.fromOptions({ version: 300, services: 1, - ts: network.now(), + time: network.now(), remote: new NetAddress(), local: new NetAddress(), nonce: util.nonce(), @@ -64,147 +77,53 @@ describe('Protocol', function() { }); packetTest('version', v2, (payload) => { - assert.equal(payload.version, 300); - assert.equal(payload.agent, agent); - assert.equal(payload.height, 10); - assert.equal(payload.noRelay, true); + assert.strictEqual(payload.version, 300); + assert.strictEqual(payload.agent, agent); + assert.strictEqual(payload.height, 10); + assert.strictEqual(payload.noRelay, true); }); packetTest('verack', new packets.VerackPacket(), (payload) => { }); - /* eslint indent: 0 */ - hosts = [ + const hosts = [ new NetAddress({ services: 1, host: '127.0.0.1', port: 8333, - ts: util.now() + time: util.now() }), new NetAddress({ services: 1, host: '::123:456:789a', port: 18333, - ts: util.now() + time: util.now() }) ]; packetTest('addr', new packets.AddrPacket(hosts), (payload) => { - assert.equal(typeof payload.items.length, 'number'); - assert.equal(payload.items.length, 2); - - assert.equal(typeof payload.items[0].ts, 'number'); - assert.equal(payload.items[0].services, 1); - assert.equal(payload.items[0].host, hosts[0].host); - assert.equal(payload.items[0].port, hosts[0].port); - - assert.equal(typeof payload.items[1].ts, 'number'); - assert.equal(payload.items[1].services, 1); - assert.equal(payload.items[1].host, hosts[1].host); - assert.equal(payload.items[1].port, hosts[1].port); + assert.typeOf(payload.items, 'array'); + assert.strictEqual(payload.items.length, 2); + + assert.typeOf(payload.items[0].time, 'number'); + assert.strictEqual(payload.items[0].services, 1); + assert.strictEqual(payload.items[0].host, hosts[0].host); + assert.strictEqual(payload.items[0].port, hosts[0].port); + + assert.typeOf(payload.items[1].time, 'number'); + assert.strictEqual(payload.items[1].services, 1); + assert.strictEqual(payload.items[1].host, hosts[1].host); + assert.strictEqual(payload.items[1].port, hosts[1].port); }); - it('should include the raw data of only one transaction in a ' + - 'parsed transaction', () => { - let tx, rawTwoTxs, rawFirstTx; - - rawTwoTxs = Buffer.from( - '0100000004b124cca7e9686375380c845d0fd002ed704aef4472f4cc193' + - 'fca4aa1b3404da400000000b400493046022100d3c9ba786488323c975f' + - 'e61593df6a8041c5442736f361887abfe5c97175c72b022100ca61688f4' + - '72f4c01ede05ffc50426d68db375f72937b5f39d67835b191b6402f014c' + - '67514104c4bee5e6dbb5c1651437cb4386c1515c7776c64535077204c6f' + - '24f05a37d04a32bc78beb2193b53b104c9954c44b0ce168bc78efd5f1e1' + - 'c7db9d6c21b301659921027f10c31cb2ad7e0388cf5187924f1294082ba' + - '5d4c697bbca7fd83a6af61db7d552aeffffffffb124cca7e9686375380c' + - '845d0fd002ed704aef4472f4cc193fca4aa1b3404da401000000fd15010' + - '0483045022100a35b7fc1973a0a8962c240a7336b501e149ef167491081' + - 'e8df91dc761f4e96c2022004ee4d20983a1d0fb96e9bedf86de03b66d7b' + - 'c50595295b1fb3b5fd2740df3c9014cc9514104c4bee5e6dbb5c1651437' + - 'cb4386c1515c7776c64535077204c6f24f05a37d04a32bc78beb2193b53' + - 'b104c9954c44b0ce168bc78efd5f1e1c7db9d6c21b3016599410495b62d' + - '1e76a915e5ed3694298c5017d2818d22acbf2a8bd9fa4cf635184e15247' + - 'dc7e1a48beb82c1fdddc3b84ac58cec12c8f8b9ca83341ac90299c697fc' + - '94cb4104e3394f3eea40b7abe32f4ad376a80f5a213287d1361b5580e3f' + - 'e70d13a5db0666e2593283b6b5abc01d98cfff5679d8c36b7caefa1c4df' + - '81b10bc45c3812de5f53aeffffffffb124cca7e9686375380c845d0fd00' + - '2ed704aef4472f4cc193fca4aa1b3404da402000000fd5e010047304402' + - '20606d6187e0ade69192f4a447794cdabb8ea9a4e70df09aa8bc689242c' + - '7ffeded02204165ec8edfc9de19d8a94e5f487c8a030187ae16a11e575a' + - '955f532a81b631ad01493046022100f7764763d17757ffdeda3d66cfaa6' + - 'ad3b8f759ddc95e8f73858dba872762658a0221009e903d526595ff9d6d' + - '53835889d816de4c47d78371d7a13223f47602b34bc71e014cc9524104c' + - '4bee5e6dbb5c1651437cb4386c1515c7776c64535077204c6f24f05a37d' + - '04a32bc78beb2193b53b104c9954c44b0ce168bc78efd5f1e1c7db9d6c2' + - '1b3016599410495b62d1e76a915e5ed3694298c5017d2818d22acbf2a8b' + - 'd9fa4cf635184e15247dc7e1a48beb82c1fdddc3b84ac58cec12c8f8b9c' + - 'a83341ac90299c697fc94cb4104e3394f3eea40b7abe32f4ad376a80f5a' + - '213287d1361b5580e3fe70d13a5db0666e2593283b6b5abc01d98cfff56' + - '79d8c36b7caefa1c4df81b10bc45c3812de5f53aeffffffffb124cca7e9' + - '686375380c845d0fd002ed704aef4472f4cc193fca4aa1b3404da404000' + - '0008a473044022075c0666d413fc85cca94ea2f24adc0fedb61a3ba0fcf' + - 'b240c1a4fd2587b03bf90220525ad4d92c6bf635f8b97c188ebf491c6e3' + - '42b767a5432f318cbb0245a7f64be014104c4bee5e6dbb5c1651437cb43' + - '86c1515c7776c64535077204c6f24f05a37d04a32bc78beb2193b53b104' + - 'c9954c44b0ce168bc78efd5f1e1c7db9d6c21b3016599ffffffff01a029' + - 'de5c0500000017a9141d9ca71efa36d814424ea6ca1437e67287aebe348' + - '70000000001000000019457e669dc6b344c0090d10eb22a0377022898d4' + - '607fbdf1e3cef2a323c13fa900000000b2004730440220440d67386a27d' + - '6776e102b82ce2d583e23d51f8ac3bb94749bd10c03ce71410e022041b4' + - '6c5d46b14ef72af9d96fb814fa894077d534a4de1215363ee68fb8d4f50' + - '1014c67514104c4bee5e6dbb5c1651437cb4386c1515c7776c645350772' + - '04c6f24f05a37d04a32bc78beb2193b53b104c9954c44b0ce168bc78efd' + - '5f1e1c7db9d6c21b301659921027f10c31cb2ad7e0388cf5187924f1294' + - '082ba5d4c697bbca7fd83a6af61db7d552aeffffffff0250c3000000000' + - '0001976a9146167aeaeec59836b22447b8af2c5e61fb4f1b7b088ac00a3' + - 'dc5c0500000017a9149eb21980dc9d413d8eac27314938b9da920ee53e8' + - '700000000', 'hex'); - - rawFirstTx = Buffer.from( - '0100000004b124cca7e9686375380c845d0fd002ed704aef4472f4cc193' + - 'fca4aa1b3404da400000000b400493046022100d3c9ba786488323c975f' + - 'e61593df6a8041c5442736f361887abfe5c97175c72b022100ca61688f4' + - '72f4c01ede05ffc50426d68db375f72937b5f39d67835b191b6402f014c' + - '67514104c4bee5e6dbb5c1651437cb4386c1515c7776c64535077204c6f' + - '24f05a37d04a32bc78beb2193b53b104c9954c44b0ce168bc78efd5f1e1' + - 'c7db9d6c21b301659921027f10c31cb2ad7e0388cf5187924f1294082ba' + - '5d4c697bbca7fd83a6af61db7d552aeffffffffb124cca7e9686375380c' + - '845d0fd002ed704aef4472f4cc193fca4aa1b3404da401000000fd15010' + - '0483045022100a35b7fc1973a0a8962c240a7336b501e149ef167491081' + - 'e8df91dc761f4e96c2022004ee4d20983a1d0fb96e9bedf86de03b66d7b' + - 'c50595295b1fb3b5fd2740df3c9014cc9514104c4bee5e6dbb5c1651437' + - 'cb4386c1515c7776c64535077204c6f24f05a37d04a32bc78beb2193b53' + - 'b104c9954c44b0ce168bc78efd5f1e1c7db9d6c21b3016599410495b62d' + - '1e76a915e5ed3694298c5017d2818d22acbf2a8bd9fa4cf635184e15247' + - 'dc7e1a48beb82c1fdddc3b84ac58cec12c8f8b9ca83341ac90299c697fc' + - '94cb4104e3394f3eea40b7abe32f4ad376a80f5a213287d1361b5580e3f' + - 'e70d13a5db0666e2593283b6b5abc01d98cfff5679d8c36b7caefa1c4df' + - '81b10bc45c3812de5f53aeffffffffb124cca7e9686375380c845d0fd00' + - '2ed704aef4472f4cc193fca4aa1b3404da402000000fd5e010047304402' + - '20606d6187e0ade69192f4a447794cdabb8ea9a4e70df09aa8bc689242c' + - '7ffeded02204165ec8edfc9de19d8a94e5f487c8a030187ae16a11e575a' + - '955f532a81b631ad01493046022100f7764763d17757ffdeda3d66cfaa6' + - 'ad3b8f759ddc95e8f73858dba872762658a0221009e903d526595ff9d6d' + - '53835889d816de4c47d78371d7a13223f47602b34bc71e014cc9524104c' + - '4bee5e6dbb5c1651437cb4386c1515c7776c64535077204c6f24f05a37d' + - '04a32bc78beb2193b53b104c9954c44b0ce168bc78efd5f1e1c7db9d6c2' + - '1b3016599410495b62d1e76a915e5ed3694298c5017d2818d22acbf2a8b' + - 'd9fa4cf635184e15247dc7e1a48beb82c1fdddc3b84ac58cec12c8f8b9c' + - 'a83341ac90299c697fc94cb4104e3394f3eea40b7abe32f4ad376a80f5a' + - '213287d1361b5580e3fe70d13a5db0666e2593283b6b5abc01d98cfff56' + - '79d8c36b7caefa1c4df81b10bc45c3812de5f53aeffffffffb124cca7e9' + - '686375380c845d0fd002ed704aef4472f4cc193fca4aa1b3404da404000' + - '0008a473044022075c0666d413fc85cca94ea2f24adc0fedb61a3ba0fcf' + - 'b240c1a4fd2587b03bf90220525ad4d92c6bf635f8b97c188ebf491c6e3' + - '42b767a5432f318cbb0245a7f64be014104c4bee5e6dbb5c1651437cb43' + - '86c1515c7776c64535077204c6f24f05a37d04a32bc78beb2193b53b104' + - 'c9954c44b0ce168bc78efd5f1e1c7db9d6c21b3016599ffffffff01a029' + - 'de5c0500000017a9141d9ca71efa36d814424ea6ca1437e67287aebe348' + - '700000000', 'hex'); - - tx = TX.fromRaw(rawTwoTxs); - tx._raw = null; - - assert.deepEqual(tx.toRaw(), rawFirstTx); + it('should include the raw data of only one transaction', () => { + const [tx1] = tx8.getTX(); + const [tx2] = tx9.getTX(); + const raw = Buffer.concat([tx1.toRaw(), tx2.toRaw()]); + + const tx = TX.fromRaw(raw); + tx.refresh(); + + assert.bufferEqual(tx.toRaw(), tx1.toRaw()); }); }); diff --git a/test/schnorr-test.js b/test/schnorr-test.js new file mode 100644 index 000000000..0934fd564 --- /dev/null +++ b/test/schnorr-test.js @@ -0,0 +1,20 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + +'use strict'; + +const assert = require('./util/assert'); +const secp256k1 = require('../lib/crypto/secp256k1'); +const digest = require('../lib/crypto/digest'); +const schnorr = require('../lib/crypto/schnorr'); + +describe('Schnorr', function() { + it('should do proper schnorr', () => { + const key = secp256k1.generatePrivateKey(); + const pub = secp256k1.publicKeyCreate(key, true); + const msg = digest.hash256(Buffer.from('foo', 'ascii')); + const sig = schnorr.sign(msg, key); + assert.strictEqual(schnorr.verify(msg, sig, pub), true); + assert.bufferEqual(schnorr.recover(sig, msg), pub); + }); +}); diff --git a/test/script-test.js b/test/script-test.js index 825eca92f..a50ff9b42 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -1,293 +1,311 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const Script = require('../lib/script/script'); const Witness = require('../lib/script/witness'); const Stack = require('../lib/script/stack'); +const Opcode = require('../lib/script/opcode'); const TX = require('../lib/primitives/tx'); +const util = require('../lib/utils/util'); const encoding = require('../lib/utils/encoding'); -const opcodes = Script.opcodes; - -const scripts = require('./data/script_tests'); -function success(res, stack) { - if (!res) - return false; +const scripts = require('./data/script-tests.json'); +function isSuccess(stack) { if (stack.length === 0) return false; - if (!Script.bool(stack.top(-1))) + if (!stack.getBool(-1)) return false; return true; } -describe('Script', function() { - it('should encode/decode script', () => { - let src, decoded, dst; - - src = '20' - + '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f' - + '20' - + '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f' - + 'ac'; - - decoded = Script.fromRaw(src, 'hex'); - assert.equal(decoded.code.length, 3); - assert.equal(decoded.code[0].data.toString('hex'), - '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'); - assert.equal(decoded.code[1].data.toString('hex'), - '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'); - assert.equal(decoded.code[2].value, opcodes.OP_CHECKSIG); - - dst = decoded.toRaw(); - assert.equal(dst.toString('hex'), src); - }); - - it('should encode/decode numbers', () => { - let script = [0, 0x51, 0x52, 0x60]; - let encoded = Script.fromArray(script).raw; - let decoded = Script(encoded).toArray(); - assert.deepEqual(decoded, script); - }); +function parseScriptTest(data) { + const witArr = Array.isArray(data[0]) ? data.shift() : []; + const inpHex = data[0]; + const outHex = data[1]; + const names = data[2] || 'NONE'; + const expected = data[3]; + let comments = data[4]; + + if (!comments) + comments = outHex.slice(0, 60); + + comments += ` (${expected})`; + + let value = 0; + if (witArr.length > 0) + value = util.fromFloat(witArr.pop(), 8); + + const witness = Witness.fromString(witArr); + const input = Script.fromString(inpHex); + const output = Script.fromString(outHex); + + let flags = 0; + for (const name of names.split(',')) { + const flag = Script.flags[`VERIFY_${name}`]; + + if (flag == null) + throw new Error(`Unknown flag: ${name}.`); + + flags |= flag; + } + + return { + witness: witness, + input: input, + output: output, + value: value, + flags: flags, + expected: expected, + comments: comments + }; +} +describe('Script', function() { it('should recognize a P2SH output', () => { - let hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87'; - let decoded = Script.fromRaw(hex, 'hex'); + const hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87'; + const decoded = Script.fromRaw(hex, 'hex'); assert(decoded.isScripthash()); }); it('should recognize a Null Data output', () => { - let hex = '6a28590c080112220a1b353930632e6f7267282a5f' + const hex = '6a28590c080112220a1b353930632e6f7267282a5f' + '5e294f7665726c6179404f7261636c65103b1a010c'; - let decoded = Script.fromRaw(hex, 'hex'); + const decoded = Script.fromRaw(hex, 'hex'); assert(decoded.isNulldata()); }); it('should handle if statements correctly', () => { - let input, output, stack, res; - - input = new Script([opcodes.OP_1, opcodes.OP_2]); - - output = new Script([ - opcodes.OP_2, - opcodes.OP_EQUAL, - opcodes.OP_IF, - opcodes.OP_3, - opcodes.OP_ELSE, - opcodes.OP_4, - opcodes.OP_ENDIF, - opcodes.OP_5 - ]); + { + const input = new Script([ + Opcode.fromInt(1), + Opcode.fromInt(2) + ]); + + const output = new Script([ + Opcode.fromInt(2), + Opcode.fromSymbol('equal'), + Opcode.fromSymbol('if'), + Opcode.fromInt(3), + Opcode.fromSymbol('else'), + Opcode.fromInt(4), + Opcode.fromSymbol('endif'), + Opcode.fromInt(5) + ]); + + const stack = new Stack(); + + input.execute(stack); + output.execute(stack); + + assert.deepEqual(stack.items, [[1], [3], [5]]); + } - stack = new Stack(); + { + const input = new Script([ + Opcode.fromInt(1), + Opcode.fromInt(2) + ]); + + const output = new Script([ + Opcode.fromInt(9), + Opcode.fromSymbol('equal'), + Opcode.fromSymbol('if'), + Opcode.fromInt(3), + Opcode.fromSymbol('else'), + Opcode.fromInt(4), + Opcode.fromSymbol('endif'), + Opcode.fromInt(5) + ]); + + const stack = new Stack(); + + input.execute(stack); + output.execute(stack); + + assert.deepEqual(stack.items, [[1], [4], [5]]); + } - input.execute(stack); + { + const input = new Script([ + Opcode.fromInt(1), + Opcode.fromInt(2) + ]); - res = output.execute(stack); - assert(res); - - assert.deepEqual(stack.items, [[1], [3], [5]]); - - input = new Script([opcodes.OP_1, opcodes.OP_2]); - output = new Script([ - opcodes.OP_9, - opcodes.OP_EQUAL, - opcodes.OP_IF, - opcodes.OP_3, - opcodes.OP_ELSE, - opcodes.OP_4, - opcodes.OP_ENDIF, - opcodes.OP_5 - ]); + const output = new Script([ + Opcode.fromInt(2), + Opcode.fromSymbol('equal'), + Opcode.fromSymbol('if'), + Opcode.fromInt(3), + Opcode.fromSymbol('endif'), + Opcode.fromInt(5) + ]); - stack = new Stack(); - input.execute(stack); + const stack = new Stack(); - res = output.execute(stack); - assert(res); - assert.deepEqual(stack.items, [[1], [4], [5]]); - - input = new Script([opcodes.OP_1, opcodes.OP_2]); - output = new Script([ - opcodes.OP_2, - opcodes.OP_EQUAL, - opcodes.OP_IF, - opcodes.OP_3, - opcodes.OP_ENDIF, - opcodes.OP_5 - ]); + input.execute(stack); + output.execute(stack); - stack = new Stack(); + assert.deepEqual(stack.items, [[1], [3], [5]]); + } - input.execute(stack); + { + const input = new Script([ + Opcode.fromInt(1), + Opcode.fromInt(2) + ]); - res = output.execute(stack); - assert(res); - assert.deepEqual(stack.items, [[1], [3], [5]]); - - input = new Script([opcodes.OP_1, opcodes.OP_2]); - output = new Script([ - opcodes.OP_9, - opcodes.OP_EQUAL, - opcodes.OP_IF, - opcodes.OP_3, - opcodes.OP_ENDIF, - opcodes.OP_5 - ]); + const output = new Script([ + Opcode.fromInt(9), + Opcode.fromSymbol('equal'), + Opcode.fromSymbol('if'), + Opcode.fromInt(3), + Opcode.fromSymbol('endif'), + Opcode.fromInt(5) + ]); - stack = new Stack(); - input.execute(stack); + const stack = new Stack(); - res = output.execute(stack); - assert(res); - assert.deepEqual(stack.items, [[1], [5]]); - - input = new Script([opcodes.OP_1, opcodes.OP_2]); - output = new Script([ - opcodes.OP_9, - opcodes.OP_EQUAL, - opcodes.OP_NOTIF, - opcodes.OP_3, - opcodes.OP_ENDIF, - opcodes.OP_5 - ]); - stack = new Stack(); - input.execute(stack); + input.execute(stack); + output.execute(stack); + + assert.deepEqual(stack.items, [[1], [5]]); + } + + { + const input = new Script([ + Opcode.fromInt(1), + Opcode.fromInt(2) + ]); + + const output = new Script([ + Opcode.fromInt(9), + Opcode.fromSymbol('equal'), + Opcode.fromSymbol('notif'), + Opcode.fromInt(3), + Opcode.fromSymbol('endif'), + Opcode.fromInt(5) + ]); - res = output.execute(stack); - assert(res); - assert.deepEqual(stack.items, [[1], [3], [5]]); + const stack = new Stack(); + + input.execute(stack); + output.execute(stack); + + assert.deepEqual(stack.items, [[1], [3], [5]]); + } }); it('should handle CScriptNums correctly', () => { - let input, output, stack; - - input = new Script([ - Buffer.from('ffffff7f', 'hex'), - opcodes.OP_NEGATE, - opcodes.OP_DUP, - opcodes.OP_ADD + const input = new Script([ + Opcode.fromString('ffffff7f', 'hex'), + Opcode.fromSymbol('negate'), + Opcode.fromSymbol('dup'), + Opcode.fromSymbol('add') ]); - output = new Script([ - Buffer.from('feffffff80', 'hex'), - opcodes.OP_EQUAL + const output = new Script([ + Opcode.fromString('feffffff80', 'hex'), + Opcode.fromSymbol('equal') ]); - stack = new Stack(); + const stack = new Stack(); + + input.execute(stack); + output.execute(stack); - assert(input.execute(stack)); - assert(success(output.execute(stack), stack)); + assert(isSuccess(stack)); }); it('should handle CScriptNums correctly', () => { - let input, output, stack; - - input = new Script([ - opcodes.OP_11, - opcodes.OP_10, - opcodes.OP_1, - opcodes.OP_ADD + const input = new Script([ + Opcode.fromInt(11), + Opcode.fromInt(10), + Opcode.fromInt(1), + Opcode.fromSymbol('add') ]); - output = new Script([ - opcodes.OP_NUMNOTEQUAL, - opcodes.OP_NOT + const output = new Script([ + Opcode.fromSymbol('numnotequal'), + Opcode.fromSymbol('not') ]); - stack = new Stack(); + const stack = new Stack(); + + input.execute(stack); + output.execute(stack); - assert(input.execute(stack)); - assert(success(output.execute(stack), stack)); + assert(isSuccess(stack)); }); it('should handle OP_ROLL correctly', () => { - let input, output, stack; - - input = new Script([ - Buffer.from([0x16]), - Buffer.from([0x15]), - Buffer.from([0x14]) + const input = new Script([ + Opcode.fromInt(0x16), + Opcode.fromInt(0x15), + Opcode.fromInt(0x14) ]); - output = new Script([ - opcodes.OP_0, - opcodes.OP_ROLL, - Buffer.from([0x14]), - opcodes.OP_EQUALVERIFY, - opcodes.OP_DEPTH, - opcodes.OP_2, - opcodes.OP_EQUAL + const output = new Script([ + Opcode.fromInt(0), + Opcode.fromSymbol('roll'), + Opcode.fromInt(0x14), + Opcode.fromSymbol('equalverify'), + Opcode.fromSymbol('depth'), + Opcode.fromInt(2), + Opcode.fromSymbol('equal') ]); - stack = new Stack(); + const stack = new Stack(); - assert(input.execute(stack)); - assert(success(output.execute(stack), stack)); - }); + input.execute(stack); + output.execute(stack); - scripts.forEach((data) => { - let witness = Array.isArray(data[0]) ? data.shift() : []; - let input = data[0] ? data[0].trim() : data[0] || ''; - let output = data[1] ? data[1].trim() : data[1] || ''; - let names = data[2] ? data[2].trim().split(/,\s*/) : []; - let expected = data[3] || ''; - let comments = Array.isArray(data[4]) ? data[4].join('. ') : data[4] || ''; - let amount = 0; - let flags = 0; + assert(isSuccess(stack)); + }); + for (const data of scripts) { if (data.length === 1) - return; - - if (!comments) - comments = output.slice(0, 60); - - comments += ` (${expected})`; + continue; - if (witness.length !== 0) - amount = witness.pop() * 100000000; + const test = parseScriptTest(data); + const {witness, input, output} = test; + const {value, flags} = test; + const {expected, comments} = test; - witness = Witness.fromString(witness); - input = Script.fromString(input); - output = Script.fromString(output); + for (const noCache of [false, true]) { + const suffix = noCache ? 'without cache' : 'with cache'; - for (let name of names) { - name = `VERIFY_${name}`; - assert(Script.flags[name] != null, 'Unknown flag.'); - flags |= Script.flags[name]; - } - - [false, true].forEach((noCache) => { - let suffix = noCache ? 'without cache' : 'with cache'; it(`should handle script test ${suffix}:${comments}`, () => { - let prev, tx, err, res; - // Funding transaction. - prev = new TX({ + const prev = new TX({ version: 1, - flag: 1, inputs: [{ prevout: { hash: encoding.NULL_HASH, index: 0xffffffff }, - script: [opcodes.OP_0, opcodes.OP_0], + script: [ + Opcode.fromInt(0), + Opcode.fromInt(0) + ], witness: [], sequence: 0xffffffff }], outputs: [{ script: output, - value: amount + value: value }], locktime: 0 }); // Spending transaction. - tx = new TX({ + const tx = new TX({ version: 1, - flag: 1, inputs: [{ prevout: { hash: prev.hash('hex'), @@ -299,7 +317,7 @@ describe('Script', function() { }], outputs: [{ script: [], - value: amount + value: value }], locktime: 0 }); @@ -309,22 +327,21 @@ describe('Script', function() { tx.refresh(); } + let err; try { - res = Script.verify(input, witness, output, tx, 0, amount, flags); + Script.verify(input, witness, output, tx, 0, value, flags); } catch (e) { err = e; } if (expected !== 'OK') { - assert(!res); - assert(err); - assert.equal(err.code, expected); + assert.typeOf(err, 'error'); + assert.strictEqual(err.code, expected); return; } assert.ifError(err); - assert(res); }); - }); - }); + } + } }); diff --git a/test/scrypt-test.js b/test/scrypt-test.js index 51ba3ff8a..93f13e1f3 100644 --- a/test/scrypt-test.js +++ b/test/scrypt-test.js @@ -1,34 +1,39 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const scrypt = require('../lib/crypto/scrypt'); describe('Scrypt', function() { + this.timeout(20000); + it('should perform scrypt with N=16', () => { - let pass = Buffer.from(''); - let salt = Buffer.from(''); - let result = scrypt.derive(pass, salt, 16, 1, 1, 64); - assert.equal(result.toString('hex'), '' + const pass = Buffer.from(''); + const salt = Buffer.from(''); + const result = scrypt.derive(pass, salt, 16, 1, 1, 64); + assert.strictEqual(result.toString('hex'), '' + '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3f' + 'ede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628' + 'cf35e20c38d18906'); }); it('should perform scrypt with N=1024', () => { - let pass = Buffer.from('password'); - let salt = Buffer.from('NaCl'); - let result = scrypt.derive(pass, salt, 1024, 8, 16, 64); - assert.equal(result.toString('hex'), '' + const pass = Buffer.from('password'); + const salt = Buffer.from('NaCl'); + const result = scrypt.derive(pass, salt, 1024, 8, 16, 64); + assert.strictEqual(result.toString('hex'), '' + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773' + '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9' + '4a83ee6d8360cbdfa2cc0640'); }); it('should perform scrypt with N=16384', () => { - let pass = Buffer.from('pleaseletmein'); - let salt = Buffer.from('SodiumChloride'); - let result = scrypt.derive(pass, salt, 16384, 8, 1, 64); - assert.equal(result.toString('hex'), '' + const pass = Buffer.from('pleaseletmein'); + const salt = Buffer.from('SodiumChloride'); + const result = scrypt.derive(pass, salt, 16384, 8, 1, 64); + assert.strictEqual(result.toString('hex'), '' + '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b54' + '3f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d' + '651e40dfcf017b45575887'); @@ -39,7 +44,48 @@ describe('Scrypt', function() { // let pass = Buffer.from('pleaseletmein'); // let salt = Buffer.from('SodiumChloride'); // let result = scrypt.derive(pass, salt, 1048576, 8, 1, 64); - // assert.equal(result.toString('hex'), '' + // assert.strictEqual(result.toString('hex'), '' + // + '2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5' + // + 'ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049' + // + 'e8a952fbcbf45c6fa77a41a4'); + // }); + + it('should perform scrypt with N=16 (async)', async () => { + const pass = Buffer.from(''); + const salt = Buffer.from(''); + const result = await scrypt.deriveAsync(pass, salt, 16, 1, 1, 64); + assert.strictEqual(result.toString('hex'), '' + + '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3f' + + 'ede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628' + + 'cf35e20c38d18906'); + }); + + it('should perform scrypt with N=1024 (async)', async () => { + const pass = Buffer.from('password'); + const salt = Buffer.from('NaCl'); + const result = await scrypt.deriveAsync(pass, salt, 1024, 8, 16, 64); + assert.strictEqual(result.toString('hex'), '' + + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773' + + '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9' + + '4a83ee6d8360cbdfa2cc0640'); + }); + + it('should perform scrypt with N=16384 (async)', async () => { + const pass = Buffer.from('pleaseletmein'); + const salt = Buffer.from('SodiumChloride'); + const result = await scrypt.deriveAsync(pass, salt, 16384, 8, 1, 64); + assert.strictEqual(result.toString('hex'), '' + + '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b54' + + '3f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d' + + '651e40dfcf017b45575887'); + }); + + // Only enable if you want to wait a while. + // it('should perform scrypt with N=1048576 (async)', async () => { + // let pass = Buffer.from('pleaseletmein'); + // let salt = Buffer.from('SodiumChloride'); + // let result = await scrypt.deriveAsync(pass, salt, 1048576, 8, 1, 64); + // assert.strictEqual(result.toString('hex'), '' // + '2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5' // + 'ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049' // + 'e8a952fbcbf45c6fa77a41a4'); diff --git a/test/siphash-test.js b/test/siphash-test.js index 5ed0ec3ea..76aa89323 100644 --- a/test/siphash-test.js +++ b/test/siphash-test.js @@ -1,27 +1,30 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const siphash = require('../lib/crypto/siphash'); const siphash256 = siphash.siphash256; describe('SipHash', function() { it('should perform siphash with no data', () => { - let data = Buffer.alloc(0); - let key = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); - assert.deepEqual(siphash256(data, key), [1919933255, -586281423]); + const data = Buffer.alloc(0); + const key = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); + assert.deepStrictEqual(siphash256(data, key), [1919933255, -586281423]); }); it('should perform siphash with data', () => { - let data = Buffer.from('0001020304050607', 'hex'); - let key = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); - assert.deepEqual(siphash256(data, key), [-1812597383, -1701632926]); + const data = Buffer.from('0001020304050607', 'hex'); + const key = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); + assert.deepStrictEqual(siphash256(data, key), [-1812597383, -1701632926]); }); it('should perform siphash with uint256', () => { - let data = Buffer.from( + const data = Buffer.from( '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex'); - let key = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); - assert.deepEqual(siphash256(data, key), [1898402095, 1928494286]); + const key = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); + assert.deepStrictEqual(siphash256(data, key), [1898402095, 1928494286]); }); }); diff --git a/test/tx-test.js b/test/tx-test.js index ef0dda2e0..5de5b4657 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -1,82 +1,89 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const util = require('../lib/utils/util'); const encoding = require('../lib/utils/encoding'); const random = require('../lib/crypto/random'); const consensus = require('../lib/protocol/consensus'); const TX = require('../lib/primitives/tx'); -const Coin = require('../lib/primitives/coin'); const Output = require('../lib/primitives/output'); +const Outpoint = require('../lib/primitives/outpoint'); const Script = require('../lib/script/script'); const Witness = require('../lib/script/witness'); +const Opcode = require('../lib/script/opcode'); const Input = require('../lib/primitives/input'); const CoinView = require('../lib/coins/coinview'); const KeyRing = require('../lib/primitives/keyring'); -const parseTX = require('./util/common').parseTX; -const opcodes = Script.opcodes; - -const valid = require('./data/tx_valid.json'); -const invalid = require('./data/tx_invalid.json'); -const sighash = require('./data/sighash.json'); -const tx1 = parseTX('data/tx1.hex'); -const tx2 = parseTX('data/tx2.hex'); -const tx3 = parseTX('data/tx3.hex'); -const tx4 = parseTX('data/tx4.hex'); -const wtx = parseTX('data/wtx.hex'); -const coolest = parseTX('data/coolest-tx-ever-sent.hex'); +const common = require('./util/common'); + +const validTests = require('./data/tx-valid.json'); +const invalidTests = require('./data/tx-invalid.json'); +const sighashTests = require('./data/sighash-tests.json'); + +const tx1 = common.readTX('tx1'); +const tx2 = common.readTX('tx2'); +const tx3 = common.readTX('tx3'); +const tx4 = common.readTX('tx4'); +const tx5 = common.readTX('tx5'); +const tx6 = common.readTX('tx6'); +const tx7 = common.readTX('tx7'); const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; const MAX_SAFE_ADDITION = 0xfffffffffffff; function clearCache(tx, noCache) { - if (!noCache) { - assert.equal(tx.hash('hex'), tx.clone().hash('hex')); + if (noCache) { + tx.refresh(); return; } - tx.refresh(); + + const copy = tx.clone(); + + assert.bufferEqual(tx.hash(), copy.hash()); + assert.bufferEqual(tx.witnessHash(), copy.witnessHash()); } -function parseTest(data) { - let [coins, tx, names] = data; - let view = new CoinView(); +function parseTXTest(data) { + const coins = data[0]; + const hex = data[1]; + const names = data[2] || 'NONE'; + let flags = 0; - let coin; - if (!names) - names = ''; + for (const name of names.split(',')) { + const flag = Script.flags[`VERIFY_${name}`]; - tx = TX.fromRaw(tx, 'hex'); - names = names.trim().split(/,\s*/); + if (flag == null) + throw new Error(`Unknown flag: ${name}.`); - for (let name of names) { - name = `VERIFY_${name}`; - assert(Script.flags[name] != null, 'Unknown flag.'); - flags |= Script.flags[name]; + flags |= flag; } - for (let [hash, index, script, value] of coins) { - hash = util.revHex(hash); - script = Script.fromString(script); - value = parseInt(value || '0', 10); + const view = new CoinView(); - if (index === -1) + for (const [txid, index, str, amount] of coins) { + const hash = util.revHex(txid); + const script = Script.fromString(str); + const value = parseInt(amount || '0', 10); + + // Ignore the coinbase tests. + // They should all fail. + if ((index >>> 0) === 0xffffffff) continue; - coin = new Coin({ - version: 1, - height: -1, - coinbase: false, - hash: hash, - index: index, - script: script, - value: value - }); + const prevout = new Outpoint(hash, index); + const output = new Output({script, value}); - view.addCoin(coin); + view.addOutput(prevout, output); } - coin = view.getOutput(tx.inputs[0]); + const raw = Buffer.from(hex, 'hex'); + const tx = TX.fromRaw(raw); + + const coin = view.getOutputFor(tx.inputs[0]); return { tx: tx, @@ -89,35 +96,93 @@ function parseTest(data) { }; } +function parseSighashTest(data) { + const [txHex, scriptHex, index, type, hash] = data; + + const tx = TX.fromRaw(txHex, 'hex'); + const script = Script.fromRaw(scriptHex, 'hex'); + + const expected = util.revHex(hash); + + let hex = type & 3; + + if (type & 0x80) + hex |= 0x80; + + hex = hex.toString(16); + + if (hex.length % 2 !== 0) + hex = '0' + hex; + + return { + tx: tx, + script: script, + index: index, + type: type, + hash: hash, + expected: expected, + hex: hex + }; +} + +function createInput(value, view) { + const hash = random.randomBytes(32).toString('hex'); + + const input = { + prevout: { + hash: hash, + index: 0 + } + }; + + const output = new Output(); + output.value = value; + + if (!view) + view = new CoinView(); + + view.addOutput(new Outpoint(hash, 0), output); + + return [input, view]; +}; + function sigopContext(scriptSig, witness, scriptPubkey) { - let view = new CoinView(); - let input, output, fund, spend; - - input = new Input(); - output = new Output(); - output.value = 1; - output.script = scriptPubkey; - - fund = new TX(); - fund.version = 1; - fund.inputs.push(input); - fund.outputs.push(output); - fund.refresh(); - - input = new Input(); - input.prevout.hash = fund.hash('hex'); - input.prevout.index = 0; - input.script = scriptSig; - input.witness = witness; - - output = new Output(); - output.value = 1; - - spend = new TX(); - spend.version = 1; - spend.inputs.push(input); - spend.outputs.push(output); - spend.refresh(); + const fund = new TX(); + + { + fund.version = 1; + + const input = new Input(); + fund.inputs.push(input); + + const output = new Output(); + output.value = 1; + output.script = scriptPubkey; + fund.outputs.push(output); + + fund.refresh(); + } + + const spend = new TX(); + + { + spend.version = 1; + + const input = new Input(); + input.prevout.hash = fund.hash('hex'); + input.prevout.index = 0; + input.script = scriptSig; + input.witness = witness; + spend.inputs.push(input); + + const output = new Output(); + output.value = 1; + spend.outputs.push(output); + + spend.refresh(); + } + + const view = new CoinView(); view.addTX(fund, 0); @@ -129,155 +194,97 @@ function sigopContext(scriptSig, witness, scriptPubkey) { } describe('TX', function() { - let raw = '010000000125393c67cd4f581456dd0805fa8e9db3abdf90dbe1d4b53e28' + - '6490f35d22b6f2010000006b483045022100f4fa5ced20d2dbd2f905809d' + - '79ebe34e03496ef2a48a04d0a9a1db436a211dd202203243d086398feb4a' + - 'c21b3b79884079036cd5f3707ba153b383eabefa656512dd0121022ebabe' + - 'fede28804b331608d8ef11e1d65b5a920720db8a644f046d156b3a73c0ff' + - 'ffffff0254150000000000001976a9140740345f114e1a1f37ac1cc442b4' + - '32b91628237e88ace7d27b00000000001976a91495ad422bb5911c2c9fe6' + - 'ce4f82a13c85f03d9b2e88ac00000000'; - let inp = '01000000052fa236559f51f343f0905ea627a955f421a198541d928798b8' + - '186980273942ec010000006b483045022100ae27626778eba264d56883f5' + - 'edc1a49897bf209e98f21c870a55d13bec916e1802204b66f4e3235143d1' + - '1aef327d9454754cd1f28807c3bf9996c107900df9d19ea60121022ebabe' + - 'fede28804b331608d8ef11e1d65b5a920720db8a644f046d156b3a73c0ff' + - 'ffffffe2136f72e4a25e300137b98b402cda91db5c6db6373ba81c722ae1' + - 'a85315b591000000006b483045022100f84293ea9bfb6d150f3a72d8b5ce' + - 'b294a77b31442bf9d4ab2058f046a9b65a9f022075935dc0a6a628df26eb' + - 'b7215634fd33b65f4da105665595028837680b87ea360121039708df1967' + - '09c5041dc9a26457a0cfa303076329f389687bdc9709d5862fd664ffffff' + - 'fff6e67655a42a2f955ec8610940c983042516c32298e57684b3c29fcade' + - '7e637a000000006a47304402203bbfb53c3011d742f3f942db18a44d8c3d' + - 'd111990ee7cc42959383dd7a3e8e8d02207f0f5ed3e165d9db81ac69d36c' + - '60a1a4a482f22cb0048dafefa5e704e84dd18e0121039708df196709c504' + - '1dc9a26457a0cfa303076329f389687bdc9709d5862fd664ffffffff9a02' + - 'e72123a149570c11696d3c798593785e95b8a3c3fc49ae1d07d809d94d5a' + - '000000006b483045022100ad0e6f5f73221aa4eda9ad82c7074882298bcf' + - '668f34ae81126df0213b2961850220020ba23622d75fb8f95199063b804f' + - '62ba103545af4e16b5be0b6dc0cb51aac60121039708df196709c5041dc9' + - 'a26457a0cfa303076329f389687bdc9709d5862fd664ffffffffd7db5a38' + - '72589ca8aa3cd5ebb0f22dbb3956f8d691e15dc010fe1093c045c3de0000' + - '00006b48304502210082b91a67da1f02dcb0d00e63b67f10af8ba9639b16' + - '5f9ff974862a9d4900e27c022069e4a58f591eb3fc7d7d0b176d64d59e90' + - 'aef0c601b3c84382abad92f6973e630121039708df196709c5041dc9a264' + - '57a0cfa303076329f389687bdc9709d5862fd664ffffffff025415000000' + - '0000001976a9140740345f114e1a1f37ac1cc442b432b91628237e88ac4b' + - '0f7c00000000001976a91495ad422bb5911c2c9fe6ce4f82a13c85f03d9b' + - '2e88ac00000000'; - - [false, true].forEach((noCache) => { - let suffix = noCache ? 'without cache' : 'with cache'; - - it(`should decode/encode with parser/framer ${suffix}`, () => { - let tx = TX.fromRaw(raw, 'hex'); - clearCache(tx, noCache); - assert.equal(tx.toRaw().toString('hex'), raw); - }); - - it(`should be verifiable ${suffix}`, () => { - let tx = TX.fromRaw(raw, 'hex'); - let p = TX.fromRaw(inp, 'hex'); - let view = new CoinView(); - view.addTX(p, -1); - - clearCache(tx, noCache); - clearCache(p, noCache); - - assert(tx.verify(view)); - }); + for (const noCache of [false, true]) { + const suffix = noCache ? 'without cache' : 'with cache'; it(`should verify non-minimal output ${suffix}`, () => { - clearCache(tx1.tx, noCache); - assert(tx1.tx.verify(tx1.view, Script.flags.VERIFY_P2SH)); + const [tx, view] = tx1.getTX(); + clearCache(tx, noCache); + assert(tx.verify(view, Script.flags.VERIFY_P2SH)); }); it(`should verify tx.version == 0 ${suffix}`, () => { - clearCache(tx2.tx, noCache); - assert(tx2.tx.verify(tx2.view, Script.flags.VERIFY_P2SH)); + const [tx, view] = tx2.getTX(); + clearCache(tx, noCache); + assert(tx.verify(view, Script.flags.VERIFY_P2SH)); }); it(`should verify sighash_single bug w/ findanddelete ${suffix}`, () => { - clearCache(tx3.tx, noCache); - assert(tx3.tx.verify(tx3.view, Script.flags.VERIFY_P2SH)); + const [tx, view] = tx3.getTX(); + clearCache(tx, noCache); + assert(tx.verify(view, Script.flags.VERIFY_P2SH)); }); it(`should verify high S value with only DERSIG enabled ${suffix}`, () => { - let coin = tx4.view.getOutput(tx4.tx.inputs[0]); - let flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; - clearCache(tx4.tx, noCache); - assert(tx4.tx.verifyInput(0, coin, flags)); - }); - - it(`should verify the coolest tx ever sent ${suffix}`, () => { - clearCache(coolest.tx, noCache); - assert(coolest.tx.verify(coolest.view, Script.flags.VERIFY_NONE)); + const [tx, view] = tx4.getTX(); + const coin = view.getOutputFor(tx.inputs[0]); + const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; + clearCache(tx, noCache); + assert(tx.verifyInput(0, coin, flags)); }); it(`should parse witness tx properly ${suffix}`, () => { - let raw1, raw2, wtx2; - - clearCache(wtx.tx, noCache); + const [tx] = tx5.getTX(); + clearCache(tx, noCache); - assert.equal(wtx.tx.inputs.length, 5); - assert.equal(wtx.tx.outputs.length, 1980); - assert(wtx.tx.hasWitness()); - assert.notEqual(wtx.tx.hash('hex'), wtx.tx.witnessHash('hex')); - assert.equal(wtx.tx.witnessHash('hex'), + assert.strictEqual(tx.inputs.length, 5); + assert.strictEqual(tx.outputs.length, 1980); + assert(tx.hasWitness()); + assert.notStrictEqual(tx.txid(), tx.wtxid()); + assert.strictEqual(tx.witnessHash('hex'), '088c919cd8408005f255c411f786928385688a9e8fdb2db4c9bc3578ce8c94cf'); - assert.equal(wtx.tx.getSize(), 62138); - assert.equal(wtx.tx.getVirtualSize(), 61813); - assert.equal(wtx.tx.getWeight(), 247250); + assert.strictEqual(tx.getSize(), 62138); + assert.strictEqual(tx.getVirtualSize(), 61813); + assert.strictEqual(tx.getWeight(), 247250); - raw1 = wtx.tx.toRaw(); - clearCache(wtx.tx, true); + const raw1 = tx.toRaw(); + tx.refresh(); - raw2 = wtx.tx.toRaw(); - assert.deepEqual(raw1, raw2); + const raw2 = tx.toRaw(); + assert.bufferEqual(raw1, raw2); - wtx2 = TX.fromRaw(raw2); - clearCache(wtx2, noCache); + const tx2 = TX.fromRaw(raw2); + clearCache(tx2, noCache); - assert.equal(wtx.tx.hash('hex'), wtx2.hash('hex')); - assert.equal(wtx.tx.witnessHash('hex'), wtx2.witnessHash('hex')); + assert.strictEqual(tx.txid(), tx2.txid()); + assert.strictEqual(tx.wtxid(), tx2.wtxid()); + assert.notStrictEqual(tx.txid(), tx2.wtxid()); }); - [[valid, true], [invalid, false]].forEach((test) => { - let [arr, valid] = test; - let comment = ''; + it(`should verify the coolest tx ever sent ${suffix}`, () => { + const [tx, view] = tx6.getTX(); + clearCache(tx, noCache); + assert(tx.verify(view, Script.flags.VERIFY_NONE)); + }); + + it(`should verify a historical transaction ${suffix}`, () => { + const [tx, view] = tx7.getTX(); + clearCache(tx, noCache); + assert(tx.verify(view)); + }); - arr.forEach((json, i) => { - let data, tx, view, flags, comments; + for (const tests of [validTests, invalidTests]) { + let comment = ''; + for (const json of tests) { if (json.length === 1) { comment += ' ' + json[0]; - return; - } - - data = parseTest(json); - - if (!data) { - comment = ''; - return; + continue; } - tx = data.tx; - view = data.view; - flags = data.flags; - comments = comment.trim(); - - if (!comments) - comments = data.comments; + const data = parseTXTest(json); + const {tx, view, flags} = data; + const comments = comment.trim() || data.comments; comment = ''; - if (valid) { + if (tests === validTests) { if (comments.indexOf('Coinbase') === 0) { - it(`should handle valid coinbase ${suffix}: ${comments}`, () => { + it(`should handle valid tx test ${suffix}: ${comments}`, () => { clearCache(tx, noCache); assert.ok(tx.isSane()); }); - return; + continue; } it(`should handle valid tx test ${suffix}: ${comments}`, () => { clearCache(tx, noCache); @@ -285,85 +292,59 @@ describe('TX', function() { }); } else { if (comments === 'Duplicate inputs') { - it(`should handle duplicate input test ${suffix}: ${comments}`, () => { + it(`should handle invalid tx test ${suffix}: ${comments}`, () => { clearCache(tx, noCache); assert.ok(tx.verify(view, flags)); assert.ok(!tx.isSane()); }); - return; + continue; } if (comments === 'Negative output') { - it(`should handle invalid tx (negative) ${suffix}: ${comments}`, () => { + it(`should handle invalid tx test ${suffix}: ${comments}`, () => { clearCache(tx, noCache); assert.ok(tx.verify(view, flags)); assert.ok(!tx.isSane()); }); - return; + continue; } if (comments.indexOf('Coinbase') === 0) { - it(`should handle invalid coinbase ${suffix}: ${comments}`, () => { + it(`should handle invalid tx test ${suffix}: ${comments}`, () => { clearCache(tx, noCache); assert.ok(!tx.isSane()); }); - return; + continue; } it(`should handle invalid tx test ${suffix}: ${comments}`, () => { clearCache(tx, noCache); assert.ok(!tx.verify(view, flags)); }); } - }); - }); - - sighash.forEach((data) => { - let [tx, script, index, type, hash] = data; - let expected, hex; - - if (data.length === 1) - return; - - tx = TX.fromRaw(tx, 'hex'); - script = Script.fromRaw(script, 'hex'); - expected = util.revHex(hash); - hex = type & 3; - - if (type & 0x80) - hex |= 0x80; + } + } - hex = hex.toString(16); + for (const json of sighashTests) { + if (json.length === 1) + continue; - if (hex.length % 2 !== 0) - hex = '0' + hex; + const test = parseSighashTest(json); + const {tx, script, index, type} = test; + const {hash, hex, expected} = test; clearCache(tx, noCache); it(`should get sighash of ${hash} (${hex}) ${suffix}`, () => { - let subscript = script.getSubscript(0).removeSeparators(); - let hash = tx.signatureHash(index, subscript, 0, type, 0); - assert.equal(hash.toString('hex'), expected); + const subscript = script.getSubscript(0).removeSeparators(); + const hash = tx.signatureHash(index, subscript, 0, type, 0); + assert.strictEqual(hash.toString('hex'), expected); }); - }); - }); - - function createInput(value, view) { - let hash = random.randomBytes(32).toString('hex'); - let output = new Output(); - output.value = value; - view.addOutput(hash, 0, output); - return { - prevout: { - hash: hash, - index: 0 - } - }; + } } it('should fail on >51 bit coin values', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY + 1); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY + 1, view)], + inputs: [input], outputs: [{ script: [], value: consensus.MAX_MONEY @@ -375,11 +356,10 @@ describe('TX', function() { }); it('should handle 51 bit coin values', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY, view)], + inputs: [input], outputs: [{ script: [], value: consensus.MAX_MONEY @@ -391,11 +371,10 @@ describe('TX', function() { }); it('should fail on >51 bit output values', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY, view)], + inputs: [input], outputs: [{ script: [], value: consensus.MAX_MONEY + 1 @@ -407,11 +386,10 @@ describe('TX', function() { }); it('should handle 51 bit output values', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY, view)], + inputs: [input], outputs: [{ script: [], value: consensus.MAX_MONEY @@ -423,11 +401,10 @@ describe('TX', function() { }); it('should fail on >51 bit fees', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY + 1); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY + 1, view)], + inputs: [input], outputs: [{ script: [], value: 0 @@ -439,14 +416,13 @@ describe('TX', function() { }); it('should fail on >51 bit values from multiple', () => { - let view = new CoinView(); - let tx = new TX({ + const view = new CoinView(); + const tx = new TX({ version: 1, - flag: 1, inputs: [ - createInput(Math.floor(consensus.MAX_MONEY / 2), view), - createInput(Math.floor(consensus.MAX_MONEY / 2), view), - createInput(Math.floor(consensus.MAX_MONEY / 2), view) + createInput(Math.floor(consensus.MAX_MONEY / 2), view)[0], + createInput(Math.floor(consensus.MAX_MONEY / 2), view)[0], + createInput(Math.floor(consensus.MAX_MONEY / 2), view)[0] ], outputs: [{ script: [], @@ -459,11 +435,10 @@ describe('TX', function() { }); it('should fail on >51 bit output values from multiple', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY, view)], + inputs: [input], outputs: [ { script: [], @@ -485,14 +460,13 @@ describe('TX', function() { }); it('should fail on >51 bit fees from multiple', () => { - let view = new CoinView(); - let tx = new TX({ + const view = new CoinView(); + const tx = new TX({ version: 1, - flag: 1, inputs: [ - createInput(Math.floor(consensus.MAX_MONEY / 2), view), - createInput(Math.floor(consensus.MAX_MONEY / 2), view), - createInput(Math.floor(consensus.MAX_MONEY / 2), view) + createInput(Math.floor(consensus.MAX_MONEY / 2), view)[0], + createInput(Math.floor(consensus.MAX_MONEY / 2), view)[0], + createInput(Math.floor(consensus.MAX_MONEY / 2), view)[0] ], outputs: [{ script: [], @@ -505,15 +479,11 @@ describe('TX', function() { }); it('should fail to parse >53 bit values', () => { - let view = new CoinView(); - let tx, raw; + const [input] = createInput(Math.floor(consensus.MAX_MONEY / 2)); - tx = new TX({ + const tx = new TX({ version: 1, - flag: 1, - inputs: [ - createInput(Math.floor(consensus.MAX_MONEY / 2), view) - ], + inputs: [input], outputs: [{ script: [], value: 0xdeadbeef @@ -521,31 +491,26 @@ describe('TX', function() { locktime: 0 }); - raw = tx.toRaw(); - assert(encoding.readU64(raw, 47) === 0xdeadbeef); + let raw = tx.toRaw(); + assert.strictEqual(encoding.readU64(raw, 47), 0xdeadbeef); raw[54] = 0x7f; - assert.throws(() => { - TX.fromRaw(raw); - }); + assert.throws(() => TX.fromRaw(raw)); tx.outputs[0].value = 0; tx.refresh(); raw = tx.toRaw(); - assert(encoding.readU64(raw, 47) === 0x00); + assert.strictEqual(encoding.readU64(raw, 47), 0x00); raw[54] = 0x80; - assert.throws(() => { - TX.fromRaw(raw); - }); + assert.throws(() => TX.fromRaw(raw)); }); it('should fail on 53 bit coin values', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(MAX_SAFE_INTEGER); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(MAX_SAFE_INTEGER, view)], + inputs: [input], outputs: [{ script: [], value: consensus.MAX_MONEY @@ -557,11 +522,10 @@ describe('TX', function() { }); it('should fail on 53 bit output values', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY, view)], + inputs: [input], outputs: [{ script: [], value: MAX_SAFE_INTEGER @@ -573,11 +537,10 @@ describe('TX', function() { }); it('should fail on 53 bit fees', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(MAX_SAFE_INTEGER); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(MAX_SAFE_INTEGER, view)], + inputs: [input], outputs: [{ script: [], value: 0 @@ -588,16 +551,15 @@ describe('TX', function() { assert.ok(!tx.verifyInputs(view, 0)); }); - [MAX_SAFE_ADDITION, MAX_SAFE_INTEGER].forEach((MAX) => { + for (const value of [MAX_SAFE_ADDITION, MAX_SAFE_INTEGER]) { it('should fail on >53 bit values from multiple', () => { - let view = new CoinView(); - let tx = new TX({ + const view = new CoinView(); + const tx = new TX({ version: 1, - flag: 1, inputs: [ - createInput(MAX, view), - createInput(MAX, view), - createInput(MAX, view) + createInput(value, view)[0], + createInput(value, view)[0], + createInput(value, view)[0] ], outputs: [{ script: [], @@ -610,23 +572,22 @@ describe('TX', function() { }); it('should fail on >53 bit output values from multiple', () => { - let view = new CoinView(); - let tx = new TX({ + const [input, view] = createInput(consensus.MAX_MONEY); + const tx = new TX({ version: 1, - flag: 1, - inputs: [createInput(consensus.MAX_MONEY, view)], + inputs: [input], outputs: [ { script: [], - value: MAX + value: value }, { script: [], - value: MAX + value: value }, { script: [], - value: MAX + value: value } ], locktime: 0 @@ -636,14 +597,13 @@ describe('TX', function() { }); it('should fail on >53 bit fees from multiple', () => { - let view = new CoinView(); - let tx = new TX({ + const view = new CoinView(); + const tx = new TX({ version: 1, - flag: 1, inputs: [ - createInput(MAX, view), - createInput(MAX, view), - createInput(MAX, view) + createInput(value, view)[0], + createInput(value, view)[0], + createInput(value, view)[0] ], outputs: [{ script: [], @@ -654,158 +614,157 @@ describe('TX', function() { assert.ok(tx.isSane()); assert.ok(!tx.verifyInputs(view, 0)); }); - }); + } it('should count sigops for multisig', () => { - let flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; - let key = KeyRing.generate(); - let pub = key.publicKey; - let ctx, output, input, witness; + const flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; + const key = KeyRing.generate(); + const pub = key.publicKey; - output = Script.fromMultisig(1, 2, [pub, pub]); + const output = Script.fromMultisig(1, 2, [pub, pub]); - input = new Script([ - opcodes.OP_0, - opcodes.OP_0 + const input = new Script([ + Opcode.fromInt(0), + Opcode.fromInt(0) ]); - witness = new Witness(); + const witness = new Witness(); - ctx = sigopContext(input, witness, output); + const ctx = sigopContext(input, witness, output); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 0); - assert.equal(ctx.fund.getSigopsCost(ctx.view, flags), + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 0); + assert.strictEqual(ctx.fund.getSigopsCost(ctx.view, flags), consensus.MAX_MULTISIG_PUBKEYS * consensus.WITNESS_SCALE_FACTOR); }); it('should count sigops for p2sh multisig', () => { - let flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; - let key = KeyRing.generate(); - let pub = key.publicKey; - let ctx, redeem, output, input, witness; + const flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; + const key = KeyRing.generate(); + const pub = key.publicKey; - redeem = Script.fromMultisig(1, 2, [pub, pub]); - output = Script.fromScripthash(redeem.hash160()); + const redeem = Script.fromMultisig(1, 2, [pub, pub]); + const output = Script.fromScripthash(redeem.hash160()); - input = new Script([ - opcodes.OP_0, - opcodes.OP_0, - redeem.toRaw() + const input = new Script([ + Opcode.fromInt(0), + Opcode.fromInt(0), + Opcode.fromData(redeem.toRaw()) ]); - witness = new Witness(); + const witness = new Witness(); - ctx = sigopContext(input, witness, output); + const ctx = sigopContext(input, witness, output); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 2 * consensus.WITNESS_SCALE_FACTOR); }); it('should count sigops for p2wpkh', () => { - let flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; - let key = KeyRing.generate(); - let ctx, output, input, witness; - - output = Script.fromProgram(0, key.getKeyHash()); + const flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; + const key = KeyRing.generate(); - input = new Script(); - - witness = new Witness([ + const witness = new Witness([ Buffer.from([0]), Buffer.from([0]) ]); - ctx = sigopContext(input, witness, output); + const input = new Script(); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 1); - assert.equal( - ctx.spend.getSigopsCost(ctx.view, flags & ~Script.flags.VERIFY_WITNESS), - 0); + { + const output = Script.fromProgram(0, key.getKeyHash()); + const ctx = sigopContext(input, witness, output); - output = Script.fromProgram(1, key.getKeyHash()); - ctx = sigopContext(input, witness, output); + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 1); + assert.strictEqual( + ctx.spend.getSigopsCost(ctx.view, flags & ~Script.flags.VERIFY_WITNESS), + 0); + } - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 0); + { + const output = Script.fromProgram(1, key.getKeyHash()); + const ctx = sigopContext(input, witness, output); - output = Script.fromProgram(0, key.getKeyHash()); - ctx = sigopContext(input, witness, output); + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 0); + } - ctx.spend.inputs[0].prevout.hash = encoding.NULL_HASH; - ctx.spend.inputs[0].prevout.index = 0xffffffff; - ctx.spend.refresh(); + { + const output = Script.fromProgram(0, key.getKeyHash()); + const ctx = sigopContext(input, witness, output); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 0); + ctx.spend.inputs[0].prevout.hash = encoding.NULL_HASH; + ctx.spend.inputs[0].prevout.index = 0xffffffff; + ctx.spend.refresh(); + + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 0); + } }); it('should count sigops for nested p2wpkh', () => { - let flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; - let key = KeyRing.generate(); - let ctx, redeem, output, input, witness; + const flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; + const key = KeyRing.generate(); - redeem = Script.fromProgram(0, key.getKeyHash()); - output = Script.fromScripthash(redeem.hash160()); + const redeem = Script.fromProgram(0, key.getKeyHash()); + const output = Script.fromScripthash(redeem.hash160()); - input = new Script([ - redeem.toRaw() + const input = new Script([ + Opcode.fromData(redeem.toRaw()) ]); - witness = new Witness([ + const witness = new Witness([ Buffer.from([0]), Buffer.from([0]) ]); - ctx = sigopContext(input, witness, output); + const ctx = sigopContext(input, witness, output); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 1); + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 1); }); it('should count sigops for p2wsh', () => { - let flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; - let key = KeyRing.generate(); - let pub = key.publicKey; - let ctx, redeem, output, input, witness; + const flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; + const key = KeyRing.generate(); + const pub = key.publicKey; - redeem = Script.fromMultisig(1, 2, [pub, pub]); - output = Script.fromProgram(0, redeem.sha256()); + const redeem = Script.fromMultisig(1, 2, [pub, pub]); + const output = Script.fromProgram(0, redeem.sha256()); - input = new Script(); + const input = new Script(); - witness = new Witness([ + const witness = new Witness([ Buffer.from([0]), Buffer.from([0]), redeem.toRaw() ]); - ctx = sigopContext(input, witness, output); + const ctx = sigopContext(input, witness, output); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 2); - assert.equal( + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 2); + assert.strictEqual( ctx.spend.getSigopsCost(ctx.view, flags & ~Script.flags.VERIFY_WITNESS), 0); }); it('should count sigops for nested p2wsh', () => { - let flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; - let key = KeyRing.generate(); - let pub = key.publicKey; - let ctx, wscript, redeem, output, input, witness; + const flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH; + const key = KeyRing.generate(); + const pub = key.publicKey; - wscript = Script.fromMultisig(1, 2, [pub, pub]); - redeem = Script.fromProgram(0, wscript.sha256()); - output = Script.fromScripthash(redeem.hash160()); + const wscript = Script.fromMultisig(1, 2, [pub, pub]); + const redeem = Script.fromProgram(0, wscript.sha256()); + const output = Script.fromScripthash(redeem.hash160()); - input = new Script([ - redeem.toRaw() + const input = new Script([ + Opcode.fromData(redeem.toRaw()) ]); - witness = new Witness([ + const witness = new Witness([ Buffer.from([0]), Buffer.from([0]), wscript.toRaw() ]); - ctx = sigopContext(input, witness, output); + const ctx = sigopContext(input, witness, output); - assert.equal(ctx.spend.getSigopsCost(ctx.view, flags), 2); + assert.strictEqual(ctx.spend.getSigopsCost(ctx.view, flags), 2); }); }); diff --git a/test/util/assert.js b/test/util/assert.js new file mode 100644 index 000000000..c3a9e56b6 --- /dev/null +++ b/test/util/assert.js @@ -0,0 +1,215 @@ +'use strict'; + +const _assert = require('assert'); +const util = require('util'); + +const assert = function assert(value, message) { + if (!value) { + throw new assert.AssertionError({ + message, + actual: value, + expected: true, + operator: '==', + stackStartFunction: assert + }); + } +}; + +Object.setPrototypeOf(assert, _assert); + +assert.typeOf = function typeOf(value, expected, message) { + _isString(expected, '`expected` must be a string.', typeOf); + + const actual = _typeOf(value); + + if (actual !== expected) { + throw new assert.AssertionError({ + message, + actual, + expected, + operator: 'typeof ==', + stackStartFunction: typeOf + }); + } +}; + +assert.notTypeOf = function notTypeOf(value, expected, message) { + _isString(expected, '`expected` must be a string.', notTypeOf); + + const actual = _typeOf(value); + + if (actual === expected) { + throw new assert.AssertionError({ + message, + actual, + expected, + operator: 'typeof !=', + stackStartFunction: notTypeOf + }); + } +}; + +assert.instanceOf = function instanceOf(object, parent, message) { + _isFunction(parent, '`parent` must be a constructor.', instanceOf); + + if (!(object instanceof parent)) { + throw new assert.AssertionError({ + message, + actual: _getConstructorName(object), + expected: _getFunctionName(parent), + operator: 'instanceof', + stackStartFunction: instanceOf + }); + } +}; + +assert.notInstanceOf = function notInstanceOf(object, parent, message) { + _isFunction(parent, '`parent` must be a constructor.', notInstanceOf); + + if (object instanceof parent) { + throw new assert.AssertionError({ + message, + actual: _getConstructorName(object), + expected: _getFunctionName(parent), + operator: 'not instanceof', + stackStartFunction: notInstanceOf + }); + } +}; + +assert.bufferEqual = function bufferEqual(actual, expected, message) { + _isBuffer(actual, '`actual` must be a buffer.', bufferEqual); + _isBuffer(expected, '`expected` must be a buffer.', bufferEqual); + + if (actual !== expected && !actual.equals(expected)) { + throw new assert.AssertionError({ + message, + actual: actual.toString('hex'), + expected: expected.toString('hex'), + operator: '===', + stackStartFunction: bufferEqual + }); + } +}; + +assert.notBufferEqual = function notBufferEqual(actual, expected, message) { + _isBuffer(actual, '`actual` must be a buffer.', notBufferEqual); + _isBuffer(expected, '`expected` must be a buffer.', notBufferEqual); + + if (actual === expected || actual.equals(expected)) { + throw new assert.AssertionError({ + message, + actual: actual.toString('hex'), + expected: expected.toString('hex'), + operator: '!==', + stackStartFunction: notBufferEqual + }); + } +}; + +function _isString(value, message, stackStartFunction) { + if (typeof value !== 'string') { + throw new assert.AssertionError({ + message, + actual: _typeOf(value), + expected: 'string', + operator: 'typeof ==', + stackStartFunction + }); + } +} + +function _isFunction(value, message, stackStartFunction) { + if (typeof value !== 'function') { + throw new assert.AssertionError({ + message, + actual: _typeOf(value), + expected: 'function', + operator: 'typeof ==', + stackStartFunction + }); + } +} + +function _isBuffer(value, message, stackStartFunction) { + if (!Buffer.isBuffer(value)) { + throw new assert.AssertionError({ + message, + actual: _typeOf(value), + expected: 'buffer', + operator: 'typeof ==', + stackStartFunction + }); + } +} + +function _typeOf(value) { + const type = typeof value; + + switch (type) { + case 'object': + if (value === null) + return 'null'; + + if (Array.isArray(value)) + return 'array'; + + if (Buffer.isBuffer(value)) + return 'buffer'; + + if (ArrayBuffer.isView(value)) + return 'arraybuffer'; + + if (util.isError(value)) + return 'error'; + + if (util.isDate(value)) + return 'date'; + + if (util.isRegExp(value)) + return 'regexp'; + + break; + case 'number': + if (!isFinite(value)) + return 'nan'; + break; + } + + return type; +} + +function _getConstructorName(object) { + if (object === undefined) + return 'undefined'; + + if (object === null) + return 'null'; + + const proto = Object.getPrototypeOf(object); + + // Should never happen. + if (proto === undefined) + throw new Error('Bad prototype.'); + + // Inherited from `null`. + if (proto === null) + return 'Null'; + + // Someone overwrote their + // constructor property? + if (!proto.constructor) + return 'Object'; + + // Non-named constructor function. + if (!proto.constructor.name) + return 'Unknown'; + + return proto.constructor.name; +} + +function _getFunctionName(func) { + return func.name || 'Unknown'; +} + +module.exports = assert; diff --git a/test/util/common.js b/test/util/common.js index e0070f26c..149cb3429 100644 --- a/test/util/common.js +++ b/test/util/common.js @@ -1,27 +1,219 @@ 'use strict'; -const fs = require('fs'); +const assert = require('assert'); +const path = require('path'); +const fs = require('../../lib/utils/fs'); +const Block = require('../../lib/primitives/block'); +const MerkleBlock = require('../../lib/primitives/merkleblock'); +const Headers = require('../../lib/primitives/headers'); +const {CompactBlock} = require('../../lib/net/bip152'); const TX = require('../../lib/primitives/tx'); +const Output = require('../../lib/primitives/output'); const CoinView = require('../../lib/coins/coinview'); +const BufferReader = require('../../lib/utils/reader'); +const BufferWriter = require('../../lib/utils/writer'); -exports.parseTX = function parseTX(file) { - let data = fs.readFileSync(`${__dirname}/../${file}`, 'utf8'); - let parts = data.trim().split(/\n+/); - let raw = parts[0]; - let tx = TX.fromRaw(raw.trim(), 'hex'); - let view = new CoinView(); - let txs = [tx]; +const common = exports; - for (let i = 1; i < parts.length; i++) { - let raw = parts[i]; - let prev = TX.fromRaw(raw.trim(), 'hex'); - view.addTX(prev, -1); - txs.push(prev); - } +common.readFile = function readFile(name, enc) { + const file = path.resolve(__dirname, '..', 'data', name); + return fs.readFileSync(file, enc); +}; + +common.writeFile = function writeFile(name, data) { + const file = path.resolve(__dirname, '..', 'data', name); + return fs.writeFileSync(file, data); +}; + +common.exists = function exists(name) { + const file = path.resolve(__dirname, '..', 'data', name); + return fs.existsSync(file); +}; + +common.readBlock = function readBlock(name) { + const raw = common.readFile(`${name}.raw`); + + if (!common.exists(`${name}-undo.raw`)) + return new BlockContext(Block, raw); + + const undoRaw = common.readFile(`${name}-undo.raw`); + + return new BlockContext(Block, raw, undoRaw); +}; + +common.readMerkle = function readMerkle(name) { + const raw = common.readFile(`${name}.raw`); + return new BlockContext(MerkleBlock, raw); +}; + +common.readCompact = function readCompact(name) { + const raw = common.readFile(`${name}.raw`); + return new BlockContext(CompactBlock, raw); +}; + +common.readTX = function readTX(name) { + const raw = common.readFile(`${name}.raw`); + + if (!common.exists(`${name}-undo.raw`)) + return new TXContext(raw); + + const undoRaw = common.readFile(`${name}-undo.raw`); - return { - tx: tx, - view: view, - txs: txs - }; + return new TXContext(raw, undoRaw); }; + +common.writeBlock = function writeBlock(name, block, view) { + common.writeFile(`${name}.raw`, block.toRaw()); + + if (!view) + return; + + const undo = makeBlockUndo(block, view); + const undoRaw = serializeUndo(undo); + + common.writeFile(`${name}-undo.raw`, undoRaw); +}; + +common.writeTX = function writeTX(name, tx, view) { + common.writeFile(`${name}.raw`, tx.toRaw()); + + if (!view) + return; + + const undo = makeTXUndo(tx, view); + const undoRaw = serializeUndo(undo); + + common.writeFile(`${name}-undo.raw`, undoRaw); +}; + +function parseUndo(data) { + const br = new BufferReader(data); + const items = []; + + while (br.left()) { + const output = Output.fromReader(br); + items.push(output); + } + + return items; +} + +function serializeUndo(items) { + const bw = new BufferWriter(); + + for (const item of items) { + bw.writeI64(item.value); + bw.writeVarBytes(item.script.toRaw()); + } + + return bw.render(); +} + +function applyBlockUndo(block, undo) { + const view = new CoinView(); + let i = 0; + + for (const tx of block.txs) { + if (tx.isCoinbase()) + continue; + + for (const {prevout} of tx.inputs) + view.addOutput(prevout, undo[i++]); + } + + assert(i === undo.length, 'Undo coins data inconsistency.'); + + return view; +} + +function applyTXUndo(tx, undo) { + const view = new CoinView(); + let i = 0; + + for (const {prevout} of tx.inputs) + view.addOutput(prevout, undo[i++]); + + assert(i === undo.length, 'Undo coins data inconsistency.'); + + return view; +} + +function makeBlockUndo(block, view) { + const items = []; + + for (const tx of block.txs) { + if (tx.isCoinbase()) + continue; + + for (const {prevout} of tx.inputs) { + const coin = view.getOutput(prevout); + assert(coin); + items.push(coin); + } + } + + return items; +} + +function makeTXUndo(tx, view) { + const items = []; + + for (const {prevout} of tx.inputs) { + const coin = view.getOutput(prevout); + assert(coin); + items.push(coin); + } + + return items; +} + +class BlockContext { + constructor(ctor, raw, undoRaw) { + this.ctor = ctor; + this.raw = raw; + this.undoRaw = undoRaw || null; + } + getRaw() { + return this.raw; + } + getBlock() { + const Block = this.ctor; + const block = Block.fromRaw(this.raw); + + if (!this.undoRaw) { + const view = new CoinView(); + return [block, view]; + } + + const undo = parseUndo(this.undoRaw); + const view = applyBlockUndo(block, undo); + + return [block, view]; + } + getHeaders() { + return Headers.fromHead(this.raw); + } +} + +class TXContext { + constructor(raw, undoRaw) { + this.raw = raw; + this.undoRaw = undoRaw || null; + } + getRaw() { + return this.raw; + } + getTX() { + const tx = TX.fromRaw(this.raw); + + if (!this.undoRaw) { + const view = new CoinView(); + return [tx, view]; + } + + const undo = parseUndo(this.undoRaw); + const view = applyTXUndo(tx, undo); + + return [tx, view]; + } +} diff --git a/test/util/memwallet.js b/test/util/memwallet.js index 939f4663e..a2364df56 100644 --- a/test/util/memwallet.js +++ b/test/util/memwallet.js @@ -8,7 +8,6 @@ const assert = require('assert'); const Network = require('../../lib/protocol/network'); -const util = require('../../lib/utils/util'); const MTX = require('../../lib/primitives/mtx'); const HD = require('../../lib/hd/hd'); const Bloom = require('../../lib/utils/bloom'); @@ -29,10 +28,10 @@ function MemWallet(options) { this.changeDepth = 1; this.receive = null; this.change = null; - this.map = {}; - this.coins = {}; - this.spent = {}; - this.paths = {}; + this.map = new Set(); + this.coins = new Map(); + this.spent = new Map(); + this.paths = new Map(); this.balance = 0; this.txs = 0; this.filter = Bloom.fromRate(1000000, 0.001, -1); @@ -89,7 +88,7 @@ MemWallet.prototype.init = function init() { this.master = HD.PrivateKey.generate(); if (!this.key) - this.key = this.master.deriveBIP44(this.account); + this.key = this.master.deriveAccount(44, this.account); i = this.receiveDepth; while (i--) @@ -101,21 +100,21 @@ MemWallet.prototype.init = function init() { }; MemWallet.prototype.createReceive = function createReceive() { - let index = this.receiveDepth++; - let key = this.deriveReceive(index); - let hash = key.getHash('hex'); + const index = this.receiveDepth++; + const key = this.deriveReceive(index); + const hash = key.getHash('hex'); this.filter.add(hash, 'hex'); - this.paths[hash] = new Path(hash, 0, index); + this.paths.set(hash, new Path(hash, 0, index)); this.receive = key; return key; }; MemWallet.prototype.createChange = function createChange() { - let index = this.changeDepth++; - let key = this.deriveChange(index); - let hash = key.getHash('hex'); + const index = this.changeDepth++; + const key = this.deriveChange(index); + const hash = key.getHash('hex'); this.filter.add(hash, 'hex'); - this.paths[hash] = new Path(hash, 1, index); + this.paths.set(hash, new Path(hash, 1, index)); this.change = key; return key; }; @@ -133,58 +132,60 @@ MemWallet.prototype.derivePath = function derivePath(path) { }; MemWallet.prototype.deriveKey = function deriveKey(branch, index) { - let key = this.master.deriveBIP44(this.account); + let key = this.master.deriveAccount(44, this.account); key = key.derive(branch).derive(index); - key = new KeyRing({ + const ring = new KeyRing({ network: this.network, privateKey: key.privateKey, witness: this.witness }); - key.witness = this.witness; - return key; + ring.witness = this.witness; + return ring; }; MemWallet.prototype.getKey = function getKey(hash) { - let path = this.paths[hash]; + const path = this.paths.get(hash); + if (!path) - return; + return null; + return this.derivePath(path); }; MemWallet.prototype.getPath = function getPath(hash) { - return this.paths[hash]; + return this.paths.get(hash); }; MemWallet.prototype.getCoin = function getCoin(key) { - return this.coins[key]; + return this.coins.get(key); }; MemWallet.prototype.getUndo = function getUndo(key) { - return this.spent[key]; + return this.spent.get(key); }; MemWallet.prototype.addCoin = function addCoin(coin) { - let op = Outpoint(coin.hash, coin.index); - let key = op.toKey(); + const op = Outpoint(coin.hash, coin.index); + const key = op.toKey(); this.filter.add(op.toRaw()); - delete this.spent[key]; + this.spent.delete(key); - this.coins[key] = coin; + this.coins.set(key, coin); this.balance += coin.value; }; MemWallet.prototype.removeCoin = function removeCoin(key) { - let coin = this.coins[key]; + const coin = this.coins.get(key); if (!coin) return; - this.spent[key] = coin; + this.spent.set(key, coin); this.balance -= coin.value; - delete this.coins[key]; + this.coins.delete(key); }; MemWallet.prototype.getAddress = function getAddress() { @@ -200,7 +201,12 @@ MemWallet.prototype.getChange = function getChange() { }; MemWallet.prototype.getCoins = function getCoins() { - return util.values(this.coins); + const coins = []; + + for (const coin of this.coins.values()) + coins.push(coin); + + return coins; }; MemWallet.prototype.syncKey = function syncKey(path) { @@ -220,38 +226,33 @@ MemWallet.prototype.syncKey = function syncKey(path) { }; MemWallet.prototype.addBlock = function addBlock(entry, txs) { - let i, tx; - - for (i = 0; i < txs.length; i++) { - tx = txs[i]; + for (let i = 0; i < txs.length; i++) { + const tx = txs[i]; this.addTX(tx, entry.height); } }; MemWallet.prototype.removeBlock = function removeBlock(entry, txs) { - let i, tx; - - for (i = txs.length - 1; i >= 0; i--) { - tx = txs[i]; + for (let i = txs.length - 1; i >= 0; i--) { + const tx = txs[i]; this.removeTX(tx, entry.height); } }; MemWallet.prototype.addTX = function addTX(tx, height) { - let hash = tx.hash('hex'); + const hash = tx.hash('hex'); let result = false; - let i, op, path, addr, coin, input, output; if (height == null) height = -1; - if (this.map[hash]) + if (this.map.has(hash)) return true; - for (i = 0; i < tx.inputs.length; i++) { - input = tx.inputs[i]; - op = input.prevout.toKey(); - coin = this.getCoin(op); + for (let i = 0; i < tx.inputs.length; i++) { + const input = tx.inputs[i]; + const op = input.prevout.toKey(); + const coin = this.getCoin(op); if (!coin) continue; @@ -261,20 +262,21 @@ MemWallet.prototype.addTX = function addTX(tx, height) { this.removeCoin(op); } - for (i = 0; i < tx.outputs.length; i++) { - output = tx.outputs[i]; - addr = output.getHash('hex'); + for (let i = 0; i < tx.outputs.length; i++) { + const output = tx.outputs[i]; + const addr = output.getHash('hex'); if (!addr) continue; - path = this.getPath(addr); + const path = this.getPath(addr); if (!path) continue; result = true; - coin = Coin.fromTX(tx, i, height); + + const coin = Coin.fromTX(tx, i, height); this.addCoin(coin); this.syncKey(path); @@ -282,23 +284,22 @@ MemWallet.prototype.addTX = function addTX(tx, height) { if (result) { this.txs++; - this.map[hash] = true; + this.map.add(hash); } return result; }; MemWallet.prototype.removeTX = function removeTX(tx, height) { - let hash = tx.hash('hex'); + const hash = tx.hash('hex'); let result = false; - let i, op, coin, input; - if (!this.map[hash]) + if (!this.map.has(hash)) return false; - for (i = 0; i < tx.outputs.length; i++) { - op = Outpoint(hash, i).toKey(); - coin = this.getCoin(op); + for (let i = 0; i < tx.outputs.length; i++) { + const op = Outpoint(hash, i).toKey(); + const coin = this.getCoin(op); if (!coin) continue; @@ -308,10 +309,10 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) { this.removeCoin(op); } - for (i = 0; i < tx.inputs.length; i++) { - input = tx.inputs[i]; - op = input.prevout.toKey(); - coin = this.getUndo(op); + for (let i = 0; i < tx.inputs.length; i++) { + const input = tx.inputs[i]; + const op = input.prevout.toKey(); + const coin = this.getUndo(op); if (!coin) continue; @@ -324,33 +325,32 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) { if (result) this.txs--; - delete this.map[hash]; + this.map.delete(hash); return result; }; MemWallet.prototype.deriveInputs = function deriveInputs(mtx) { - let keys = []; - let i, input, coin, addr, path, key; + const keys = []; - for (i = 0; i < mtx.inputs.length; i++) { - input = mtx.inputs[i]; - coin = mtx.view.getOutput(input); + for (let i = 0; i < mtx.inputs.length; i++) { + const input = mtx.inputs[i]; + const coin = mtx.view.getOutputFor(input); if (!coin) continue; - addr = coin.getHash('hex'); + const addr = coin.getHash('hex'); if (!addr) continue; - path = this.getPath(addr); + const path = this.getPath(addr); if (!path) continue; - key = this.derivePath(path); + const key = this.derivePath(path); keys.push(key); } @@ -359,7 +359,7 @@ MemWallet.prototype.deriveInputs = function deriveInputs(mtx) { }; MemWallet.prototype.fund = function fund(mtx, options) { - let coins = this.getCoins(); + const coins = this.getCoins(); if (!options) options = {}; @@ -378,18 +378,18 @@ MemWallet.prototype.fund = function fund(mtx, options) { }; MemWallet.prototype.template = function template(mtx) { - let keys = this.deriveInputs(mtx); + const keys = this.deriveInputs(mtx); mtx.template(keys); }; MemWallet.prototype.sign = function sign(mtx) { - let keys = this.deriveInputs(mtx); + const keys = this.deriveInputs(mtx); mtx.template(keys); mtx.sign(keys); }; MemWallet.prototype.create = async function create(options) { - let mtx = new MTX(options); + const mtx = new MTX(options); await this.fund(mtx, options); @@ -409,7 +409,7 @@ MemWallet.prototype.create = async function create(options) { }; MemWallet.prototype.send = async function send(options) { - let mtx = await this.create(options); + const mtx = await this.create(options); this.addTX(mtx.toTX()); return mtx; }; diff --git a/test/util/node-context.js b/test/util/node-context.js index b8f8c6db0..f8b39cd81 100644 --- a/test/util/node-context.js +++ b/test/util/node-context.js @@ -17,17 +17,15 @@ function NodeContext(network, size) { this.init(); }; -NodeContext.prototype.init = function() { - let i, port, last, node; - - for (i = 0; i < this.size; i++) { - port = this.network.port + i; - last = port - 1; +NodeContext.prototype.init = function init() { + for (let i = 0; i < this.size; i++) { + const port = this.network.port + i; + let last = port - 1; if (last < this.network.port) last = port; - node = new FullNode({ + const node = new FullNode({ network: this.network, db: 'memory', logger: new Logger({ @@ -46,7 +44,7 @@ NodeContext.prototype.init = function() { ] }); - node.on('error', function(err) { + node.on('error', (err) => { node.logger.error(err); }); @@ -55,42 +53,40 @@ NodeContext.prototype.init = function() { }; NodeContext.prototype.open = function open() { - let jobs = []; + const jobs = []; - for (let node of this.nodes) + for (const node of this.nodes) jobs.push(node.open()); return Promise.all(jobs); }; NodeContext.prototype.close = function close() { - let jobs = []; + const jobs = []; - for (let node of this.nodes) + for (const node of this.nodes) jobs.push(node.close()); return Promise.all(jobs); }; NodeContext.prototype.connect = async function connect() { - for (let node of this.nodes) { + for (const node of this.nodes) { await node.connect(); await co.timeout(1000); } }; NodeContext.prototype.disconnect = async function disconnect() { - let i, node; - - for (i = this.nodes.length - 1; i >= 0; i--) { - node = this.nodes[i]; + for (let i = this.nodes.length - 1; i >= 0; i--) { + const node = this.nodes[i]; await node.disconnect(); await co.timeout(1000); } }; NodeContext.prototype.startSync = function startSync() { - for (let node of this.nodes) { + for (const node of this.nodes) { node.chain.synced = true; node.chain.emit('full'); node.startSync(); @@ -98,24 +94,23 @@ NodeContext.prototype.startSync = function startSync() { }; NodeContext.prototype.stopSync = function stopSync() { - for (let node of this.nodes) + for (const node of this.nodes) node.stopSync(); }; NodeContext.prototype.generate = async function generate(index, blocks) { - let node = this.nodes[index]; - let i, block; + const node = this.nodes[index]; assert(node); - for (i = 0; i < blocks; i++) { - block = await node.miner.mineBlock(); + for (let i = 0; i < blocks; i++) { + const block = await node.miner.mineBlock(); await node.chain.add(block); } }; NodeContext.prototype.height = function height(index) { - let node = this.nodes[index]; + const node = this.nodes[index]; assert(node); diff --git a/test/utils-test.js b/test/utils-test.js index 98313f44e..8e7240ac3 100644 --- a/test/utils-test.js +++ b/test/utils-test.js @@ -1,112 +1,124 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); -const BN = require('../lib/crypto/bn'); -const secp256k1 = require('../lib/crypto/secp256k1'); +const assert = require('./util/assert'); +const {U64, I64} = require('../lib/utils/int64'); const base58 = require('../lib/utils/base58'); const encoding = require('../lib/utils/encoding'); -const digest = require('../lib/crypto/digest'); -const hkdf = require('../lib/crypto/hkdf'); -const schnorr = require('../lib/crypto/schnorr'); const Amount = require('../lib/btc/amount'); -const consensus = require('../lib/protocol/consensus'); const Validator = require('../lib/utils/validator'); +const util = require('../lib/utils/util'); + +const base58Tests = [ + ['', ''], + ['61', '2g'], + ['626262', 'a3gV'], + ['636363', 'aPEr'], + [ + '73696d706c792061206c6f6e6720737472696e67', + '2cFupjhnEsSn59qHXstmK2ffpLv2' + ], + [ + '00eb15231dfceb60925886b67d065299925915aeb172c06647', + '1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L' + ], + ['516b6fcd0f', 'ABnLTmg'], + ['bf4f89001e670274dd', '3SEo3LWLoPntC'], + ['572e4794', '3EFU7m'], + ['ecac89cad93923c02321', 'EJDM8drfXA6uyA'], + ['10c8511e', 'Rt5zm'], + ['00000000000000000000', '1111111111'] +]; + +const unsigned = [ + new U64('ffeeffee', 16), + new U64('001fffeeffeeffee', 16), + new U64('eeffeeff', 16), + new U64('001feeffeeffeeff', 16), + new U64(0), + new U64(1) +]; + +const signed = [ + new I64('ffeeffee', 16), + new I64('001fffeeffeeffee', 16), + new I64('eeffeeff', 16), + new I64('001feeffeeffeeff', 16), + new I64(0), + new I64(1), + new I64('ffeeffee', 16).ineg(), + new I64('001fffeeffeeffee', 16).ineg(), + new I64('eeffeeff', 16).ineg(), + new I64('001feeffeeffeeff', 16).ineg(), + new I64(0).ineg(), + new I64(1).ineg() +]; describe('Utils', function() { - let vectors, signed, unsigned; - - vectors = [ - ['', ''], - ['61', '2g'], - ['626262', 'a3gV'], - ['636363', 'aPEr'], - [ - '73696d706c792061206c6f6e6720737472696e67', - '2cFupjhnEsSn59qHXstmK2ffpLv2' - ], - [ - '00eb15231dfceb60925886b67d065299925915aeb172c06647', - '1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L' - ], - ['516b6fcd0f', 'ABnLTmg'], - ['bf4f89001e670274dd', '3SEo3LWLoPntC'], - ['572e4794', '3EFU7m'], - ['ecac89cad93923c02321', 'EJDM8drfXA6uyA'], - ['10c8511e', 'Rt5zm'], - ['00000000000000000000', '1111111111'] - ]; - it('should encode/decode base58', () => { - let buf = Buffer.from('000000deadbeef', 'hex'); - let b = base58.encode(buf); - let i, r; - - assert.equal(b, '1116h8cQN'); - assert.deepEqual(base58.decode(b), buf); - - for (i = 0; i < vectors.length; i++) { - r = Buffer.from(vectors[i][0], 'hex'); - b = vectors[i][1]; - assert.equal(base58.encode(r), b); - assert.deepEqual(base58.decode(b), r); - } - }); + const buf = Buffer.from('000000deadbeef', 'hex'); + const str = base58.encode(buf); - it('should verify proof-of-work', () => { - let bits = 0x1900896c; - let hash; + assert.strictEqual(str, '1116h8cQN'); + assert.bufferEqual(base58.decode(str), buf); - hash = Buffer.from( - '672b3f1bb11a994267ea4171069ba0aa4448a840f38e8f340000000000000000', - 'hex' - ); - - assert(consensus.verifyPOW(hash, bits)); + for (const [hex, b58] of base58Tests) { + const data = Buffer.from(hex, 'hex'); + assert.strictEqual(base58.encode(data), b58); + assert.bufferEqual(base58.decode(b58), data); + } }); it('should convert satoshi to btc', () => { - let btc = Amount.btc(5460); - assert.equal(btc, '0.0000546'); - btc = Amount.btc(54678 * 1000000); - assert.equal(btc, '546.78'); - btc = Amount.btc(5460 * 10000000); - assert.equal(btc, '546.0'); + assert.strictEqual(Amount.btc(5460), '0.0000546'); + assert.strictEqual(Amount.btc(54678 * 1000000), '546.78'); + assert.strictEqual(Amount.btc(5460 * 10000000), '546.0'); }); it('should convert btc to satoshi', () => { - let btc = Amount.value('0.0000546'); - assert(btc === 5460); - btc = Amount.value('546.78'); - assert(btc === 54678 * 1000000); - btc = Amount.value('546'); - assert(btc === 5460 * 10000000); - btc = Amount.value('546.0'); - assert(btc === 5460 * 10000000); - btc = Amount.value('546.0000'); - assert(btc === 5460 * 10000000); + assert.strictEqual(Amount.value('0.0000546'), 5460); + assert.strictEqual(Amount.value('546.78'), 54678 * 1000000); + assert.strictEqual(Amount.value('546'), 5460 * 10000000); + assert.strictEqual(Amount.value('546.0'), 5460 * 10000000); + assert.strictEqual(Amount.value('546.0000'), 5460 * 10000000); + assert.doesNotThrow(() => { Amount.value('546.00000000000000000'); }); + assert.throws(() => { Amount.value('546.00000000000000001'); }); + assert.doesNotThrow(() => { Amount.value('90071992.54740991'); }); + assert.doesNotThrow(() => { Amount.value('090071992.547409910'); }); + assert.throws(() => { Amount.value('90071992.54740992'); }); + assert.throws(() => { Amount.value('190071992.54740991'); }); + + assert.strictEqual(0.15645647 * 1e8, 15645646.999999998); + assert.strictEqual(parseFloat('0.15645647') * 1e8, 15645646.999999998); + assert.strictEqual(15645647 / 1e8, 0.15645647); + + assert.strictEqual(util.fromFixed('0.15645647', 8), 15645647); + assert.strictEqual(util.toFixed(15645647, 8), '0.15645647'); + assert.strictEqual(util.fromFloat(0.15645647, 8), 15645647); + assert.strictEqual(util.toFloat(15645647, 8), 0.15645647); }); it('should write/read new varints', () => { - let b; - /* * 0: [0x00] 256: [0x81 0x00] * 1: [0x01] 16383: [0xFE 0x7F] @@ -116,224 +128,120 @@ describe('Utils', function() { * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] */ - b = Buffer.allocUnsafe(1); - b.fill(0x00); + let b = Buffer.alloc(1, 0xff); encoding.writeVarint2(b, 0, 0); - assert.equal(encoding.readVarint2(b, 0).value, 0); + assert.strictEqual(encoding.readVarint2(b, 0).value, 0); assert.deepEqual(b, [0]); - b = Buffer.allocUnsafe(1); - b.fill(0x00); + b = Buffer.alloc(1, 0xff); encoding.writeVarint2(b, 1, 0); - assert.equal(encoding.readVarint2(b, 0).value, 1); + assert.strictEqual(encoding.readVarint2(b, 0).value, 1); assert.deepEqual(b, [1]); - b = Buffer.allocUnsafe(1); - b.fill(0x00); + b = Buffer.alloc(1, 0xff); encoding.writeVarint2(b, 127, 0); - assert.equal(encoding.readVarint2(b, 0).value, 127); + assert.strictEqual(encoding.readVarint2(b, 0).value, 127); assert.deepEqual(b, [0x7f]); - b = Buffer.allocUnsafe(2); - b.fill(0x00); + b = Buffer.alloc(2, 0xff); encoding.writeVarint2(b, 128, 0); - assert.equal(encoding.readVarint2(b, 0).value, 128); + assert.strictEqual(encoding.readVarint2(b, 0).value, 128); assert.deepEqual(b, [0x80, 0x00]); - b = Buffer.allocUnsafe(2); - b.fill(0x00); + b = Buffer.alloc(2, 0xff); encoding.writeVarint2(b, 255, 0); - assert.equal(encoding.readVarint2(b, 0).value, 255); + assert.strictEqual(encoding.readVarint2(b, 0).value, 255); assert.deepEqual(b, [0x80, 0x7f]); - b = Buffer.allocUnsafe(2); - b.fill(0x00); + b = Buffer.alloc(2, 0xff); encoding.writeVarint2(b, 16383, 0); - assert.equal(encoding.readVarint2(b, 0).value, 16383); + assert.strictEqual(encoding.readVarint2(b, 0).value, 16383); assert.deepEqual(b, [0xfe, 0x7f]); - b = Buffer.allocUnsafe(2); - b.fill(0x00); + b = Buffer.alloc(2, 0xff); encoding.writeVarint2(b, 16384, 0); - assert.equal(encoding.readVarint2(b, 0).value, 16384); + assert.strictEqual(encoding.readVarint2(b, 0).value, 16384); assert.deepEqual(b, [0xff, 0x00]); - b = Buffer.allocUnsafe(3); - b.fill(0x00); + b = Buffer.alloc(3, 0xff); encoding.writeVarint2(b, 16511, 0); - assert.equal(encoding.readVarint2(b, 0).value, 16511); + assert.strictEqual(encoding.readVarint2(b, 0).value, 16511); + assert.deepEqual(b.slice(0, 2), [0xff, 0x7f]); // assert.deepEqual(b, [0x80, 0xff, 0x7f]); - assert.deepEqual(b, [0xff, 0x7f, 0x00]); - b = Buffer.allocUnsafe(3); - b.fill(0x00); + b = Buffer.alloc(3, 0xff); encoding.writeVarint2(b, 65535, 0); - assert.equal(encoding.readVarint2(b, 0).value, 65535); - // assert.deepEqual(b, [0x82, 0xfd, 0x7f]); + assert.strictEqual(encoding.readVarint2(b, 0).value, 65535); assert.deepEqual(b, [0x82, 0xfe, 0x7f]); + // assert.deepEqual(b, [0x82, 0xfd, 0x7f]); - b = Buffer.allocUnsafe(5); - b.fill(0x00); + b = Buffer.alloc(5, 0xff); encoding.writeVarint2(b, Math.pow(2, 32), 0); - assert.equal(encoding.readVarint2(b, 0).value, Math.pow(2, 32)); + assert.strictEqual(encoding.readVarint2(b, 0).value, Math.pow(2, 32)); assert.deepEqual(b, [0x8e, 0xfe, 0xfe, 0xff, 0x00]); }); - unsigned = [ - new BN('ffeeffee'), - new BN('001fffeeffeeffee'), - new BN('eeffeeff'), - new BN('001feeffeeffeeff'), - new BN(0), - new BN(1) - ]; - - signed = [ - new BN('ffeeffee'), - new BN('001fffeeffeeffee'), - new BN('eeffeeff'), - new BN('001feeffeeffeeff'), - new BN(0), - new BN(1), - new BN('ffeeffee').ineg(), - new BN('001fffeeffeeffee').ineg(), - new BN('eeffeeff').ineg(), - new BN('001feeffeeffeeff').ineg(), - new BN(0).ineg(), - new BN(1).ineg() - ]; - - unsigned.forEach((num) => { - let buf1 = Buffer.allocUnsafe(8); - let buf2 = Buffer.allocUnsafe(8); - let bits = num.bitLength(); + for (const num of unsigned) { + const bits = num.bitLength(); it(`should write+read a ${bits} bit unsigned int`, () => { - let n1, n2; + const buf1 = Buffer.allocUnsafe(8); + const buf2 = Buffer.allocUnsafe(8); - encoding.writeU64BN(buf1, num, 0); + encoding.writeU64N(buf1, num, 0); encoding.writeU64(buf2, num.toNumber(), 0); - assert.deepEqual(buf1, buf2); + assert.bufferEqual(buf1, buf2); + + const n1 = encoding.readU64N(buf1, 0); + const n2 = encoding.readU64(buf2, 0); - n1 = encoding.readU64BN(buf1, 0); - n2 = encoding.readU64(buf2, 0); - assert.equal(n1.toNumber(), n2); + assert.strictEqual(n1.toNumber(), n2); }); - }); + } - signed.forEach((num) => { - let buf1 = Buffer.allocUnsafe(8); - let buf2 = Buffer.allocUnsafe(8); - let bits = num.bitLength(); - let sign = num.isNeg() ? 'negative' : 'positive'; + for (const num of signed) { + const bits = num.bitLength(); + const sign = num.isNeg() ? 'negative' : 'positive'; it(`should write+read a ${bits} bit ${sign} int`, () => { - let n1, n2; + const buf1 = Buffer.allocUnsafe(8); + const buf2 = Buffer.allocUnsafe(8); + + encoding.writeI64N(buf1, num, 0); + encoding.writeI64(buf2, num.toNumber(), 0); + assert.bufferEqual(buf1, buf2); - encoding.write64BN(buf1, num, 0); - encoding.write64(buf2, num.toNumber(), 0); - assert.deepEqual(buf1, buf2); + const n1 = encoding.readI64N(buf1, 0); + const n2 = encoding.readI64(buf2, 0); - n1 = encoding.read64BN(buf1, 0); - n2 = encoding.read64(buf2, 0); - assert.equal(n1.toNumber(), n2); + assert.strictEqual(n1.toNumber(), n2); }); it(`should write+read a ${bits} bit ${sign} int as unsigned`, () => { - let n1, n2; + const buf1 = Buffer.allocUnsafe(8); + const buf2 = Buffer.allocUnsafe(8); - encoding.writeU64BN(buf1, num, 0); + encoding.writeU64N(buf1, num.toU64(), 0); encoding.writeU64(buf2, num.toNumber(), 0); - assert.deepEqual(buf1, buf2); + assert.bufferEqual(buf1, buf2); + + const n1 = encoding.readU64N(buf1, 0); - n1 = encoding.readU64BN(buf1, 0); if (num.isNeg()) { assert.throws(() => encoding.readU64(buf2, 0)); } else { - n2 = encoding.readU64(buf2, 0); - assert.equal(n1.toNumber(), n2); + const n2 = encoding.readU64(buf2, 0); + assert.strictEqual(n1.toNumber(), n2); } }); - }); - - it('should do proper hkdf', () => { - // https://tools.ietf.org/html/rfc5869 - let alg = 'sha256'; - let ikm = '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'; - let salt = '000102030405060708090a0b0c'; - let info = 'f0f1f2f3f4f5f6f7f8f9'; - let len = 42; - let prkE, okmE, prk, okm; - - prkE = '077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5'; - okmE = '3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1' - + 'a5a4c5db02d56ecc4c5bf34007208d5b887185865'; - - ikm = Buffer.from(ikm, 'hex'); - salt = Buffer.from(salt, 'hex'); - info = Buffer.from(info, 'hex'); - - prk = hkdf.extract(ikm, salt, alg); - okm = hkdf.expand(prk, info, len, alg); - - assert.equal(prk.toString('hex'), prkE); - assert.equal(okm.toString('hex'), okmE); - - alg = 'sha256'; - - ikm = '000102030405060708090a0b0c0d0e0f' - + '101112131415161718191a1b1c1d1e1f' - + '202122232425262728292a2b2c2d2e2f' - + '303132333435363738393a3b3c3d3e3f' - + '404142434445464748494a4b4c4d4e4f'; - - salt = '606162636465666768696a6b6c6d6e6f' - + '707172737475767778797a7b7c7d7e7f' - + '808182838485868788898a8b8c8d8e8f' - + '909192939495969798999a9b9c9d9e9f' - + 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf'; - - info = 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' - + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' - + 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' - + 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' - + 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'; - - len = 82; - - prkE = '06a6b88c5853361a06104c9ceb35b45c' - + 'ef760014904671014a193f40c15fc244'; - - okmE = 'b11e398dc80327a1c8e7f78c596a4934' - + '4f012eda2d4efad8a050cc4c19afa97c' - + '59045a99cac7827271cb41c65e590e09' - + 'da3275600c2f09b8367793a9aca3db71' - + 'cc30c58179ec3e87c14c01d5c1f3434f' - + '1d87'; - - ikm = Buffer.from(ikm, 'hex'); - salt = Buffer.from(salt, 'hex'); - info = Buffer.from(info, 'hex'); - - prk = hkdf.extract(ikm, salt, alg); - okm = hkdf.expand(prk, info, len, alg); - - assert.equal(prk.toString('hex'), prkE); - assert.equal(okm.toString('hex'), okmE); - }); - - it('should do proper schnorr', () => { - let key = secp256k1.generatePrivateKey(); - let pub = secp256k1.publicKeyCreate(key, true); - let msg = digest.hash256(Buffer.from('foo', 'ascii')); - let sig = schnorr.sign(msg, key); - assert(schnorr.verify(msg, sig, pub)); - assert.deepEqual(schnorr.recover(sig, msg), pub); - }); + } it('should validate integers 0 and 1 as booleans', () => { - let validator = new Validator({shouldBeTrue: 1, shouldBeFalse: 0}); - assert(validator.bool('shouldBeTrue') === true); - assert(validator.bool('shouldBeFalse') === false); + const validator = new Validator({ + shouldBeTrue: 1, + shouldBeFalse: 0 + }); + assert.strictEqual(validator.bool('shouldBeTrue'), true); + assert.strictEqual(validator.bool('shouldBeFalse'), false); }); }); diff --git a/test/wallet-test.js b/test/wallet-test.js index 6f6d7a5ae..9a7daaee5 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -1,12 +1,16 @@ +/* eslint-env mocha */ +/* eslint prefer-arrow-callback: "off" */ + 'use strict'; -const assert = require('assert'); +const assert = require('./util/assert'); const consensus = require('../lib/protocol/consensus'); const util = require('../lib/utils/util'); const encoding = require('../lib/utils/encoding'); const digest = require('../lib/crypto/digest'); const random = require('../lib/crypto/random'); const WalletDB = require('../lib/wallet/walletdb'); +const WorkerPool = require('../lib/workers/workerpool'); const Address = require('../lib/primitives/address'); const MTX = require('../lib/primitives/mtx'); const Coin = require('../lib/primitives/coin'); @@ -22,58 +26,228 @@ const KEY1 = 'xprv9s21ZrQH143K3Aj6xQBymM31Zb4BVc7wxqfUhMZrzewdDVCt' const KEY2 = 'xprv9s21ZrQH143K3mqiSThzPtWAabQ22Pjp3uSNnZ53A5bQ4udp' + 'faKekc2m4AChLYH1XDzANhrSdxHYWUeTWjYJwFwWFyHkTMnMeAcW4JyRCZa'; -let globalHeight = 1; +const workers = new WorkerPool({ + enabled: false +}); + +const wdb = new WalletDB({ + db: 'memory', + verify: true, + workers +}); + +let currentWallet = null; +let importedWallet = null; +let importedKey = null; +let doubleSpendWallet = null; +let doubleSpendCoin = null; + let globalTime = util.now(); +let globalHeight = 1; -function nextBlock(height) { - let hash, prev; +function nextBlock() { + const height = globalHeight++; + const time = globalTime++; - if (height == null) - height = globalHeight++; + const prevHead = encoding.U32(height - 1); + const prevHash = digest.hash256(prevHead); - hash = digest.hash256(encoding.U32(height)).toString('hex'); - prev = digest.hash256(encoding.U32(height - 1)).toString('hex'); + const head = encoding.U32(height); + const hash = digest.hash256(head); return { - hash: hash, + hash: hash.toString('hex'), height: height, - prevBlock: prev, - ts: globalTime + height, + prevBlock: prevHash.toString('hex'), + time: time, merkleRoot: encoding.NULL_HASH, nonce: 0, bits: 0 }; } -function dummy(hash) { - if (!hash) - hash = random.randomBytes(32).toString('hex'); - +function dummyInput() { + const hash = random.randomBytes(32).toString('hex'); return Input.fromOutpoint(new Outpoint(hash, 0)); } -describe('Wallet', function() { - let walletdb, wallet, ewallet, ekey; - let doubleSpendWallet, doubleSpend; +async function testP2PKH(witness, nesting) { + const flags = Script.flags.STANDARD_VERIFY_FLAGS; + + const wallet = await wdb.create({ + witness + }); + + const addr = Address.fromString(wallet.getAddress('string')); + + const type = witness ? Address.types.WITNESS : Address.types.PUBKEYHASH; + assert.strictEqual(addr.type, type); + + const src = new MTX(); + src.addInput(dummyInput()); + src.addOutput(nesting ? wallet.getNested() : wallet.getAddress(), 5460 * 2); + src.addOutput(new Address(), 2 * 5460); + + const mtx = new MTX(); + mtx.addTX(src, 0); + mtx.addOutput(wallet.getAddress(), 5460); + + await wallet.sign(mtx); + + const [tx, view] = mtx.commit(); + + assert(tx.verify(view, flags)); +} + +async function testP2SH(witness, nesting) { + const flags = Script.flags.STANDARD_VERIFY_FLAGS; + const receive = nesting ? 'nested' : 'receive'; + const receiveDepth = nesting ? 'nestedDepth' : 'receiveDepth'; + const vector = witness ? 'witness' : 'script'; + + // Create 3 2-of-3 wallets with our pubkeys as "shared keys" + const options = { + witness, + type: 'multisig', + m: 2, + n: 3 + }; + + const alice = await wdb.create(options); + const bob = await wdb.create(options); + const carol = await wdb.create(options); + const recipient = await wdb.create(); + + await alice.addSharedKey(bob.account.accountKey); + await alice.addSharedKey(carol.account.accountKey); + + await bob.addSharedKey(alice.account.accountKey); + await bob.addSharedKey(carol.account.accountKey); + + await carol.addSharedKey(alice.account.accountKey); + await carol.addSharedKey(bob.account.accountKey); + + // Our p2sh address + const addr1 = alice.account[receive].getAddress(); + + if (witness) { + const type = nesting ? Address.types.SCRIPTHASH : Address.types.WITNESS; + assert.strictEqual(addr1.type, type); + } else { + assert.strictEqual(addr1.type, Address.types.SCRIPTHASH); + } + + assert(alice.account[receive].getAddress().equals(addr1)); + assert(bob.account[receive].getAddress().equals(addr1)); + assert(carol.account[receive].getAddress().equals(addr1)); + + const nestedAddr1 = alice.getNested(); + + if (witness) { + assert(nestedAddr1); + assert(alice.getNested().equals(nestedAddr1)); + assert(bob.getNested().equals(nestedAddr1)); + assert(carol.getNested().equals(nestedAddr1)); + } + + { + // Add a shared unspent transaction to our wallets + const fund = new MTX(); + fund.addInput(dummyInput()); + fund.addOutput(nesting ? nestedAddr1 : addr1, 5460 * 10); + + // Simulate a confirmation + const block = nextBlock(); + + assert.strictEqual(alice.account[receiveDepth], 1); + + await wdb.addBlock(block, [fund.toTX()]); + + assert.strictEqual(alice.account[receiveDepth], 2); + assert.strictEqual(alice.account.changeDepth, 1); + } + + const addr2 = alice.account[receive].getAddress(); + assert(!addr2.equals(addr1)); + + assert(alice.account[receive].getAddress().equals(addr2)); + assert(bob.account[receive].getAddress().equals(addr2)); + assert(carol.account[receive].getAddress().equals(addr2)); - walletdb = new WalletDB({ - name: 'wallet-test', - db: 'memory', - verify: true + // Create a tx requiring 2 signatures + const send = new MTX(); + + send.addOutput(recipient.getAddress(), 5460); + + assert(!send.verify(flags)); + + await alice.fund(send, { + rate: 10000, + round: true }); + await alice.sign(send); + + assert(!send.verify(flags)); + + await bob.sign(send); + + const [tx, view] = send.commit(); + assert(tx.verify(view, flags)); + + assert.strictEqual(alice.account.changeDepth, 1); + + const change = alice.account.change.getAddress(); + + assert(alice.account.change.getAddress().equals(change)); + assert(bob.account.change.getAddress().equals(change)); + assert(carol.account.change.getAddress().equals(change)); + + // Simulate a confirmation + { + const block = nextBlock(); + + await wdb.addBlock(block, [tx]); + + assert.strictEqual(alice.account[receiveDepth], 2); + assert.strictEqual(alice.account.changeDepth, 2); + + assert(alice.account[receive].getAddress().equals(addr2)); + assert(!alice.account.change.getAddress().equals(change)); + } + + const change2 = alice.account.change.getAddress(); + + assert(alice.account.change.getAddress().equals(change2)); + assert(bob.account.change.getAddress().equals(change2)); + assert(carol.account.change.getAddress().equals(change2)); + + const input = tx.inputs[0]; + input[vector].setData(2, encoding.ZERO_SIG); + input[vector].compile(); + + assert(!tx.verify(view, flags)); + assert.strictEqual(tx.getFee(view), 10000); +} + +describe('Wallet', function() { this.timeout(5000); it('should open walletdb', async () => { consensus.COINBASE_MATURITY = 0; - await walletdb.open(); + await wdb.open(); }); it('should generate new key and address', async () => { - let w = await walletdb.create(); - let addr = w.getAddress('string'); - assert(addr); - assert(Address.fromString(addr)); + const wallet = await wdb.create(); + + const addr1 = wallet.getAddress(); + assert(addr1); + + const str = addr1.toString(); + const addr2 = Address.fromString(str); + + assert(addr2.equals(addr1)); }); it('should validate existing address', () => { @@ -87,503 +261,484 @@ describe('Wallet', function() { }); it('should create and get wallet', async () => { - let w1, w2; + const wallet1 = await wdb.create(); - w1 = await walletdb.create(); - await w1.destroy(); + await wallet1.destroy(); - w2 = await walletdb.get(w1.id); + const wallet2 = await wdb.get(wallet1.id); - assert(w1 !== w2); - assert(w1.master !== w2.master); - assert.equal(w1.master.key.toBase58(), w2.master.key.toBase58()); - assert.equal( - w1.account.accountKey.toBase58(), - w2.account.accountKey.toBase58()); + assert(wallet1 !== wallet2); + assert(wallet1.master !== wallet2.master); + assert(wallet1.master.key.equals(wallet2.master.key)); + assert(wallet1.account.accountKey.equals(wallet2.account.accountKey)); }); - async function testP2PKH(witness, bullshitNesting) { - let flags = Script.flags.STANDARD_VERIFY_FLAGS; - let w, addr, src, tx; - - w = await walletdb.create({ witness: witness }); - - addr = Address.fromString(w.getAddress('string')); - - if (witness) - assert.equal(addr.type, Address.types.WITNESS); - else - assert.equal(addr.type, Address.types.PUBKEYHASH); - - src = new MTX(); - src.addInput(dummy()); - src.addOutput(bullshitNesting ? w.getNested() : w.getAddress(), 5460 * 2); - src.addOutput(new Address(), 2 * 5460); - src = src.toTX(); - - tx = new MTX(); - tx.addTX(src, 0); - tx.addOutput(w.getAddress(), 5460); - - await w.sign(tx); - - assert(tx.verify(flags)); - } - - it('should sign/verify pubkeyhash tx', async () => { + it('should sign/verify p2pkh tx', async () => { await testP2PKH(false, false); }); - it('should sign/verify witnesspubkeyhash tx', async () => { + it('should sign/verify p2wpkh tx', async () => { await testP2PKH(true, false); }); - it('should sign/verify witnesspubkeyhash tx with bullshit nesting', async () => { + it('should sign/verify p2wpkh tx w/ nested bullshit', async () => { await testP2PKH(true, true); }); it('should multisign/verify TX', async () => { - let w, k, script, src, tx, maxSize; - - w = await walletdb.create({ + const wallet = await wdb.create({ type: 'multisig', m: 1, n: 2 }); - k = HD.generate().deriveBIP44(0).toPublic(); + const xpriv = HD.PrivateKey.generate(); + const key = xpriv.deriveAccount(44, 0).toPublic(); - await w.addSharedKey(k); + await wallet.addSharedKey(key); - script = Script.fromMultisig(1, 2, [ - w.account.receive.getPublicKey(), - k.derivePath('m/0/0').publicKey + const script = Script.fromMultisig(1, 2, [ + wallet.account.receive.getPublicKey(), + key.derivePath('m/0/0').publicKey ]); // Input transaction (bare 1-of-2 multisig) - src = new MTX(); - src.addInput(dummy()); + const src = new MTX(); + src.addInput(dummyInput()); src.addOutput(script, 5460 * 2); src.addOutput(new Address(), 5460 * 2); - src = src.toTX(); - tx = new MTX(); + const tx = new MTX(); tx.addTX(src, 0); - tx.addOutput(w.getAddress(), 5460); + tx.addOutput(wallet.getAddress(), 5460); - maxSize = await tx.estimateSize(); + const maxSize = await tx.estimateSize(); - await w.sign(tx); + await wallet.sign(tx); assert(tx.toRaw().length <= maxSize); assert(tx.verify()); }); it('should handle missed and invalid txs', async () => { - let w = await walletdb.create(); - let f = await walletdb.create(); - let t1, t2, t3, t4, f1, fake, balance, txs; + const alice = await wdb.create(); + const bob = await wdb.create(); // Coinbase // balance: 51000 - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w.getAddress(), 50000); - t1.addOutput(w.getAddress(), 1000); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 50000); + t1.addOutput(alice.getAddress(), 1000); - t2 = new MTX(); + const t2 = new MTX(); t2.addTX(t1, 0); // 50000 - t2.addOutput(w.getAddress(), 24000); - t2.addOutput(w.getAddress(), 24000); + t2.addOutput(alice.getAddress(), 24000); + t2.addOutput(alice.getAddress(), 24000); // Save for later. - doubleSpendWallet = w; - doubleSpend = Coin.fromTX(t1, 0, -1); + doubleSpendWallet = alice; + doubleSpendCoin = Coin.fromTX(t1, 0, -1); // balance: 49000 - await w.sign(t2); - t2 = t2.toTX(); - t3 = new MTX(); + await alice.sign(t2); + + const t3 = new MTX(); t3.addTX(t1, 1); // 1000 t3.addTX(t2, 0); // 24000 - t3.addOutput(w.getAddress(), 23000); + t3.addOutput(alice.getAddress(), 23000); // balance: 47000 - await w.sign(t3); - t3 = t3.toTX(); - t4 = new MTX(); + await alice.sign(t3); + + const t4 = new MTX(); t4.addTX(t2, 1); // 24000 t4.addTX(t3, 0); // 23000 - t4.addOutput(w.getAddress(), 11000); - t4.addOutput(w.getAddress(), 11000); + t4.addOutput(alice.getAddress(), 11000); + t4.addOutput(alice.getAddress(), 11000); // balance: 22000 - await w.sign(t4); - t4 = t4.toTX(); - f1 = new MTX(); + await alice.sign(t4); + + const f1 = new MTX(); f1.addTX(t4, 1); // 11000 - f1.addOutput(f.getAddress(), 10000); + f1.addOutput(bob.getAddress(), 10000); // balance: 11000 - await w.sign(f1); - f1 = f1.toTX(); + await alice.sign(f1); - fake = new MTX(); + const fake = new MTX(); fake.addTX(t1, 1); // 1000 (already redeemed) - fake.addOutput(w.getAddress(), 500); + fake.addOutput(alice.getAddress(), 500); // Script inputs but do not sign - await w.template(fake); + await alice.template(fake); // Fake signature - fake.inputs[0].script.set(0, encoding.ZERO_SIG); - fake.inputs[0].script.compile(); + const input = fake.inputs[0]; + input.script.setData(0, encoding.ZERO_SIG); + input.script.compile(); // balance: 11000 - fake = fake.toTX(); // Fake TX should temporarily change output. - await walletdb.addTX(fake); + { + await wdb.addTX(fake.toTX()); + await wdb.addTX(t4.toTX()); - await walletdb.addTX(t4); - - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 22500); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 22500); + } - await walletdb.addTX(t1); + { + await wdb.addTX(t1.toTX()); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 72500); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 72500); + } - await walletdb.addTX(t2); + { + await wdb.addTX(t2.toTX()); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 46500); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 46500); + } - await walletdb.addTX(t3); + { + await wdb.addTX(t3.toTX()); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 22000); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 22000); + } - await walletdb.addTX(f1); + { + await wdb.addTX(f1.toTX()); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 11000); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 11000); - txs = await w.getHistory(); - assert(txs.some((wtx) => { - return wtx.hash === f1.hash('hex'); - })); + const txs = await alice.getHistory(); + assert(txs.some((wtx) => { + return wtx.hash === f1.hash('hex'); + })); + } - balance = await f.getBalance(); - assert.equal(balance.unconfirmed, 10000); + { + const balance = await bob.getBalance(); + assert.strictEqual(balance.unconfirmed, 10000); - txs = await f.getHistory(); - assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); - })); + const txs = await bob.getHistory(); + assert(txs.some((wtx) => { + return wtx.tx.hash('hex') === f1.hash('hex'); + })); + } }); it('should cleanup spenders after double-spend', async () => { - let w = doubleSpendWallet; - let tx, txs, total, balance; + const wallet = doubleSpendWallet; - tx = new MTX(); - tx.addCoin(doubleSpend); - tx.addOutput(w.getAddress(), 5000); + { + const txs = await wallet.getHistory(); + assert.strictEqual(txs.length, 5); - txs = await w.getHistory(); - assert.equal(txs.length, 5); - total = txs.reduce((t, wtx) => { - return t + wtx.tx.getOutputValue(); - }, 0); + const total = txs.reduce((t, wtx) => { + return t + wtx.tx.getOutputValue(); + }, 0); + assert.strictEqual(total, 154000); + } - assert.equal(total, 154000); + { + const balance = await wallet.getBalance(); + assert.strictEqual(balance.unconfirmed, 11000); + } - await w.sign(tx); - tx = tx.toTX(); + { + const tx = new MTX(); + tx.addCoin(doubleSpendCoin); + tx.addOutput(wallet.getAddress(), 5000); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 11000); + await wallet.sign(tx); - await walletdb.addTX(tx); + await wdb.addTX(tx.toTX()); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 6000); + const balance = await wallet.getBalance(); + assert.strictEqual(balance.unconfirmed, 6000); + } - txs = await w.getHistory(); - assert.equal(txs.length, 2); + { + const txs = await wallet.getHistory(); + assert.strictEqual(txs.length, 2); - total = txs.reduce((t, wtx) => { - return t + wtx.tx.getOutputValue(); - }, 0); - assert.equal(total, 56000); + const total = txs.reduce((t, wtx) => { + return t + wtx.tx.getOutputValue(); + }, 0); + assert.strictEqual(total, 56000); + } }); it('should handle missed txs without resolution', async () => { - let walletdb, w, f, t1, t2, t3, t4, f1, balance, txs; - - walletdb = new WalletDB({ + const wdb = new WalletDB({ name: 'wallet-test', db: 'memory', verify: false }); - await walletdb.open(); + await wdb.open(); - w = await walletdb.create(); - f = await walletdb.create(); + const alice = await wdb.create(); + const bob = await wdb.create(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w.getAddress(), 50000); - t1.addOutput(w.getAddress(), 1000); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 50000); + t1.addOutput(alice.getAddress(), 1000); // balance: 51000 - // await w.sign(t1); - t1 = t1.toTX(); - t2 = new MTX(); + const t2 = new MTX(); t2.addTX(t1, 0); // 50000 - t2.addOutput(w.getAddress(), 24000); - t2.addOutput(w.getAddress(), 24000); + t2.addOutput(alice.getAddress(), 24000); + t2.addOutput(alice.getAddress(), 24000); // balance: 49000 - await w.sign(t2); - t2 = t2.toTX(); - t3 = new MTX(); + await alice.sign(t2); + + const t3 = new MTX(); t3.addTX(t1, 1); // 1000 t3.addTX(t2, 0); // 24000 - t3.addOutput(w.getAddress(), 23000); + t3.addOutput(alice.getAddress(), 23000); // balance: 47000 - await w.sign(t3); - t3 = t3.toTX(); - t4 = new MTX(); + await alice.sign(t3); + + const t4 = new MTX(); t4.addTX(t2, 1); // 24000 t4.addTX(t3, 0); // 23000 - t4.addOutput(w.getAddress(), 11000); - t4.addOutput(w.getAddress(), 11000); + t4.addOutput(alice.getAddress(), 11000); + t4.addOutput(alice.getAddress(), 11000); // balance: 22000 - await w.sign(t4); - t4 = t4.toTX(); - f1 = new MTX(); - f1.addTX(t4, 1); // 11000 - f1.addOutput(f.getAddress(), 10000); + await alice.sign(t4); - // balance: 11000 - await w.sign(f1); - f1 = f1.toTX(); - - // fake = new MTX(); - // fake.addTX(t1, 1); // 1000 (already redeemed) - // fake.addOutput(w.getAddress(), 500); + const f1 = new MTX(); + f1.addTX(t4, 1); // 11000 + f1.addOutput(bob.getAddress(), 10000); - // Script inputs but do not sign - // await w.template(fake); - // Fake signature - // fake.inputs[0].script.set(0, encoding.ZERO_SIG); - // fake.inputs[0].script.compile(); // balance: 11000 - // fake = fake.toTX(); - - // Fake TX should temporarly change output - // await walletdb.addTX(fake); - - await walletdb.addTX(t4); - - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 22000); - - await walletdb.addTX(t1); + await alice.sign(f1); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 73000); - - await walletdb.addTX(t2); - - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 47000); - - await walletdb.addTX(t3); - - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 22000); + { + await wdb.addTX(t4.toTX()); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 22000); + } - await walletdb.addTX(f1); + { + await wdb.addTX(t1.toTX()); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 73000); + } - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 11000); + { + await wdb.addTX(t2.toTX()); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 47000); + } - txs = await w.getHistory(); - assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); - })); + { + await wdb.addTX(t3.toTX()); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 22000); + } - balance = await f.getBalance(); - assert.equal(balance.unconfirmed, 10000); + { + await wdb.addTX(f1.toTX()); - txs = await f.getHistory(); - assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); - })); + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 11000); - await walletdb.addTX(t2); + const txs = await alice.getHistory(); + assert(txs.some((wtx) => { + return wtx.tx.hash('hex') === f1.hash('hex'); + })); + } - await walletdb.addTX(t3); + { + const balance = await bob.getBalance(); + assert.strictEqual(balance.unconfirmed, 10000); - await walletdb.addTX(t4); + const txs = await bob.getHistory(); + assert(txs.some((wtx) => { + return wtx.tx.hash('hex') === f1.hash('hex'); + })); + } - await walletdb.addTX(f1); + await wdb.addTX(t2.toTX()); + await wdb.addTX(t3.toTX()); + await wdb.addTX(t4.toTX()); + await wdb.addTX(f1.toTX()); - balance = await w.getBalance(); - assert.equal(balance.unconfirmed, 11000); + { + const balance = await alice.getBalance(); + assert.strictEqual(balance.unconfirmed, 11000); + } - balance = await f.getBalance(); - assert.equal(balance.unconfirmed, 10000); + { + const balance = await bob.getBalance(); + assert.strictEqual(balance.unconfirmed, 10000); + } }); it('should fill tx with inputs', async () => { - let w1 = await walletdb.create(); - let w2 = await walletdb.create(); - let view, t1, t2, t3, err; + const alice = await wdb.create(); + const bob = await wdb.create(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); - t1 = t1.toTX(); - - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Create new transaction - t2 = new MTX(); - t2.addOutput(w2.getAddress(), 5460); - await w1.fund(t2, { rate: 10000, round: true }); - await w1.sign(t2); - view = t2.view; - t2 = t2.toTX(); + const m2 = new MTX(); + m2.addOutput(bob.getAddress(), 5460); + + await alice.fund(m2, { + rate: 10000, + round: true + }); + + await alice.sign(m2); + + const [t2, v2] = m2.commit(); - assert(t2.verify(view)); + assert(t2.verify(v2)); - assert.equal(t2.getInputValue(view), 16380); - assert.equal(t2.getOutputValue(), 6380); - assert.equal(t2.getFee(view), 10000); + assert.strictEqual(t2.getInputValue(v2), 16380); + assert.strictEqual(t2.getOutputValue(), 6380); + assert.strictEqual(t2.getFee(v2), 10000); // Create new transaction - t3 = new MTX(); - t3.addOutput(w2.getAddress(), 15000); + const t3 = new MTX(); + t3.addOutput(bob.getAddress(), 15000); + let err; try { - await w1.fund(t3, { rate: 10000, round: true }); + await alice.fund(t3, { + rate: 10000, + round: true + }); } catch (e) { err = e; } assert(err); - assert.equal(err.requiredFunds, 25000); + assert.strictEqual(err.requiredFunds, 25000); }); it('should fill tx with inputs with accurate fee', async () => { - let w1 = await walletdb.create({ master: KEY1 }); - let w2 = await walletdb.create({ master: KEY2 }); - let view, t1, t2, t3, balance, err; + const alice = await wdb.create({ + master: KEY1 + }); + + const bob = await wdb.create({ + master: KEY2 + }); // Coinbase - t1 = new MTX(); - t1.addInput(dummy(encoding.NULL_HASH)); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addOutpoint(new Outpoint(encoding.NULL_HASH, 0)); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Create new transaction - t2 = new MTX(); - t2.addOutput(w2.getAddress(), 5460); - await w1.fund(t2, { rate: 10000 }); + const m2 = new MTX(); + m2.addOutput(bob.getAddress(), 5460); + + await alice.fund(m2, { + rate: 10000 + }); + + await alice.sign(m2); + + const [t2, v2] = m2.commit(); - await w1.sign(t2); - view = t2.view; - t2 = t2.toTX(); - assert(t2.verify(view)); + assert(t2.verify(v2)); - assert.equal(t2.getInputValue(view), 16380); + assert.strictEqual(t2.getInputValue(v2), 16380); // Should now have a change output: - assert.equal(t2.getOutputValue(), 11130); + assert.strictEqual(t2.getOutputValue(), 11130); - assert.equal(t2.getFee(view), 5250); + assert.strictEqual(t2.getFee(v2), 5250); - assert.equal(t2.getWeight(), 2084); - assert.equal(t2.getBaseSize(), 521); - assert.equal(t2.getSize(), 521); - assert.equal(t2.getVirtualSize(), 521); + assert.strictEqual(t2.getWeight(), 2084); + assert.strictEqual(t2.getBaseSize(), 521); + assert.strictEqual(t2.getSize(), 521); + assert.strictEqual(t2.getVirtualSize(), 521); - w2.once('balance', (b) => { + let balance; + bob.once('balance', (b) => { balance = b; }); - await walletdb.addTX(t2); + await wdb.addTX(t2); // Create new transaction - t3 = new MTX(); - t3.addOutput(w2.getAddress(), 15000); + const t3 = new MTX(); + t3.addOutput(bob.getAddress(), 15000); + let err; try { - await w1.fund(t3, { rate: 10000 }); + await alice.fund(t3, { + rate: 10000 + }); } catch (e) { err = e; } assert(err); assert(balance); - assert(balance.unconfirmed === 5460); + assert.strictEqual(balance.unconfirmed, 5460); }); it('should sign multiple inputs using different keys', async () => { - let w1 = await walletdb.create(); - let w2 = await walletdb.create(); - let to = await walletdb.create(); - let t1, t2, tx, cost, total, coins1, coins2; + const alice = await wdb.create(); + const bob = await wdb.create(); + const carol = await wdb.create(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); // Coinbase - t2 = new MTX(); - t2.addInput(dummy()); - t2.addOutput(w2.getAddress(), 5460); - t2.addOutput(w2.getAddress(), 5460); - t2.addOutput(w2.getAddress(), 5460); - t2.addOutput(w2.getAddress(), 5460); - t2 = t2.toTX(); + const t2 = new MTX(); + t2.addInput(dummyInput()); + t2.addOutput(bob.getAddress(), 5460); + t2.addOutput(bob.getAddress(), 5460); + t2.addOutput(bob.getAddress(), 5460); + t2.addOutput(bob.getAddress(), 5460); - await walletdb.addTX(t1); - await walletdb.addTX(t2); + await wdb.addTX(t1.toTX()); + await wdb.addTX(t2.toTX()); // Create our tx with an output - tx = new MTX(); - tx.addOutput(to.getAddress(), 5460); + const tx = new MTX(); + tx.addOutput(carol.getAddress(), 5460); - cost = tx.getOutputValue(); - total = cost * 10000; - - coins1 = await w1.getCoins(); - coins2 = await w2.getCoins(); + const coins1 = await alice.getCoins(); + const coins2 = await bob.getCoins(); // Add our unspent inputs to sign tx.addCoin(coins1[0]); @@ -591,330 +746,234 @@ describe('Wallet', function() { tx.addCoin(coins2[0]); // Sign transaction - total = await w1.sign(tx); - assert.equal(total, 2); - - total = await w2.sign(tx); - assert.equal(total, 1); + assert.strictEqual(await alice.sign(tx), 2); + assert.strictEqual(await bob.sign(tx), 1); // Verify - assert.equal(tx.verify(), true); + assert.strictEqual(tx.verify(), true); tx.inputs.length = 0; tx.addCoin(coins1[1]); tx.addCoin(coins1[2]); tx.addCoin(coins2[1]); - total = await w1.sign(tx); - assert.equal(total, 2); - - total = await w2.sign(tx); - assert.equal(total, 1); + assert.strictEqual(await alice.sign(tx), 2); + assert.strictEqual(await bob.sign(tx), 1); // Verify - assert.equal(tx.verify(), true); + assert.strictEqual(tx.verify(), true); }); - async function testMultisig(witness, bullshitNesting, cb) { - let flags = Script.flags.STANDARD_VERIFY_FLAGS; - let rec = bullshitNesting ? 'nested' : 'receive'; - let depth = bullshitNesting ? 'nestedDepth' : 'receiveDepth'; - let options, w1, w2, w3, receive, b58; - let addr, paddr, utx, send, change; - let view, block; - - // Create 3 2-of-3 wallets with our pubkeys as "shared keys" - options = { - witness: witness, - type: 'multisig', - m: 2, - n: 3 - }; - - w1 = await walletdb.create(options); - w2 = await walletdb.create(options); - w3 = await walletdb.create(options); - receive = await walletdb.create(); - - await w1.addSharedKey(w2.account.accountKey); - await w1.addSharedKey(w3.account.accountKey); - await w2.addSharedKey(w1.account.accountKey); - await w2.addSharedKey(w3.account.accountKey); - await w3.addSharedKey(w1.account.accountKey); - await w3.addSharedKey(w2.account.accountKey); - - // Our p2sh address - b58 = w1.account[rec].getAddress('string'); - addr = Address.fromString(b58); - - if (witness) { - if (bullshitNesting) - assert.equal(addr.type, Address.types.SCRIPTHASH); - else - assert.equal(addr.type, Address.types.WITNESS); - } else { - assert.equal(addr.type, Address.types.SCRIPTHASH); - } - - assert.equal(w1.account[rec].getAddress('string'), b58); - assert.equal(w2.account[rec].getAddress('string'), b58); - assert.equal(w3.account[rec].getAddress('string'), b58); - - paddr = w1.getNested(); - - if (witness) { - assert(paddr); - assert.equal(w1.getNested('string'), paddr.toString()); - assert.equal(w2.getNested('string'), paddr.toString()); - assert.equal(w3.getNested('string'), paddr.toString()); - } - - // Add a shared unspent transaction to our wallets - utx = new MTX(); - utx.addInput(dummy()); - utx.addOutput(bullshitNesting ? paddr : addr, 5460 * 10); - utx = utx.toTX(); - - // Simulate a confirmation - block = nextBlock(); - - assert.equal(w1.account[depth], 1); - - await walletdb.addBlock(block, [utx]); - - assert.equal(w1.account[depth], 2); - - assert.equal(w1.account.changeDepth, 1); - - assert(w1.account[rec].getAddress('string') !== b58); - b58 = w1.account[rec].getAddress('string'); - assert.equal(w1.account[rec].getAddress('string'), b58); - assert.equal(w2.account[rec].getAddress('string'), b58); - assert.equal(w3.account[rec].getAddress('string'), b58); - - // Create a tx requiring 2 signatures - send = new MTX(); - send.addOutput(receive.getAddress(), 5460); - assert(!send.verify(flags)); - await w1.fund(send, { rate: 10000, round: true }); - - await w1.sign(send); - - assert(!send.verify(flags)); - - await w2.sign(send); - - view = send.view; - send = send.toTX(); - assert(send.verify(view, flags)); - - assert.equal(w1.account.changeDepth, 1); - - change = w1.account.change.getAddress('string'); - assert.equal(w1.account.change.getAddress('string'), change); - assert.equal(w2.account.change.getAddress('string'), change); - assert.equal(w3.account.change.getAddress('string'), change); - - // Simulate a confirmation - block = nextBlock(); - - await walletdb.addBlock(block, [send]); - - assert.equal(w1.account[depth], 2); - assert.equal(w1.account.changeDepth, 2); - - assert(w1.account[rec].getAddress('string') === b58); - assert(w1.account.change.getAddress('string') !== change); - change = w1.account.change.getAddress('string'); - assert.equal(w1.account.change.getAddress('string'), change); - assert.equal(w2.account.change.getAddress('string'), change); - assert.equal(w3.account.change.getAddress('string'), change); - - if (witness) { - send.inputs[0].witness.set(2, 0); - send.inputs[0].witness.compile(); - } else { - send.inputs[0].script.set(2, 0); - send.inputs[0].script.compile(); - } - - assert(!send.verify(view, flags)); - assert.equal(send.getFee(view), 10000); - } - - it('should verify 2-of-3 scripthash tx', async () => { - await testMultisig(false, false); + it('should verify 2-of-3 p2sh tx', async () => { + await testP2SH(false, false); }); - it('should verify 2-of-3 witnessscripthash tx', async () => { - await testMultisig(true, false); + it('should verify 2-of-3 p2wsh tx', async () => { + await testP2SH(true, false); }); - it('should verify 2-of-3 witnessscripthash tx with bullshit nesting', async () => { - await testMultisig(true, true); + it('should verify 2-of-3 p2wsh tx w/ nested bullshit', async () => { + await testP2SH(true, true); }); it('should fill tx with account 1', async () => { - let w1 = await walletdb.create(); - let w2 = await walletdb.create(); - let account, accounts, rec, t1, t2, t3, err; - - account = await w1.createAccount({ name: 'foo' }); - assert.equal(account.name, 'foo'); - assert.equal(account.accountIndex, 1); + const alice = await wdb.create(); + const bob = await wdb.create(); + + { + const account = await alice.createAccount({ + name: 'foo' + }); + assert.strictEqual(account.name, 'foo'); + assert.strictEqual(account.accountIndex, 1); + } - account = await w1.getAccount('foo'); - assert.equal(account.name, 'foo'); - assert.equal(account.accountIndex, 1); - rec = account.receive; + const account = await alice.getAccount('foo'); + assert.strictEqual(account.name, 'foo'); + assert.strictEqual(account.accountIndex, 1); // Coinbase - t1 = new MTX(); - t1.addOutput(rec.getAddress(), 5460); - t1.addOutput(rec.getAddress(), 5460); - t1.addOutput(rec.getAddress(), 5460); - t1.addOutput(rec.getAddress(), 5460); - - t1.addInput(dummy()); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(account.receive.getAddress(), 5460); + t1.addOutput(account.receive.getAddress(), 5460); + t1.addOutput(account.receive.getAddress(), 5460); + t1.addOutput(account.receive.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Create new transaction - t2 = new MTX(); - t2.addOutput(w2.getAddress(), 5460); - await w1.fund(t2, { rate: 10000, round: true }); - await w1.sign(t2); + const t2 = new MTX(); + t2.addOutput(bob.getAddress(), 5460); + + await alice.fund(t2, { + rate: 10000, + round: true + }); + + await alice.sign(t2); assert(t2.verify()); - assert.equal(t2.getInputValue(), 16380); - assert.equal(t2.getOutputValue(), 6380); - assert.equal(t2.getFee(), 10000); + assert.strictEqual(t2.getInputValue(), 16380); + assert.strictEqual(t2.getOutputValue(), 6380); + assert.strictEqual(t2.getFee(), 10000); // Create new transaction - t3 = new MTX(); - t3.addOutput(w2.getAddress(), 15000); + const t3 = new MTX(); + t3.addOutput(bob.getAddress(), 15000); + let err; try { - await w1.fund(t3, { rate: 10000, round: true }); + await alice.fund(t3, { + rate: 10000, + round: true + }); } catch (e) { err = e; } assert(err); - assert.equal(err.requiredFunds, 25000); + assert.strictEqual(err.requiredFunds, 25000); - accounts = await w1.getAccounts(); - assert.deepEqual(accounts, ['default', 'foo']); + const accounts = await alice.getAccounts(); + assert.deepStrictEqual(accounts, ['default', 'foo']); }); it('should fail to fill tx with account 1', async () => { - let w = await walletdb.create(); - let acc, account, t1, t2, err; - - wallet = w; - - acc = await w.createAccount({ name: 'foo' }); - assert.equal(acc.name, 'foo'); - assert.equal(acc.accountIndex, 1); + const wallet = await wdb.create(); + + { + const account = await wallet.createAccount({ + name: 'foo' + }); + assert.strictEqual(account.name, 'foo'); + assert.strictEqual(account.accountIndex, 1); + } - account = await w.getAccount('foo'); - assert.equal(account.name, 'foo'); - assert.equal(account.accountIndex, 1); - assert(account.accountKey.toBase58() === acc.accountKey.toBase58()); - assert(w.account.accountIndex === 0); + const account = await wallet.getAccount('foo'); + assert.strictEqual(account.name, 'foo'); + assert.strictEqual(account.accountIndex, 1); + assert.strictEqual(wallet.account.accountIndex, 0); - assert.notEqual( - account.receive.getAddress('string'), - w.account.receive.getAddress('string')); + assert(!account.receive.getAddress().equals( + wallet.account.receive.getAddress())); - assert.equal(w.getAddress('string'), - w.account.receive.getAddress('string')); + assert(wallet.getAddress().equals(wallet.account.receive.getAddress())); // Coinbase - t1 = new MTX(); - t1.addOutput(w.getAddress(), 5460); - t1.addOutput(w.getAddress(), 5460); - t1.addOutput(w.getAddress(), 5460); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(wallet.getAddress(), 5460); + t1.addOutput(wallet.getAddress(), 5460); + t1.addOutput(wallet.getAddress(), 5460); t1.addOutput(account.receive.getAddress(), 5460); - t1.addInput(dummy()); - t1 = t1.toTX(); - - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Should fill from `foo` and fail - t2 = new MTX(); - t2.addOutput(w.getAddress(), 5460); + const t2 = new MTX(); + + t2.addOutput(wallet.getAddress(), 5460); + + let err; try { - await w.fund(t2, { rate: 10000, round: true, account: 'foo' }); + await wallet.fund(t2, { + rate: 10000, + round: true, + account: 'foo' + }); } catch (e) { err = e; } + assert(err); // Should fill from whole wallet and succeed - t2 = new MTX(); - t2.addOutput(w.getAddress(), 5460); - await w.fund(t2, { rate: 10000, round: true }); + const t3 = new MTX(); + t3.addOutput(wallet.getAddress(), 5460); + + await wallet.fund(t3, { + rate: 10000, + round: true + }); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(account.receive.getAddress(), 5460); - t1.addOutput(account.receive.getAddress(), 5460); - t1.addOutput(account.receive.getAddress(), 5460); - t1 = t1.toTX(); + const t4 = new MTX(); + t4.addInput(dummyInput()); + t4.addOutput(account.receive.getAddress(), 5460); + t4.addOutput(account.receive.getAddress(), 5460); + t4.addOutput(account.receive.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t4.toTX()); // Should fill from `foo` and succeed - t2 = new MTX(); - t2.addOutput(w.getAddress(), 5460); - await w.fund(t2, { rate: 10000, round: true, account: 'foo' }); + const t5 = new MTX(); + t5.addOutput(wallet.getAddress(), 5460); + + await wallet.fund(t5, { + rate: 10000, + round: true, + account: 'foo' + }); + + currentWallet = wallet; }); it('should create two accounts (multiple encryption)', async () => { - let w = await walletdb.create({ id: 'foobar', passphrase: 'foo' }); - let account; + { + const wallet = await wdb.create({ + id: 'foobar', + passphrase: 'foo' + }); + await wallet.destroy(); + } - await w.destroy(); + const wallet = await wdb.get('foobar'); + assert(wallet); - w = await walletdb.get('foobar'); + const options = { + name: 'foo1' + }; + + const account = await wallet.createAccount(options, 'foo'); - account = await w.createAccount({ name: 'foo1' }, 'foo'); assert(account); - await w.lock(); + await wallet.lock(); }); it('should fill tx with inputs when encrypted', async () => { - let w = await walletdb.create({ passphrase: 'foo' }); - let t1, t2, err; + const wallet = await wdb.create({ + passphrase: 'foo' + }); - w.master.stop(); - w.master.key = null; + wallet.master.stop(); + wallet.master.key = null; // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w.getAddress(), 5460); - t1.addOutput(w.getAddress(), 5460); - t1.addOutput(w.getAddress(), 5460); - t1.addOutput(w.getAddress(), 5460); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(wallet.getAddress(), 5460); + t1.addOutput(wallet.getAddress(), 5460); + t1.addOutput(wallet.getAddress(), 5460); + t1.addOutput(wallet.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Create new transaction - t2 = new MTX(); - t2.addOutput(w.getAddress(), 5460); - await w.fund(t2, { rate: 10000, round: true }); + const t2 = new MTX(); + t2.addOutput(wallet.getAddress(), 5460); + + await wallet.fund(t2, { + rate: 10000, + round: true + }); // Should fail + let err; try { - await w.sign(t2, 'bar'); + await wallet.sign(t2, 'bar'); } catch (e) { err = e; } @@ -923,467 +982,504 @@ describe('Wallet', function() { assert(!t2.verify()); // Should succeed - await w.sign(t2, 'foo'); + await wallet.sign(t2, 'foo'); assert(t2.verify()); }); it('should fill tx with inputs with subtract fee (1)', async () => { - let w1 = await walletdb.create(); - let w2 = await walletdb.create(); - let t1, t2; + const alice = await wdb.create(); + const bob = await wdb.create(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Create new transaction - t2 = new MTX(); - t2.addOutput(w2.getAddress(), 21840); - await w1.fund(t2, { rate: 10000, round: true, subtractFee: true }); - await w1.sign(t2); + const t2 = new MTX(); + t2.addOutput(bob.getAddress(), 21840); + + await alice.fund(t2, { + rate: 10000, + round: true, + subtractFee: true + }); + + await alice.sign(t2); assert(t2.verify()); - assert.equal(t2.getInputValue(), 5460 * 4); - assert.equal(t2.getOutputValue(), 21840 - 10000); - assert.equal(t2.getFee(), 10000); + assert.strictEqual(t2.getInputValue(), 5460 * 4); + assert.strictEqual(t2.getOutputValue(), 21840 - 10000); + assert.strictEqual(t2.getFee(), 10000); }); it('should fill tx with inputs with subtract fee (2)', async () => { - let w1 = await walletdb.create(); - let w2 = await walletdb.create(); - let options, t1, t2; + const alice = await wdb.create(); + const bob = await wdb.create(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); - options = { + const options = { subtractFee: true, rate: 10000, round: true, - outputs: [{ address: w2.getAddress(), value: 21840 }] + outputs: [{ address: bob.getAddress(), value: 21840 }] }; // Create new transaction - t2 = await w1.createTX(options); - await w1.sign(t2); + const t2 = await alice.createTX(options); + await alice.sign(t2); assert(t2.verify()); - assert.equal(t2.getInputValue(), 5460 * 4); - assert.equal(t2.getOutputValue(), 21840 - 10000); - assert.equal(t2.getFee(), 10000); + assert.strictEqual(t2.getInputValue(), 5460 * 4); + assert.strictEqual(t2.getOutputValue(), 21840 - 10000); + assert.strictEqual(t2.getFee(), 10000); }); it('should fill tx with smart coin selection', async () => { - let w1 = await walletdb.create(); - let w2 = await walletdb.create(); - let found = false; - let total = 0; - let i, options, t1, t2, t3, block, coins, coin; + const alice = await wdb.create(); + const bob = await wdb.create(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1.addOutput(w1.getAddress(), 5460); - t1 = t1.toTX(); + const t1 = new MTX(); + t1.addInput(dummyInput()); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); + t1.addOutput(alice.getAddress(), 5460); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); // Coinbase - t2 = new MTX(); - t2.addInput(dummy()); - t2.addOutput(w1.getAddress(), 5460); - t2.addOutput(w1.getAddress(), 5460); - t2.addOutput(w1.getAddress(), 5460); - t2.addOutput(w1.getAddress(), 5460); - t2 = t2.toTX(); + const t2 = new MTX(); + t2.addInput(dummyInput()); + t2.addOutput(alice.getAddress(), 5460); + t2.addOutput(alice.getAddress(), 5460); + t2.addOutput(alice.getAddress(), 5460); + t2.addOutput(alice.getAddress(), 5460); - block = nextBlock(); + const block = nextBlock(); - await walletdb.addBlock(block, [t2]); + await wdb.addBlock(block, [t2.toTX()]); - coins = await w1.getSmartCoins(); - assert.equal(coins.length, 4); + { + const coins = await alice.getSmartCoins(); + assert.strictEqual(coins.length, 4); - for (i = 0; i < coins.length; i++) { - coin = coins[i]; - assert.equal(coin.height, block.height); + for (let i = 0; i < coins.length; i++) { + const coin = coins[i]; + assert.strictEqual(coin.height, block.height); + } } // Create a change output for ourselves. - await w1.send({ + await alice.send({ subtractFee: true, rate: 1000, depth: 1, - outputs: [{ address: w2.getAddress(), value: 1461 }] + outputs: [{ address: bob.getAddress(), value: 1461 }] }); - coins = await w1.getSmartCoins(); - assert.equal(coins.length, 4); - - for (i = 0; i < coins.length; i++) { - coin = coins[i]; - if (coin.height === -1) { - assert(!found); - assert(coin.value < 5460); - found = true; - } else { - assert.equal(coin.height, block.height); + const coins = await alice.getSmartCoins(); + assert.strictEqual(coins.length, 4); + + let total = 0; + + { + let found = false; + + for (let i = 0; i < coins.length; i++) { + const coin = coins[i]; + if (coin.height === -1) { + assert(!found); + assert(coin.value < 5460); + found = true; + } else { + assert.strictEqual(coin.height, block.height); + } + total += coin.value; } - total += coin.value; - } - assert(found); + assert(found); + } // Use smart selection - options = { + const options = { subtractFee: true, smart: true, rate: 10000, - outputs: [{ address: w2.getAddress(), value: total }] + outputs: [{ + address: bob.getAddress(), + value: total + }] }; - t3 = await w1.createTX(options); - assert.equal(t3.inputs.length, 4); - - found = false; - for (i = 0; i < t3.inputs.length; i++) { - coin = t3.view.getCoin(t3.inputs[i]); - if (coin.height === -1) { - assert(!found); - assert(coin.value < 5460); - found = true; - } else { - assert.equal(coin.height, block.height); + const t3 = await alice.createTX(options); + assert.strictEqual(t3.inputs.length, 4); + + { + let found = false; + + for (let i = 0; i < t3.inputs.length; i++) { + const coin = t3.view.getCoinFor(t3.inputs[i]); + if (coin.height === -1) { + assert(!found); + assert(coin.value < 5460); + found = true; + } else { + assert.strictEqual(coin.height, block.height); + } } - } - assert(found); + assert(found); + } - await w1.sign(t3); + await alice.sign(t3); assert(t3.verify()); }); it('should get range of txs', async () => { - let w = wallet; - let txs = await w.getRange({ start: util.now() - 1000 }); - assert.equal(txs.length, 2); + const wallet = currentWallet; + const txs = await wallet.getRange({ + start: util.now() - 1000 + }); + assert.strictEqual(txs.length, 2); }); it('should get range of txs from account', async () => { - let w = wallet; - let txs = await w.getRange('foo', { start: util.now() - 1000 }); - assert.equal(txs.length, 2); + const wallet = currentWallet; + const txs = await wallet.getRange('foo', { + start: util.now() - 1000 + }); + assert.strictEqual(txs.length, 2); }); it('should not get range of txs from non-existent account', async () => { - let w = wallet; - let txs, err; + const wallet = currentWallet; + let txs, err; try { - txs = await w.getRange('bad', { start: 0xdeadbeef - 1000 }); + txs = await wallet.getRange('bad', { + start: 0xdeadbeef - 1000 + }); } catch (e) { err = e; } assert(!txs); assert(err); - assert.equal(err.message, 'Account not found.'); + assert.strictEqual(err.message, 'Account not found.'); }); it('should get account balance', async () => { - let w = wallet; - let balance = await w.getBalance('foo'); - assert.equal(balance.unconfirmed, 21840); + const wallet = currentWallet; + const balance = await wallet.getBalance('foo'); + assert.strictEqual(balance.unconfirmed, 21840); }); it('should import privkey', async () => { - let key = KeyRing.generate(); - let w = await walletdb.create({ passphrase: 'test' }); - let options, k, t1, t2, wtx; + const key = KeyRing.generate(); - await w.importKey('default', key, 'test'); + const wallet = await wdb.create({ + passphrase: 'test' + }); + + await wallet.importKey('default', key, 'test'); - k = await w.getKey(key.getHash('hex')); + const wkey = await wallet.getKey(key.getHash('hex')); - assert.equal(k.getHash('hex'), key.getHash('hex')); + assert.strictEqual(wkey.getHash('hex'), key.getHash('hex')); // Coinbase - t1 = new MTX(); + const t1 = new MTX(); t1.addOutput(key.getAddress(), 5460); t1.addOutput(key.getAddress(), 5460); t1.addOutput(key.getAddress(), 5460); t1.addOutput(key.getAddress(), 5460); - t1.addInput(dummy()); - t1 = t1.toTX(); + t1.addInput(dummyInput()); - await walletdb.addTX(t1); + await wdb.addTX(t1.toTX()); - wtx = await w.getTX(t1.hash('hex')); + const wtx = await wallet.getTX(t1.hash('hex')); assert(wtx); - assert.equal(t1.hash('hex'), wtx.hash); + assert.strictEqual(t1.hash('hex'), wtx.hash); - options = { + const options = { rate: 10000, round: true, - outputs: [{ address: w.getAddress(), value: 7000 }] + outputs: [{ + address: wallet.getAddress(), + value: 7000 + }] }; // Create new transaction - t2 = await w.createTX(options); - await w.sign(t2); + const t2 = await wallet.createTX(options); + await wallet.sign(t2); assert(t2.verify()); - assert(t2.inputs[0].prevout.hash === wtx.hash); + assert.strictEqual(t2.inputs[0].prevout.hash, wtx.hash); - ewallet = w; - ekey = key; + importedWallet = wallet; + importedKey = key; }); it('should import pubkey', async () => { - let priv = KeyRing.generate(); - let key = new KeyRing(priv.publicKey); - let w = await walletdb.create({ watchOnly: true }); - let k; + const key = KeyRing.generate(); + const pub = new KeyRing(key.publicKey); - await w.importKey('default', key); + const wallet = await wdb.create({ + watchOnly: true + }); - k = await w.getPath(key.getHash('hex')); + await wallet.importKey('default', pub); - assert.equal(k.hash, key.getHash('hex')); + const path = await wallet.getPath(pub.getHash('hex')); + assert.strictEqual(path.hash, pub.getHash('hex')); - k = await w.getKey(key.getHash('hex')); - assert(k); + const wkey = await wallet.getKey(pub.getHash('hex')); + assert(wkey); }); it('should import address', async () => { - let key = KeyRing.generate(); - let w = await walletdb.create({ watchOnly: true }); - let k; + const key = KeyRing.generate(); - await w.importAddress('default', key.getAddress()); + const wallet = await wdb.create({ + watchOnly: true + }); - k = await w.getPath(key.getHash('hex')); + await wallet.importAddress('default', key.getAddress()); - assert.equal(k.hash, key.getHash('hex')); + const path = await wallet.getPath(key.getHash('hex')); + assert(path); + assert.strictEqual(path.hash, key.getHash('hex')); - k = await w.getKey(key.getHash('hex')); - assert(!k); + const wkey = await wallet.getKey(key.getHash('hex')); + assert(!wkey); }); it('should get details', async () => { - let w = wallet; - let txs = await w.getRange('foo', { start: util.now() - 1000 }); - let details = await w.toDetails(txs); + const wallet = currentWallet; + + const txs = await wallet.getRange('foo', { + start: util.now() - 1000 + }); + + const details = await wallet.toDetails(txs); + assert(details.some((tx) => { return tx.toJSON().outputs[0].path.name === 'foo'; })); }); it('should rename wallet', async () => { - let w = wallet; + const wallet = currentWallet; + await wallet.rename('test'); - let txs = await w.getRange('foo', { start: util.now() - 1000 }); - let details = await w.toDetails(txs); - assert.equal(details[0].toJSON().id, 'test'); - }); - it('should change passphrase with encrypted imports', async () => { - let w = ewallet; - let addr = ekey.getAddress(); - let path, d1, d2, k; + const txs = await wallet.getRange('foo', { + start: util.now() - 1000 + }); - assert(w.master.encrypted); + const details = await wallet.toDetails(txs); - path = await w.getPath(addr); - assert(path); - assert(path.data && path.encrypted); - d1 = path.data; + assert.strictEqual(details[0].toJSON().id, 'test'); + }); - await w.decrypt('test'); + it('should change passphrase with encrypted imports', async () => { + const wallet = importedWallet; + const addr = importedKey.getAddress(); - path = await w.getPath(addr); - assert(path); - assert(path.data && !path.encrypted); + assert(wallet.master.encrypted); - k = await w.getKey(addr); - assert(k); + let data; + { + const path = await wallet.getPath(addr); + assert(path); + assert(path.data && path.encrypted); + data = path.data; + } - await w.encrypt('foo'); + await wallet.decrypt('test'); - path = await w.getPath(addr); - assert(path); - assert(path.data && path.encrypted); - d2 = path.data; + { + const path = await wallet.getPath(addr); + assert(path); + assert(path.data && !path.encrypted); + assert(await wallet.getKey(addr)); + } + + await wallet.encrypt('foo'); - assert(!d1.equals(d2)); + { + const path = await wallet.getPath(addr); + assert(path); + assert(path.data && path.encrypted); + assert(!data.equals(path.data)); + assert(!await wallet.getKey(addr)); + } - k = await w.getKey(addr); - assert(!k); + await wallet.unlock('foo'); - await w.unlock('foo'); - k = await w.getKey(addr); - assert(k); - assert.equal(k.getHash('hex'), addr.getHash('hex')); + const key = await wallet.getKey(addr); + assert(key); + assert.strictEqual(key.getHash('hex'), addr.getHash('hex')); }); it('should recover from a missed tx', async () => { - let walletdb, alice, addr, bob, t1, t2, t3; - - walletdb = new WalletDB({ + const wdb = new WalletDB({ name: 'wallet-test', db: 'memory', verify: false }); - await walletdb.open(); + await wdb.open(); - alice = await walletdb.create({ master: KEY1 }); - bob = await walletdb.create({ master: KEY1 }); - addr = alice.getAddress(); + const alice = await wdb.create({ + master: KEY1 + }); + + const bob = await wdb.create({ + master: KEY1 + }); + + const addr = alice.getAddress(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); + const t1 = new MTX(); + t1.addInput(dummyInput()); t1.addOutput(addr, 50000); - t1 = t1.toTX(); - await alice.add(t1); - await bob.add(t1); + await alice.add(t1.toTX()); + await bob.add(t1.toTX()); // Bob misses this tx! - t2 = new MTX(); + const t2 = new MTX(); t2.addTX(t1, 0); t2.addOutput(addr, 24000); t2.addOutput(addr, 24000); await alice.sign(t2); - t2 = t2.toTX(); - await alice.add(t2); + await alice.add(t2.toTX()); - assert.notEqual( + assert.notStrictEqual( (await alice.getBalance()).unconfirmed, (await bob.getBalance()).unconfirmed); // Bob sees this one. - t3 = new MTX(); + const t3 = new MTX(); t3.addTX(t2, 0); t3.addTX(t2, 1); t3.addOutput(addr, 30000); await alice.sign(t3); - t3 = t3.toTX(); - assert.equal((await bob.getBalance()).unconfirmed, 50000); + assert.strictEqual((await bob.getBalance()).unconfirmed, 50000); - await alice.add(t3); - await bob.add(t3); + await alice.add(t3.toTX()); + await bob.add(t3.toTX()); - assert.equal((await alice.getBalance()).unconfirmed, 30000); + assert.strictEqual((await alice.getBalance()).unconfirmed, 30000); // Bob sees t2 on the chain. - await bob.add(t2); + await bob.add(t2.toTX()); // Bob sees t3 on the chain. - await bob.add(t3); + await bob.add(t3.toTX()); - assert.equal((await bob.getBalance()).unconfirmed, 30000); + assert.strictEqual((await bob.getBalance()).unconfirmed, 30000); }); it('should recover from a missed tx and double spend', async () => { - let walletdb, alice, addr, bob, t1, t2, t3, t2a; - - walletdb = new WalletDB({ + const wdb = new WalletDB({ name: 'wallet-test', db: 'memory', verify: false }); - await walletdb.open(); + await wdb.open(); + + const alice = await wdb.create({ + master: KEY1 + }); + + const bob = await wdb.create({ + master: KEY1 + }); - alice = await walletdb.create({ master: KEY1 }); - bob = await walletdb.create({ master: KEY1 }); - addr = alice.getAddress(); + const addr = alice.getAddress(); // Coinbase - t1 = new MTX(); - t1.addInput(dummy()); + const t1 = new MTX(); + t1.addInput(dummyInput()); t1.addOutput(addr, 50000); - t1 = t1.toTX(); - await alice.add(t1); - await bob.add(t1); + await alice.add(t1.toTX()); + await bob.add(t1.toTX()); // Bob misses this tx! - t2 = new MTX(); - t2.addTX(t1, 0); - t2.addOutput(addr, 24000); - t2.addOutput(addr, 24000); + const t2a = new MTX(); + t2a.addTX(t1, 0); + t2a.addOutput(addr, 24000); + t2a.addOutput(addr, 24000); - await alice.sign(t2); - t2 = t2.toTX(); + await alice.sign(t2a); - await alice.add(t2); + await alice.add(t2a.toTX()); - assert.notEqual( + assert.notStrictEqual( (await alice.getBalance()).unconfirmed, (await bob.getBalance()).unconfirmed); // Bob doublespends. - t2a = new MTX(); - t2a.addTX(t1, 0); - t2a.addOutput(addr, 10000); - t2a.addOutput(addr, 10000); + const t2b = new MTX(); + t2b.addTX(t1, 0); + t2b.addOutput(addr, 10000); + t2b.addOutput(addr, 10000); - await bob.sign(t2a); - t2a = t2a.toTX(); + await bob.sign(t2b); - await bob.add(t2a); + await bob.add(t2b.toTX()); // Bob sees this one. - t3 = new MTX(); - t3.addTX(t2, 0); - t3.addTX(t2, 1); + const t3 = new MTX(); + t3.addTX(t2a, 0); + t3.addTX(t2a, 1); t3.addOutput(addr, 30000); await alice.sign(t3); - t3 = t3.toTX(); - assert.equal((await bob.getBalance()).unconfirmed, 20000); + assert.strictEqual((await bob.getBalance()).unconfirmed, 20000); - await alice.add(t3); - await bob.add(t3); + await alice.add(t3.toTX()); + await bob.add(t3.toTX()); - assert.equal((await alice.getBalance()).unconfirmed, 30000); + assert.strictEqual((await alice.getBalance()).unconfirmed, 30000); - // Bob sees t2 on the chain. - await bob.add(t2); + // Bob sees t2a on the chain. + await bob.add(t2a.toTX()); // Bob sees t3 on the chain. - await bob.add(t3); + await bob.add(t3.toTX()); - assert.equal((await bob.getBalance()).unconfirmed, 30000); + assert.strictEqual((await bob.getBalance()).unconfirmed, 30000); }); it('should cleanup', () => { diff --git a/webpack.browser.js b/webpack.browser.js index d5bded287..7579f8704 100644 --- a/webpack.browser.js +++ b/webpack.browser.js @@ -1,6 +1,6 @@ 'use strict'; -const webpack = require('webpack') +const webpack = require('webpack'); const path = require('path'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const str = JSON.stringify; diff --git a/webpack.compat.js b/webpack.compat.js index 207aed8de..26a352675 100644 --- a/webpack.compat.js +++ b/webpack.compat.js @@ -1,7 +1,8 @@ 'use strict'; -const webpack = require('webpack') +const webpack = require('webpack'); const path = require('path'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const str = JSON.stringify; const env = process.env; @@ -33,7 +34,7 @@ module.exports = { 'process.env.BCOIN_WORKER_FILE': str(env.BCOIN_WORKER_FILE || '/bcoin-worker.js') }), - new webpack.optimize.UglifyJsPlugin({ + new UglifyJsPlugin({ compress: { warnings: false } diff --git a/webpack.node.js b/webpack.node.js index d27705063..110ce7231 100644 --- a/webpack.node.js +++ b/webpack.node.js @@ -1,6 +1,6 @@ 'use strict'; -const webpack = require('webpack') +const webpack = require('webpack'); const path = require('path'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const str = JSON.stringify;