From 49dfb96f295913f29a8530bcd64e08a05c7af093 Mon Sep 17 00:00:00 2001 From: Suyash Nayan Date: Sun, 29 Jan 2023 12:34:35 +0530 Subject: [PATCH 1/3] test: added more coverage to tests --- test/coin-test.js | 30 +++++++++++++++ test/coins-test.js | 29 ++++++++++++++ test/consensus-test.js | 86 ++++++++++++++++++++++++++++++++++++++++++ test/gcs-test.js | 10 +++++ test/headers-test.js | 16 ++++++++ test/mnemonic-test.js | 18 +++++++++ test/mtx-test.js | 50 ++++++++++++++++++++++++ test/pow-test.js | 21 +++++++++++ 8 files changed, 260 insertions(+) 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..22ac9b63c 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -99,4 +99,33 @@ 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..9a4958c4f 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..209e8829d 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..ed3d0b453 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..cdbf6a343 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..de55976bd 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++) { From 66ba459e09e60175fc37a0012fbd4a4634c665d8 Mon Sep 17 00:00:00 2001 From: Suyash Nayan Date: Sun, 29 Jan 2023 15:30:56 +0530 Subject: [PATCH 2/3] fix linting errors --- test/coins-test.js | 17 ++++++++--------- test/consensus-test.js | 4 ++-- test/gcs-test.js | 6 +++--- test/headers-test.js | 6 +++--- test/mtx-test.js | 6 +++--- test/pow-test.js | 4 ++-- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/test/coins-test.js b/test/coins-test.js index 22ac9b63c..95628ed83 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -102,30 +102,29 @@ describe('Coins', function() { 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); }); - -}); +}); \ No newline at end of file diff --git a/test/consensus-test.js b/test/consensus-test.js index 9a4958c4f..63a6fe9d9 100644 --- a/test/consensus-test.js +++ b/test/consensus-test.js @@ -79,7 +79,7 @@ describe('Consensus', function() { consensus.getReward(-100, 210000); }, /Bad height for reward./); }); - + it('should return false for invalid proof-of-work', () => { const bits = 0x1900896c; const hash = Buffer.from( @@ -150,4 +150,4 @@ describe('Consensus', function() { assert.strictEqual(height, expectedHeight); assert.strictEqual(total, expectedTotal); }); -}); +}); \ No newline at end of file diff --git a/test/gcs-test.js b/test/gcs-test.js index 209e8829d..a797eed5c 100644 --- a/test/gcs-test.js +++ b/test/gcs-test.js @@ -175,9 +175,9 @@ describe('GCS', function () { const filterBytes = filter1.toBytes(); assert(filterBytes instanceof Buffer); }); - + it('should test toNBytes', () => { const filterNBytes = filter1.toNBytes(); assert(filterNBytes instanceof Buffer); - }); -}); + }); +}); \ No newline at end of file diff --git a/test/headers-test.js b/test/headers-test.js index ed3d0b453..d5831c633 100644 --- a/test/headers-test.js +++ b/test/headers-test.js @@ -55,7 +55,7 @@ describe('Headers', function() { assert(headers.verifyBody()); assert(headers.verifyPOW()); }); - + it('should match raw headers from headers', () => { const headers = new Headers(); headers.time = 1231469665; @@ -68,7 +68,7 @@ describe('Headers', function() { headers.merkleRoot = Buffer.from( '982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e', 'hex'); - + assert.bufferEqual(headers.toRaw(), headers1); }); -}); +}); \ No newline at end of file diff --git a/test/mtx-test.js b/test/mtx-test.js index cdbf6a343..455fd3c75 100644 --- a/test/mtx-test.js +++ b/test/mtx-test.js @@ -69,7 +69,7 @@ describe('MTX', function () { 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: { @@ -89,5 +89,5 @@ describe('MTX', function () { }); const mtx2 = MTX.fromRaw(mtx1.toRaw()); assert.deepStrictEqual(mtx1, mtx2); - }); -}); + }); +}); \ No newline at end of file diff --git a/test/pow-test.js b/test/pow-test.js index de55976bd..fb800bf65 100644 --- a/test/pow-test.js +++ b/test/pow-test.js @@ -78,7 +78,7 @@ describe('Difficulty', function() { { 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 }, + { prevTime: 1269211443, prevBits: 0x1c387f6f, firstTime: 1263163443, expected: 0x1d00e1fd } ]; // Iterate through the test cases and check the output of the retarget function @@ -114,4 +114,4 @@ describe('Difficulty', function() { assert.ok(tdiff === p1.time - p2.time); } }); -}); +}); \ No newline at end of file From 994d064752be6e6b0204be689d44a81e571ef64b Mon Sep 17 00:00:00 2001 From: Suyash Nayan Date: Sun, 29 Jan 2023 15:36:01 +0530 Subject: [PATCH 3/3] fix: more linting errors --- test/coins-test.js | 2 +- test/consensus-test.js | 2 +- test/gcs-test.js | 2 +- test/headers-test.js | 2 +- test/mtx-test.js | 2 +- test/pow-test.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/coins-test.js b/test/coins-test.js index 95628ed83..0c2737021 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -127,4 +127,4 @@ describe('Coins', function() { assert.deepStrictEqual(view, res); }); -}); \ No newline at end of file +}); diff --git a/test/consensus-test.js b/test/consensus-test.js index 63a6fe9d9..f92c4739d 100644 --- a/test/consensus-test.js +++ b/test/consensus-test.js @@ -150,4 +150,4 @@ describe('Consensus', function() { assert.strictEqual(height, expectedHeight); assert.strictEqual(total, expectedTotal); }); -}); \ No newline at end of file +}); diff --git a/test/gcs-test.js b/test/gcs-test.js index a797eed5c..1bf6697c0 100644 --- a/test/gcs-test.js +++ b/test/gcs-test.js @@ -180,4 +180,4 @@ describe('GCS', function () { const filterNBytes = filter1.toNBytes(); assert(filterNBytes instanceof Buffer); }); -}); \ No newline at end of file +}); diff --git a/test/headers-test.js b/test/headers-test.js index d5831c633..7ebf4130a 100644 --- a/test/headers-test.js +++ b/test/headers-test.js @@ -71,4 +71,4 @@ describe('Headers', function() { assert.bufferEqual(headers.toRaw(), headers1); }); -}); \ No newline at end of file +}); diff --git a/test/mtx-test.js b/test/mtx-test.js index 455fd3c75..965df40b5 100644 --- a/test/mtx-test.js +++ b/test/mtx-test.js @@ -90,4 +90,4 @@ describe('MTX', function () { const mtx2 = MTX.fromRaw(mtx1.toRaw()); assert.deepStrictEqual(mtx1, mtx2); }); -}); \ No newline at end of file +}); diff --git a/test/pow-test.js b/test/pow-test.js index fb800bf65..51c02ded8 100644 --- a/test/pow-test.js +++ b/test/pow-test.js @@ -114,4 +114,4 @@ describe('Difficulty', function() { assert.ok(tdiff === p1.time - p2.time); } }); -}); \ No newline at end of file +});