package test; import static org.junit.Assert.*; import java.math.BigDecimal; import java.util.Arrays; import ntp.NTP; import org.junit.Test; import database.DBSet; import qora.BlockGenerator; import qora.account.Account; import qora.account.PrivateKeyAccount; import qora.block.Block; import qora.block.BlockFactory; import qora.block.GenesisBlock; import qora.crypto.Crypto; import qora.transaction.GenesisTransaction; import qora.transaction.PaymentTransaction; import qora.transaction.Transaction; public class BlockTests { @Test public void validateSignatureGenesisBlock() { Block genesisBlock = new GenesisBlock(); //CHECK IF SIGNATURE VALID assertEquals(true, genesisBlock.isSignatureValid()); } @Test public void validateGenesisBlock() { //CREATE EMPTY DATABASE DBSet databaseSet = DBSet.createEmptyDatabaseSet(); //CREATE GENESIS BLOCK Block genesisBlock = new GenesisBlock(); //CHECK IF VALID assertEquals(true, genesisBlock.isValid(databaseSet)); //ADD INVALID GENESIS TRANSACTION Transaction transaction = new GenesisTransaction(new Account("XUi2oga2pnGNcZ9es6pBqxydtRZKWdkL2g"), BigDecimal.valueOf(-1000).setScale(8), NTP.getTime()); genesisBlock.addTransaction(transaction); //CHECK IF INVALID assertEquals(false, genesisBlock.isValid(databaseSet)); //CREATE NEW BLOCK genesisBlock = new GenesisBlock(); //CHECK IF VALID assertEquals(true, genesisBlock.isValid(databaseSet)); //PROCESS genesisBlock.process(databaseSet); //CHECK IF INVALID assertEquals(false, genesisBlock.isValid(databaseSet)); } @Test public void parseGenesisBlock() { //CREATE VALID BLOCK Block genesisBlock = new GenesisBlock(); //CONVERT TO BYTES byte[] rawBlock = genesisBlock.toBytes(); try { //PARSE FROM BYTES Block parsedBlock = BlockFactory.getInstance().parse(rawBlock); //CHECK INSTANCE assertEquals(true, parsedBlock instanceof GenesisBlock); //CHECK SIGNATURE assertEquals(true, Arrays.equals(genesisBlock.getSignature(), parsedBlock.getSignature())); //CHECK GENERATOR assertEquals(genesisBlock.getGenerator().getAddress(), parsedBlock.getGenerator().getAddress()); //CHECK BASE TARGET assertEquals(genesisBlock.getGeneratingBalance(), parsedBlock.getGeneratingBalance()); //CHECK FEE assertEquals(genesisBlock.getTotalFee(), parsedBlock.getTotalFee()); //CHECK REFERENCE assertEquals(true, Arrays.equals(genesisBlock.getReference(), parsedBlock.getReference())); //CHECK TIMESTAMP assertEquals(genesisBlock.getTimestamp(), parsedBlock.getTimestamp()); //CHECK TRANSACTION COUNT assertEquals(genesisBlock.getTransactionCount(), parsedBlock.getTransactionCount()); } catch (Exception e) { fail("Exception while parsing transaction."); } //PARSE TRANSACTION FROM WRONG BYTES rawBlock = new byte[50]; try { //PARSE FROM BYTES BlockFactory.getInstance().parse(rawBlock); //FAIL fail("this should throw an exception"); } catch (Exception e) { //EXCEPTION IS THROWN OKE } } @Test public void validateSignatureBlock() { //CREATE EMPTY MEMORY DATABASE DBSet databaseSet = DBSet.createEmptyDatabaseSet(); //PROCESS GENESISBLOCK GenesisBlock genesisBlock = new GenesisBlock(); genesisBlock.process(databaseSet); //CREATE KNOWN ACCOUNT byte[] seed = Crypto.getInstance().digest("test".getBytes()); byte[] privateKey = Crypto.getInstance().createKeyPair(seed).getA(); PrivateKeyAccount generator = new PrivateKeyAccount(privateKey); //PROCESS GENESIS TRANSACTION TO MAKE SURE GENERATOR HAS FUNDS Transaction transaction = new GenesisTransaction(generator, BigDecimal.valueOf(1000).setScale(8), NTP.getTime()); transaction.process(databaseSet); //GENERATE NEXT BLOCK BlockGenerator blockGenerator = new BlockGenerator(); Block newBlock = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //ADD TRANSACTION SIGNATURE byte[] transactionsSignature = Crypto.getInstance().sign(generator, newBlock.getGeneratorSignature()); newBlock.setTransactionsSignature(transactionsSignature); //CHECK IF SIGNATURE VALID assertEquals(true, newBlock.isSignatureValid()); //INVALID TRANSACTION SIGNATURE transactionsSignature = new byte[64]; newBlock.setTransactionsSignature(transactionsSignature); //CHECK IF SIGNATURE INVALID assertEquals(false, newBlock.isSignatureValid()); //INVALID GENERATOR SIGNATURE newBlock = BlockFactory.getInstance().create(newBlock.getVersion(), newBlock.getReference(), newBlock.getTimestamp(), newBlock.getGeneratingBalance(), generator, new byte[32]); transactionsSignature = Crypto.getInstance().sign(generator, newBlock.getGeneratorSignature()); newBlock.setTransactionsSignature(transactionsSignature); ///CHECK IF SIGNATURE INVALID assertEquals(false, newBlock.isSignatureValid()); //VALID TRANSACTION SIGNATURE newBlock = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //ADD TRANSACTION Account recipient = new Account("XUi2oga2pnGNcZ9es6pBqxydtRZKWdkL2g"); long timestamp = newBlock.getTimestamp(); byte[] signature = PaymentTransaction.generateSignature(databaseSet, generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment = new PaymentTransaction(generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(databaseSet), signature); newBlock.addTransaction(payment); //ADD TRANSACTION SIGNATURE transactionsSignature = blockGenerator.calculateTransactionsSignature(newBlock, generator); newBlock.setTransactionsSignature(transactionsSignature); //CHECK VALID TRANSACTION SIGNATURE assertEquals(true, newBlock.isSignatureValid()); //INVALID TRANSACTION SIGNATURE newBlock = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //ADD TRANSACTION payment = new PaymentTransaction(generator, recipient, BigDecimal.valueOf(200).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(databaseSet), signature); newBlock.addTransaction(payment); //ADD TRANSACTION SIGNATURE transactionsSignature = blockGenerator.calculateTransactionsSignature(newBlock, generator); newBlock.setTransactionsSignature(transactionsSignature); //CHECK INVALID TRANSACTION SIGNATURE assertEquals(false, newBlock.isSignatureValid()); } @Test public void validateBlock() { //CREATE EMPTY MEMORY DATABASE DBSet databaseSet = DBSet.createEmptyDatabaseSet(); //PROCESS GENESISBLOCK GenesisBlock genesisBlock = new GenesisBlock(); genesisBlock.process(databaseSet); //CREATE KNOWN ACCOUNT byte[] seed = Crypto.getInstance().digest("test".getBytes()); byte[] privateKey = Crypto.getInstance().createKeyPair(seed).getA(); PrivateKeyAccount generator = new PrivateKeyAccount(privateKey); //PROCESS GENESIS TRANSACTION TO MAKE SURE GENERATOR HAS FUNDS Transaction transaction = new GenesisTransaction(generator, BigDecimal.valueOf(1000).setScale(8), NTP.getTime()); transaction.process(databaseSet); //GENERATE NEXT BLOCK BlockGenerator blockGenerator = new BlockGenerator(); Block newBlock = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //ADD TRANSACTION SIGNATURE byte[] transactionsSignature = Crypto.getInstance().sign(generator, newBlock.getGeneratorSignature()); newBlock.setTransactionsSignature(transactionsSignature); //CHECK IF VALID assertEquals(true, newBlock.isValid(databaseSet)); //CHANGE REFERENCE Block invalidBlock = BlockFactory.getInstance().create(newBlock.getVersion(), new byte[128], newBlock.getTimestamp(), newBlock.getGeneratingBalance(), newBlock.getGenerator(), newBlock.getGeneratorSignature()); //CHECK IF INVALID assertEquals(false, invalidBlock.isValid(databaseSet)); //CHANGE TIMESTAMP invalidBlock = BlockFactory.getInstance().create(newBlock.getVersion(), newBlock.getReference(), 1L, newBlock.getGeneratingBalance(), newBlock.getGenerator(), newBlock.getGeneratorSignature()); //CHECK IF INVALID assertEquals(false, invalidBlock.isValid(databaseSet)); //CHANGE BASETARGET invalidBlock = BlockFactory.getInstance().create(newBlock.getVersion(), newBlock.getReference(), newBlock.getTimestamp(), 1L, newBlock.getGenerator(), newBlock.getGeneratorSignature()); //CHECK IF INVALID assertEquals(false, invalidBlock.isValid(databaseSet)); //ADD INVALID TRANSACTION invalidBlock = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); Account recipient = new Account("XUi2oga2pnGNcZ9es6pBqxydtRZKWdkL2g"); long timestamp = newBlock.getTimestamp(); byte[] signature = PaymentTransaction.generateSignature(databaseSet, generator, recipient, BigDecimal.valueOf(-100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment = new PaymentTransaction(generator, recipient, BigDecimal.valueOf(-100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(databaseSet), signature); invalidBlock.addTransaction(payment); //CHECK IF INVALID assertEquals(false, invalidBlock.isValid(databaseSet)); //ADD GENESIS TRANSACTION invalidBlock = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); transaction = new GenesisTransaction(generator, BigDecimal.valueOf(1000).setScale(8), newBlock.getTimestamp()); invalidBlock.addTransaction(transaction); //CHECK IF INVALID assertEquals(false, invalidBlock.isValid(databaseSet)); } @Test public void parseBlock() { //CREATE EMPTY MEMORY DATABASE DBSet databaseSet = DBSet.createEmptyDatabaseSet(); //PROCESS GENESISBLOCK GenesisBlock genesisBlock = new GenesisBlock(); genesisBlock.process(databaseSet); //CREATE KNOWN ACCOUNT byte[] seed = Crypto.getInstance().digest("test".getBytes()); byte[] privateKey = Crypto.getInstance().createKeyPair(seed).getA(); PrivateKeyAccount generator = new PrivateKeyAccount(privateKey); //PROCESS GENESIS TRANSACTION TO MAKE SURE GENERATOR HAS FUNDS Transaction transaction = new GenesisTransaction(generator, BigDecimal.valueOf(1000).setScale(8), NTP.getTime()); transaction.process(databaseSet); //GENERATE NEXT BLOCK BlockGenerator blockGenerator = new BlockGenerator(); Block block = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //FORK DBSet fork = databaseSet.fork(); //GENERATE PAYMENT 1 Account recipient = new Account("XUi2oga2pnGNcZ9es6pBqxydtRZKWdkL2g"); long timestamp = block.getTimestamp(); byte[] signature = PaymentTransaction.generateSignature(databaseSet, generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment1 = new PaymentTransaction(generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(databaseSet), signature); payment1.process(fork); block.addTransaction(payment1); //GENERATE PAYMENT 2 Account recipient2 = new Account("XLPYYfxKEiDcybCkFA7jXcxSdePMMoyZLt"); signature = PaymentTransaction.generateSignature(fork, generator, recipient2, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment2 = new PaymentTransaction(generator, recipient2, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(fork), signature); block.addTransaction(payment2); //ADD TRANSACTION SIGNATURE byte[] transactionsSignature = Crypto.getInstance().sign(generator, block.getGeneratorSignature()); block.setTransactionsSignature(transactionsSignature); //CONVERT TO BYTES byte[] rawBlock = block.toBytes(); try { //PARSE FROM BYTES Block parsedBlock = BlockFactory.getInstance().parse(rawBlock); //CHECK INSTANCE assertEquals(false, parsedBlock instanceof GenesisBlock); //CHECK SIGNATURE assertEquals(true, Arrays.equals(block.getSignature(), parsedBlock.getSignature())); //CHECK GENERATOR assertEquals(block.getGenerator().getAddress(), parsedBlock.getGenerator().getAddress()); //CHECK BASE TARGET assertEquals(block.getGeneratingBalance(), parsedBlock.getGeneratingBalance()); //CHECK FEE assertEquals(block.getTotalFee(), parsedBlock.getTotalFee()); //CHECK REFERENCE assertEquals(true, Arrays.equals(block.getReference(), parsedBlock.getReference())); //CHECK TIMESTAMP assertEquals(block.getTimestamp(), parsedBlock.getTimestamp()); //CHECK TRANSACTIONS COUNT assertEquals(block.getTransactionCount(), parsedBlock.getTransactionCount()); } catch (Exception e) { fail("Exception while parsing transaction."); } //PARSE TRANSACTION FROM WRONG BYTES rawBlock = new byte[50]; try { //PARSE FROM BYTES BlockFactory.getInstance().parse(rawBlock); //FAIL fail("this should throw an exception"); } catch (Exception e) { //EXCEPTION IS THROWN OKE } } @Test public void processBlock() { //CREATE EMPTY MEMORY DATABASE DBSet databaseSet = DBSet.createEmptyDatabaseSet(); //PROCESS GENESISBLOCK GenesisBlock genesisBlock = new GenesisBlock(); genesisBlock.process(databaseSet); //CREATE KNOWN ACCOUNT byte[] seed = Crypto.getInstance().digest("test".getBytes()); byte[] privateKey = Crypto.getInstance().createKeyPair(seed).getA(); PrivateKeyAccount generator = new PrivateKeyAccount(privateKey); //PROCESS GENESIS TRANSACTION TO MAKE SURE GENERATOR HAS FUNDS Transaction transaction = new GenesisTransaction(generator, BigDecimal.valueOf(1000).setScale(8), NTP.getTime()); transaction.process(databaseSet); //GENERATE NEXT BLOCK BlockGenerator blockGenerator = new BlockGenerator(); Block block = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //FORK DBSet fork = databaseSet.fork(); //GENERATE PAYMENT 1 Account recipient = new Account("XUi2oga2pnGNcZ9es6pBqxydtRZKWdkL2g"); long timestamp = block.getTimestamp(); byte[] signature = PaymentTransaction.generateSignature(databaseSet, generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment1 = new PaymentTransaction(generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(databaseSet), signature); payment1.process(fork); block.addTransaction(payment1); //GENERATE PAYMENT 2 Account recipient2 = new Account("XLPYYfxKEiDcybCkFA7jXcxSdePMMoyZLt"); signature = PaymentTransaction.generateSignature(fork, generator, recipient2, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment2 = new PaymentTransaction(generator, recipient2, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(fork), signature); block.addTransaction(payment2); //ADD TRANSACTION SIGNATURE byte[] transactionsSignature = blockGenerator.calculateTransactionsSignature(block, generator); block.setTransactionsSignature(transactionsSignature); //CHECK VALID assertEquals(true, block.isSignatureValid()); assertEquals(true, block.isValid(databaseSet)); //PROCESS BLOCK block.process(databaseSet); //CHECK BALANCE GENERATOR assertEquals(true, generator.getConfirmedBalance(databaseSet).compareTo(BigDecimal.valueOf(800)) == 0); //CHECK LAST REFERENCE GENERATOR assertEquals(true, Arrays.equals(generator.getLastReference(databaseSet), payment2.getSignature())); //CHECK BALANCE RECIPIENT assertEquals(true, recipient.getConfirmedBalance(databaseSet).compareTo(BigDecimal.valueOf(1100)) == 0); //CHECK LAST REFERENCE RECIPIENT assertEquals(false, Arrays.equals(recipient.getLastReference(databaseSet), payment1.getSignature())); //CHECK BALANCE RECIPIENT2 assertEquals(true, recipient2.getConfirmedBalance(databaseSet).compareTo(BigDecimal.valueOf(100)) == 0); //CHECK LAST REFERENCE RECIPIENT assertEquals(true, Arrays.equals(recipient2.getLastReference(databaseSet), payment2.getSignature())); //CHECK TOTAL FEE assertEquals(true, block.getTotalFee().compareTo(BigDecimal.valueOf(2)) == 0); //CHECK TOTAL TRANSACTIONS assertEquals(2, block.getTransactionCount()); //CHECK LAST BLOCK assertEquals(true, Arrays.equals(block.getSignature(), databaseSet.getBlockMap().getLastBlock().getSignature())); } @Test public void orphanBlock() { //CREATE EMPTY MEMORY DATABASE DBSet databaseSet = DBSet.createEmptyDatabaseSet(); //PROCESS GENESISBLOCK GenesisBlock genesisBlock = new GenesisBlock(); genesisBlock.process(databaseSet); //CREATE KNOWN ACCOUNT byte[] seed = Crypto.getInstance().digest("test".getBytes()); byte[] privateKey = Crypto.getInstance().createKeyPair(seed).getA(); PrivateKeyAccount generator = new PrivateKeyAccount(privateKey); //PROCESS GENESIS TRANSACTION TO MAKE SURE GENERATOR HAS FUNDS Transaction transaction = new GenesisTransaction(generator, BigDecimal.valueOf(1000).setScale(8), NTP.getTime()); transaction.process(databaseSet); //GENERATE NEXT BLOCK BlockGenerator blockGenerator = new BlockGenerator(); Block block = blockGenerator.generateNextBlock(databaseSet, generator, genesisBlock); //FORK DBSet fork = databaseSet.fork(); //GENERATE PAYMENT 1 Account recipient = new Account("XUi2oga2pnGNcZ9es6pBqxydtRZKWdkL2g"); long timestamp = block.getTimestamp(); byte[] signature = PaymentTransaction.generateSignature(databaseSet, generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment1 = new PaymentTransaction(generator, recipient, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(databaseSet), signature); payment1.process(fork); block.addTransaction(payment1); //GENERATE PAYMENT 2 Account recipient2 = new Account("XLPYYfxKEiDcybCkFA7jXcxSdePMMoyZLt"); signature = PaymentTransaction.generateSignature(fork, generator, recipient2, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp); Transaction payment2 = new PaymentTransaction(generator, recipient2, BigDecimal.valueOf(100).setScale(8), BigDecimal.valueOf(1).setScale(8), timestamp, generator.getLastReference(fork), signature); block.addTransaction(payment2); //ADD TRANSACTION SIGNATURE byte[] transactionsSignature = blockGenerator.calculateTransactionsSignature(block, generator); block.setTransactionsSignature(transactionsSignature); //CHECK VALID assertEquals(true, block.isSignatureValid()); assertEquals(true, block.isValid(databaseSet)); //PROCESS BLOCK block.process(databaseSet); //ORPHAN BLOCK block.orphan(databaseSet); //CHECK BALANCE GENERATOR assertEquals(true, generator.getConfirmedBalance(databaseSet).compareTo(BigDecimal.valueOf(1000)) == 0); //CHECK LAST REFERENCE GENERATOR assertEquals(true, Arrays.equals(generator.getLastReference(databaseSet), transaction.getSignature())); //CHECK BALANCE RECIPIENT assertEquals(true, recipient.getConfirmedBalance(databaseSet).compareTo(BigDecimal.valueOf(1000)) == 0); //CHECK LAST REFERENCE RECIPIENT assertEquals(false, Arrays.equals(recipient.getLastReference(databaseSet), payment1.getSignature())); //CHECK BALANCE RECIPIENT2 assertEquals(true, recipient2.getConfirmedBalance(databaseSet).compareTo(BigDecimal.valueOf(0)) == 0); //CHECK LAST REFERENCE RECIPIENT assertEquals(true, Arrays.equals(recipient2.getLastReference(databaseSet), new byte[0])); //CHECK LAST BLOCK assertEquals(true, Arrays.equals(genesisBlock.getSignature(), databaseSet.getBlockMap().getLastBlock().getSignature())); } }