diff --git a/test/coin-test.js b/test/coin-test.js index c6e25a8ff..857bd17ef 100644 --- a/test/coin-test.js +++ b/test/coin-test.js @@ -48,4 +48,34 @@ describe('Coin', function() { assert(fmt.includes('coinbase')); assert(fmt.includes('script')); }); + + it('should throw error for invalid input raw data', () => { + let error; + try { + Coin.fromRaw(Buffer.from([])); + } catch (e) { + error = e; + } + + assert(error instanceof Error); + assert.strictEqual(error.message, 'Out of bounds read (offset=0).'); + }); + + it('should return expected txid', () => { + const [tx] = tx1.getTX(); + const coin = Coin.fromTX(tx, 0, 0); + assert.strictEqual(coin.txid(), 'ff80fe4937e2de16411c3a2bc534d661dc8b4f8aad75e6fbc4b1ec6060d9ef1c'); + }); + + it('should return expected type', () => { + const [tx] = tx1.getTX(); + const coin = Coin.fromTX(tx, 0, 0); + assert.strictEqual(coin.getType(), 'multisig'); + }); + + it('should return expected address', () => { + const [tx] = tx1.getTX(); + const coin = Coin.fromTX(tx, 0, 0); + assert.strictEqual(coin.getAddress().toString(), '3KUER9kZ693d5FQgvmr5qNDKnSpP9nXv9v'); + }); }); diff --git a/test/coins-test.js b/test/coins-test.js index 7e3f48dbe..0c2737021 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -99,4 +99,32 @@ describe('Coins', function() { assert.strictEqual(coins.get(0), null); deepCoinsEqual(coins.get(1), reserialize(coins.get(1))); }); + + it('should spend multiple outputs from a single transaction', () => { + const [tx, view] = tx1.getTX(); + + view.addTX(tx, 1); + + const hash = tx.hash(); + const coins = view.get(hash); + + view.spendEntry(new Outpoint(hash, 0)); + view.spendEntry(new Outpoint(hash, 1)); + + assert.strictEqual(coins.get(0).spent, true); + assert.strictEqual(coins.get(1).spent, true); + assert.strictEqual(view.undo.items.length, 2); + }); + + it('should handle serialization and deserialization of the coin view', () => { + const [tx, view] = tx1.getTX(); + + const size = view.getSize(tx); + const bw = bio.write(size); + const raw = view.toWriter(bw, tx).render(); + const br = bio.read(raw); + const res = CoinView.fromReader(br, tx); + + assert.deepStrictEqual(view, res); + }); }); diff --git a/test/consensus-test.js b/test/consensus-test.js index 03503d442..f92c4739d 100644 --- a/test/consensus-test.js +++ b/test/consensus-test.js @@ -64,4 +64,90 @@ describe('Consensus', function() { assert(consensus.hasBit(0x20000003, 1)); assert(consensus.hasBit(0x20000003, 0)); }); + + it('should calculate block reward properly', () => { + let height = 0; + const reward = consensus.getReward(height, 210000); + assert.strictEqual(reward, 50 * consensus.COIN); + height = 210000; + const reward2 = consensus.getReward(height, 210000); + assert.strictEqual(reward2, 25 * consensus.COIN); + }); + + it('should throw an error for invalid height', () => { + assert.throws(() => { + consensus.getReward(-100, 210000); + }, /Bad height for reward./); + }); + + it('should return false for invalid proof-of-work', () => { + const bits = 0x1900896c; + const hash = Buffer.from( + '672b3f1bb11a994267ea4171069ba0aa4448a840f38e8f340000000000000001', + 'hex'); + assert.strictEqual(consensus.verifyPOW(hash, bits), false); + }); + + it('should return correct reward amount at given height and reward interval', () => { + const height = 210000; + const rewardInterval = 210000; + const expectedReward = 25 * consensus.COIN; + + const reward = consensus.getReward(height, rewardInterval); + + assert.strictEqual(reward, expectedReward); + }); + + it('should correctly determine whether a given version number contains a specific bit', () => { + const version = 0x20000001; + const bit = 0; + const expectedResult = true; + + const result = consensus.hasBit(version, bit); + + assert.strictEqual(result, expectedResult); + }); + + it('should correctly convert target to compact representation of target', () => { + const target = new BN( + '0000000000000000896c00000000000000000000000000000000000000000000', + 'hex'); + const expectedCompact = 0x1900896c; + + const compact = consensus.toCompact(target); + + assert.strictEqual(compact, expectedCompact); + }); + + it('should correctly verify proof of work', () => { + const hash = Buffer.from( + '672b3f1bb11a994267ea4171069ba0aa4448a840f38e8f340000000000000000', + 'hex' + ); + const bits = 0x1900896c; + const expectedResult = true; + + const result = consensus.verifyPOW(hash, bits); + + assert.strictEqual(result, expectedResult); + }); + + it('should correctly return total reward for all blocks until the reward becomes zero', () => { + let height = 0; + let total = 0; + + for (;;) { + const reward = consensus.getReward(height, 210000); + total += reward; + if (reward === 0) + break; + height++; + } + + const expectedHeight = 6930000; + const expectedTotal = 2099999997690000; + + assert.strictEqual(height, expectedHeight); + assert.strictEqual(total, expectedTotal); + }); }); diff --git a/test/gcs-test.js b/test/gcs-test.js index f3f566671..1bf6697c0 100644 --- a/test/gcs-test.js +++ b/test/gcs-test.js @@ -170,4 +170,14 @@ describe('GCS', function () { match = filter2.matchAny(key, contents); assert(match); }); + + it('should test toBytes', () => { + const filterBytes = filter1.toBytes(); + assert(filterBytes instanceof Buffer); + }); + + it('should test toNBytes', () => { + const filterNBytes = filter1.toNBytes(); + assert(filterNBytes instanceof Buffer); + }); }); diff --git a/test/headers-test.js b/test/headers-test.js index 338283bf0..7ebf4130a 100644 --- a/test/headers-test.js +++ b/test/headers-test.js @@ -55,4 +55,20 @@ describe('Headers', function() { assert(headers.verifyBody()); assert(headers.verifyPOW()); }); + + it('should match raw headers from headers', () => { + const headers = new Headers(); + headers.time = 1231469665; + headers.bits = 486604799; + headers.nonce = 2573394689; + headers.version = 1; + headers.prevBlock = Buffer.from( + '6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000', + 'hex'); + headers.merkleRoot = Buffer.from( + '982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e', + 'hex'); + + assert.bufferEqual(headers.toRaw(), headers1); + }); }); diff --git a/test/mnemonic-test.js b/test/mnemonic-test.js index b0e670df1..1e3b6134a 100644 --- a/test/mnemonic-test.js +++ b/test/mnemonic-test.js @@ -64,4 +64,22 @@ describe('Mnemonic', function() { assert.strictEqual(m2.language, m1.language); assert.bufferEqual(m2.toSeed(), m1.toSeed()); }); + + it('should create different seed with different passphrase', () => { + const mnemonic = new Mnemonic(); + const seed1 = mnemonic.toSeed(); + const seed2 = mnemonic.toSeed('different passphrase'); + assert.notDeepEqual(seed1, seed2); + }); + + it('should create a mnemonic in French', () => { + const mnemonic = new Mnemonic({language: 'french'}); + assert.strictEqual(mnemonic.language, 'french'); + }); + + it('should create an HD Private Key from a mnemonic with no passphrase', () => { + const mnemonic = new Mnemonic(); + const key = HDPrivateKey.fromMnemonic(mnemonic); + assert.strictEqual(key.depth, 0); + }); }); diff --git a/test/mtx-test.js b/test/mtx-test.js index 7b885012c..965df40b5 100644 --- a/test/mtx-test.js +++ b/test/mtx-test.js @@ -40,4 +40,54 @@ describe('MTX', function () { const mtx2 = MTX.fromRaw(mtx1.toRaw()); assert.deepStrictEqual(mtx1, mtx2); }); + + it('should encode and decode mtx with multiple inputs and outputs', () => { + const input1 = new Input({ + prevout: { + hash: Buffer.alloc(32), + index: 0 + } + }); + const input2 = new Input({ + prevout: { + hash: Buffer.alloc(32), + index: 1 + } + }); + const output1 = new Output({ + value: 1e8, + address: new Address() + }); + const output2 = new Output({ + value: 2e8, + address: new Address() + }); + const mtx1 = new MTX({ + inputs: [input1, input2], + outputs: [output1, output2] + }); + const mtx2 = MTX.fromRaw(mtx1.toRaw()); + assert.deepStrictEqual(mtx1, mtx2); + }); + + it('should encode and decode mtx with segwit inputs and outputs', () => { + const input = new Input({ + prevout: { + hash: Buffer.alloc(32), + index: 0 + }, + witness: [Buffer.alloc(4)] + }); + const output = new Output({ + value: 1e8, + address: new Address(), + script: Buffer.alloc(4) + }); + const mtx1 = new MTX({ + inputs: [input], + outputs: [output] + }); + const mtx2 = MTX.fromRaw(mtx1.toRaw()); + assert.deepStrictEqual(mtx1, mtx2); + }); }); diff --git a/test/pow-test.js b/test/pow-test.js index 5c780cf2e..51c02ded8 100644 --- a/test/pow-test.js +++ b/test/pow-test.js @@ -72,6 +72,27 @@ describe('Difficulty', function() { assert.strictEqual(chain.retarget(prev, first), 0x1d00e1fd); }); + it('should test retarget with a range of inputs', async () => { + // Create an array of test cases + const testCases = [ + { prevTime: 1262152739, prevBits: 0x1d00ffff, firstTime: 1261130161, expected: 0x1d00d86a }, + { prevTime: 1233061996, prevBits: 0x1d00ffff, firstTime: 1231006505, expected: 0x1d00ffff }, + { prevTime: 1279297671, prevBits: 0x1c05a3f4, firstTime: 1279008237, expected: 0x1c0168fd }, + { prevTime: 1269211443, prevBits: 0x1c387f6f, firstTime: 1263163443, expected: 0x1d00e1fd } + ]; + + // Iterate through the test cases and check the output of the retarget function + for (const testCase of testCases) { + const prev = new ChainEntry(); + prev.time = testCase.prevTime; + prev.bits = testCase.prevBits; + prev.height = 32255; + const first = new ChainEntry(); + first.time = testCase.firstTime; + assert.strictEqual(chain.retarget(prev, first), testCase.expected); + } + }); + it('should get block proof equivalent time', async () => { const blocks = []; for (let i = 0; i < 10000; i++) {