From 3cdd7e3d2888d3d5efa664b9f209463292a10b6a Mon Sep 17 00:00:00 2001 From: Alexandra Roatis Date: Tue, 10 Mar 2020 17:25:54 -0400 Subject: [PATCH] Add tests for getThreeGenerationBlocksByHashWithInfo --- .../impl/blockchain/AionBlockchainImpl.java | 6 +- .../org/aion/zero/impl/db/AionBlockStore.java | 17 ++- .../aion/zero/impl/db/AionBlockStoreTest.java | 137 ++++++++++++++++++ 3 files changed, 149 insertions(+), 11 deletions(-) diff --git a/modAionImpl/src/org/aion/zero/impl/blockchain/AionBlockchainImpl.java b/modAionImpl/src/org/aion/zero/impl/blockchain/AionBlockchainImpl.java index 8f4e90e924..287531e0a7 100644 --- a/modAionImpl/src/org/aion/zero/impl/blockchain/AionBlockchainImpl.java +++ b/modAionImpl/src/org/aion/zero/impl/blockchain/AionBlockchainImpl.java @@ -1666,12 +1666,10 @@ public boolean isValid(BlockHeader header) { } Block[] threeGenParents = repository.getBlockStore().getThreeGenerationBlocksByHashWithInfo(header.getParentHash()); - - if (threeGenParents == null) { + Block parentBlock = threeGenParents[0]; + if (parentBlock == null) { return false; } - - Block parentBlock = threeGenParents[0]; Block grandparentBlock = threeGenParents[1]; Block greatGrandparentBlock = threeGenParents[2]; diff --git a/modAionImpl/src/org/aion/zero/impl/db/AionBlockStore.java b/modAionImpl/src/org/aion/zero/impl/db/AionBlockStore.java index e6cb36c7f1..ebca69648f 100644 --- a/modAionImpl/src/org/aion/zero/impl/db/AionBlockStore.java +++ b/modAionImpl/src/org/aion/zero/impl/db/AionBlockStore.java @@ -1392,18 +1392,21 @@ void redoIndexWithoutSideChains(Block block) { } /** - * Retrieve three generation blocks with unity protocol info with one lock. - * @param hash given hash of the block - * @return the 3 generation block data have matched hash with unity protocol info. Block[0] is the parent block, - * Block[1] is the grandParent block, and Block[2] is the greatParentBlock. The return might only contain the parent - * block and still return the 3-elements array. + * Retrieves three generation blocks with unity protocol info. + *

+ * Always returns a 3-element array. If the blocks cannot be retrieved the array will contain null values. + * Block[0] is the parent block and has the given hash. Block[1] is the grandparent block. + * Block[2] is the great grandparent block. + * + * @param hash the hash of the parent block + * @return the retrieved three generation blocks with unity protocol info */ public final Block[] getThreeGenerationBlocksByHashWithInfo(byte[] hash) { + Block[] blockFamily = new Block[] { null, null, null}; if (hash == null) { - return null; + return blockFamily; } - Block[] blockFamily = new Block[] { null, null, null}; lock.lock(); try { diff --git a/modAionImpl/test/org/aion/zero/impl/db/AionBlockStoreTest.java b/modAionImpl/test/org/aion/zero/impl/db/AionBlockStoreTest.java index e5f69260fb..b63bdd9374 100644 --- a/modAionImpl/test/org/aion/zero/impl/db/AionBlockStoreTest.java +++ b/modAionImpl/test/org/aion/zero/impl/db/AionBlockStoreTest.java @@ -562,4 +562,141 @@ public void testGetTwoGenerationBlocksByHashWithInfo_withSidechainGrandparent() assertThat(blocks[1].getTotalDifficulty()).isEqualTo(BigInteger.TWO); assertThat(blocks[1].isMainChain()).isFalse(); } + + @Test + public void testGetThreeGenerationBlocksByHashWithInfo_withNullInput() { + AionBlockStore store = new AionBlockStore(index, blocks, false); + Block[] blocks = store.getThreeGenerationBlocksByHashWithInfo(null); + assertThat(blocks.length).isEqualTo(3); + assertThat(blocks[0]).isNull(); + assertThat(blocks[1]).isNull(); + assertThat(blocks[2]).isNull(); + } + + @Test + public void testGetThreeGenerationBlocksByHashWithInfo_withMissingParent() { + byte[] parentHash = RandomUtils.nextBytes(32); + + AionBlockStore store = new AionBlockStore(index, blocks, false); + assertThat(index.isEmpty()).isTrue(); + assertThat(blocks.isEmpty()).isTrue(); + + Block[] blocks = store.getThreeGenerationBlocksByHashWithInfo(parentHash); + assertThat(blocks.length).isEqualTo(3); + assertThat(blocks[0]).isNull(); + assertThat(blocks[1]).isNull(); + assertThat(blocks[2]).isNull(); + } + + @Test + public void testGetThreeGenerationBlocksByHashWithInfo_withMissingGrandparent() { + Block parent = consecutiveBlocks.get(0); + + AionBlockStore store = new AionBlockStore(index, blocks, false); + // does not require accurate total difficulty + store.saveBlock(parent, BigInteger.TEN, true); + + Block[] blocks = store.getThreeGenerationBlocksByHashWithInfo(parent.getHash()); + assertThat(blocks.length).isEqualTo(3); + assertThat(blocks[0]).isEqualTo(parent); + assertThat(blocks[0].getTotalDifficulty()).isEqualTo(BigInteger.TEN); + assertThat(blocks[0].isMainChain()).isTrue(); + assertThat(blocks[1]).isNull(); + assertThat(blocks[2]).isNull(); + } + + @Test + public void testGetThreeGenerationBlocksByHashWithInfo_withMissingGreatGrandparent() { + Block grandparent = consecutiveBlocks.get(0); + Block parent = consecutiveBlocks.get(1); + + AionBlockStore store = new AionBlockStore(index, blocks, false); + // does not require accurate total difficulty + store.saveBlock(grandparent, BigInteger.TWO, true); + store.saveBlock(parent, BigInteger.TEN, true); + + Block[] blocks = store.getThreeGenerationBlocksByHashWithInfo(parent.getHash()); + assertThat(blocks.length).isEqualTo(3); + assertThat(blocks[0]).isEqualTo(parent); + assertThat(blocks[0].getTotalDifficulty()).isEqualTo(BigInteger.TEN); + assertThat(blocks[0].isMainChain()).isTrue(); + assertThat(blocks[1]).isEqualTo(grandparent); + assertThat(blocks[1].getTotalDifficulty()).isEqualTo(BigInteger.TWO); + assertThat(blocks[1].isMainChain()).isTrue(); + assertThat(blocks[2]).isNull(); + } + + @Test + public void testGetThreeGenerationBlocksByHashWithInfo() { + Block greatGrandparent = consecutiveBlocks.get(0); + Block grandparent = consecutiveBlocks.get(1); + Block parent = consecutiveBlocks.get(2); + + AionBlockStore store = new AionBlockStore(index, blocks, false); + // does not require accurate total difficulty + store.saveBlock(greatGrandparent, BigInteger.ONE, true); + store.saveBlock(grandparent, BigInteger.TWO, true); + store.saveBlock(parent, BigInteger.TEN, true); + + Block[] blocks = store.getThreeGenerationBlocksByHashWithInfo(parent.getHash()); + assertThat(blocks.length).isEqualTo(3); + assertThat(blocks[0]).isEqualTo(parent); + assertThat(blocks[0].getTotalDifficulty()).isEqualTo(BigInteger.TEN); + assertThat(blocks[0].isMainChain()).isTrue(); + assertThat(blocks[1]).isEqualTo(grandparent); + assertThat(blocks[1].getTotalDifficulty()).isEqualTo(BigInteger.TWO); + assertThat(blocks[1].isMainChain()).isTrue(); + assertThat(blocks[2]).isEqualTo(greatGrandparent); + assertThat(blocks[2].getTotalDifficulty()).isEqualTo(BigInteger.ONE); + assertThat(blocks[2].isMainChain()).isTrue(); + } + + @Test + public void testGetThreeGenerationBlocksByHashWithInfo_withSidechains() { + Block greatGrandparent = consecutiveBlocks.get(0); + Block grandparent = consecutiveBlocks.get(1); + Block parent = consecutiveBlocks.get(2); + + Block sideGreatGrandparent = spy(greatGrandparent); + byte[] newHash = RandomUtils.nextBytes(32); + when(sideGreatGrandparent.getHash()).thenReturn(newHash); + when(sideGreatGrandparent.getHashWrapper()).thenReturn(ByteArrayWrapper.wrap(newHash)); + assertThat(greatGrandparent.getHash()).isNotEqualTo(sideGreatGrandparent.getHash()); + + Block sideGrandparent = spy(grandparent); + newHash = RandomUtils.nextBytes(32); + when(sideGrandparent.getHash()).thenReturn(newHash); + when(sideGrandparent.getHashWrapper()).thenReturn(ByteArrayWrapper.wrap(newHash)); + assertThat(grandparent.getHash()).isNotEqualTo(sideGrandparent.getHash()); + + Block sideParent = spy(parent); + newHash = RandomUtils.nextBytes(32); + when(sideParent.getHash()).thenReturn(newHash); + when(sideParent.getHashWrapper()).thenReturn(ByteArrayWrapper.wrap(newHash)); + assertThat(parent.getHash()).isNotEqualTo(sideParent.getHash()); + + AionBlockStore store = new AionBlockStore(index, blocks, false); + // does not require accurate total difficulty + store.saveBlock(greatGrandparent, BigInteger.ONE, false); + store.saveBlock(grandparent, BigInteger.TWO, false); + store.saveBlock(parent, BigInteger.TEN, false); + store.saveBlock(sideGreatGrandparent, sideGreatGrandparent.getTotalDifficulty(), true); + store.saveBlock(sideGrandparent, sideGrandparent.getTotalDifficulty(), true); + store.saveBlock(sideParent, sideParent.getTotalDifficulty(), true); + + Block[] blocks = store.getThreeGenerationBlocksByHashWithInfo(parent.getHash()); + assertThat(blocks.length).isEqualTo(3); + assertThat(blocks[0]).isEqualTo(parent); + assertThat(blocks[0].getHash()).isEqualTo(parent.getHash()); + assertThat(blocks[0].getTotalDifficulty()).isEqualTo(BigInteger.TEN); + assertThat(blocks[0].isMainChain()).isFalse(); + assertThat(blocks[1]).isEqualTo(grandparent); + assertThat(blocks[1].getHash()).isEqualTo(grandparent.getHash()); + assertThat(blocks[1].getTotalDifficulty()).isEqualTo(BigInteger.TWO); + assertThat(blocks[1].isMainChain()).isFalse(); + assertThat(blocks[2]).isEqualTo(greatGrandparent); + assertThat(blocks[2].getHash()).isEqualTo(greatGrandparent.getHash()); + assertThat(blocks[2].getTotalDifficulty()).isEqualTo(BigInteger.ONE); + assertThat(blocks[2].isMainChain()).isFalse(); + } } \ No newline at end of file