mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-23 04:36:50 +00:00
Refactoring, new translations, cleaning up warnings.
Refactored to standard Maven layout: src/main/java src/main/resources src/test/java etc. New translation code that uses locale-specific ResourceBundles to load translations on demand. Reworked API error/exceptions code to a shorter, simpler @ApiErrors annotation. Processing of @ApiErrors annotations produces an example for each possible API error and includes API error string in HTTP response code, e.g. 400 INVALID_SIGNATURE Missing API error cases added to each API call. Translation of openAPI.json removed (for now). block-explorer.html and BIP39 wordlists now read as resources instead of direct from disk. Java compile warnings fixed. Some runtime warnings remain: WARNING: A provider api.resource.ApiDefinition registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. WARNING: A provider api.resource.AnnotationPostProcessor registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. WARN org.reflections.Reflections - given scan urls are empty. set urls in the configuration
This commit is contained in:
106
src/test/java/test/ATTests.java
Normal file
106
src/test/java/test/ATTests.java
Normal file
@@ -0,0 +1,106 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
|
||||
import data.at.ATStateData;
|
||||
import data.block.BlockData;
|
||||
import data.block.BlockTransactionData;
|
||||
import data.transaction.DeployATTransactionData;
|
||||
import qora.assets.Asset;
|
||||
import qora.transaction.DeployATTransaction;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
|
||||
public class ATTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testATAccount() throws TransformationException, DataException {
|
||||
// 2dZ4megUyNoYYY7qWmuSd4xw1yUKgPPF97yBbeddh8aKuC8PLpz7Xvf3r6Zjv1zwGrR8fEAHuaztCPD4KQp76KdL at height 125598
|
||||
// AT address: AaaUn82XV4YcUtsQ3rHa5ZgqyiK35rVfE3
|
||||
|
||||
String expectedAddress = "AaaUn82XV4YcUtsQ3rHa5ZgqyiK35rVfE3";
|
||||
|
||||
byte[] creatorPublicKey = HashCode.fromString("c74d71ecec6b37890f26573186e634986cc90a507af01749f92aa2c7c95ad05f").asBytes();
|
||||
String name = "QORABURST @ 1.00";
|
||||
String description = "Initiators BURST address: BURST-LKGW-Z2JK-EZ99-E7CUE";
|
||||
String ATType = "acct";
|
||||
String tags = "acct,atomic cross chain tx,initiate,initiator";
|
||||
byte[] creationBytes = HashCode
|
||||
.fromString("010000000100010000000000" + "0094357700" + "000000bf"
|
||||
+ "3501030900000006040000000900000029302009000000040000000f1ab4000000330403090000003525010a000000260a000000320903350703090000003526010a0000001b0a000000cd322801331601000000003317010100000033180102000000331901030000003505020a0000001b0a000000a1320b033205041e050000001833000509000000320a033203041ab400000033160105000000331701060000003318010700000033190108000000320304320b033203041ab7"
|
||||
+ "00000048"
|
||||
+ "5e211280259d2f3130248482c2dfc53be2fd5f9bedc9bc21425f951e8097a21900000000c80000003ac8716ad810191acf270d22e9f47f27806256c10d6ba6144900000000000000")
|
||||
.asBytes();
|
||||
BigDecimal amount = BigDecimal.valueOf(500.0).setScale(8);
|
||||
BigDecimal fee = BigDecimal.valueOf(20.0).setScale(8);
|
||||
long timestamp = 1439997077932L;
|
||||
byte[] reference = Base58.decode("2D3jX1pEgu6irsQ7QzJb85QP1D9M45dNyP5M9a3WFHndU5ZywF4F5pnUurcbzMnGMcTwpAY6H7DuLw8cUBU66ao1");
|
||||
byte[] signature = Base58.decode("2dZ4megUyNoYYY7qWmuSd4xw1yUKgPPF97yBbeddh8aKuC8PLpz7Xvf3r6Zjv1zwGrR8fEAHuaztCPD4KQp76KdL");
|
||||
|
||||
DeployATTransactionData transactionData = new DeployATTransactionData(creatorPublicKey, name, description, ATType, tags, creationBytes, amount,
|
||||
Asset.QORA, fee, timestamp, reference, signature);
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
repository.getTransactionRepository().save(transactionData);
|
||||
|
||||
DeployATTransaction transaction = new DeployATTransaction(repository, transactionData);
|
||||
|
||||
// Fake entry for this transaction at block height 125598 if it doesn't already exist
|
||||
if (transaction.getHeight() == 0) {
|
||||
byte[] blockSignature = Base58.decode(
|
||||
"2amu634LnAbxeLfDtWdTLiCWtKu1XM2XLK9o6fDM7yGNNoh5Tq2KxSLdx8AS486zUU1wYNGCm8mcGxjMiww979MxdPVB2PQzaKrW2aFn9hpdSNN6Nk7EmeYKwsZdx9tkpHfBt5thSrUUrhzXJju9KYCAP6p3Ty4zccFkaxCP15j332U");
|
||||
byte[] generatorSignature = Arrays.copyOfRange(blockSignature, 0, 64);
|
||||
byte[] transactionsSignature = Arrays.copyOfRange(blockSignature, 64, 128);
|
||||
|
||||
// Check block exists too
|
||||
if (repository.getBlockRepository().fromSignature(blockSignature) == null) {
|
||||
int version = 2;
|
||||
byte[] blockReference = blockSignature;
|
||||
int transactionCount = 0;
|
||||
BigDecimal totalFees = BigDecimal.valueOf(70.0).setScale(8);
|
||||
int height = 125598;
|
||||
long blockTimestamp = 1439997158336L;
|
||||
BigDecimal generatingBalance = BigDecimal.valueOf(1440368826L).setScale(8);
|
||||
byte[] generatorPublicKey = Base58.decode("X4s833bbtghh7gejmaBMbWqD44HrUobw93ANUuaNhFc");
|
||||
int atCount = 1;
|
||||
BigDecimal atFees = BigDecimal.valueOf(50.0).setScale(8);
|
||||
|
||||
BlockData blockData = new BlockData(version, blockReference, transactionCount, totalFees, transactionsSignature, height, blockTimestamp,
|
||||
generatingBalance, generatorPublicKey, generatorSignature, atCount, atFees);
|
||||
|
||||
repository.getBlockRepository().save(blockData);
|
||||
|
||||
byte[] atBytes = HashCode.fromString("17950a6c62d17ff0caa545651c054a105f1c464daca443df846cc6a3d58f764b78c09cff50f0fd9ec2").asBytes();
|
||||
|
||||
String atAddress = Base58.encode(Arrays.copyOfRange(atBytes, 0, 25));
|
||||
byte[] stateHash = Arrays.copyOfRange(atBytes, 25, atBytes.length);
|
||||
|
||||
ATStateData atStateData = new ATStateData(atAddress, height, timestamp, new byte[0], stateHash, atFees);
|
||||
|
||||
repository.getATRepository().save(atStateData);
|
||||
}
|
||||
|
||||
int sequence = 0;
|
||||
|
||||
BlockTransactionData blockTransactionData = new BlockTransactionData(blockSignature, sequence, signature);
|
||||
repository.getBlockRepository().save(blockTransactionData);
|
||||
}
|
||||
|
||||
String actualAddress = transaction.getATAccount().getAddress();
|
||||
|
||||
repository.discardChanges();
|
||||
|
||||
assertEquals(expectedAddress, actualAddress);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
331
src/test/java/test/BTCACCTTests.java
Normal file
331
src/test/java/test/BTCACCTTests.java
Normal file
@@ -0,0 +1,331 @@
|
||||
package test;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.Transaction.SigHash;
|
||||
import org.bitcoinj.core.TransactionBroadcast;
|
||||
import org.bitcoinj.core.TransactionInput;
|
||||
import org.bitcoinj.core.TransactionOutPoint;
|
||||
import org.bitcoinj.crypto.TransactionSignature;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.bitcoinj.script.ScriptChunk;
|
||||
import org.bitcoinj.script.ScriptOpCodes;
|
||||
import org.bitcoinj.wallet.WalletTransaction.Pool;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.common.primitives.Bytes;
|
||||
|
||||
/**
|
||||
* Initiator must be Qora-chain so that initiator can send initial message to BTC P2SH then Qora can scan for P2SH add send corresponding message to Qora AT.
|
||||
*
|
||||
* Initiator (wants Qora, has BTC)
|
||||
* Funds BTC P2SH address
|
||||
*
|
||||
* Responder (has Qora, wants BTC)
|
||||
* Builds Qora ACCT AT and funds it with Qora
|
||||
*
|
||||
* Initiator sends recipient+secret+script as input to BTC P2SH address, releasing BTC amount - fees to responder
|
||||
*
|
||||
* Qora nodes scan for P2SH output, checks amount and recipient and if ok sends secret to Qora ACCT AT
|
||||
* (Or it's possible to feed BTC transaction details into Qora AT so it can check them itself?)
|
||||
*
|
||||
* Qora ACCT AT sends its Qora to initiator
|
||||
*
|
||||
*/
|
||||
|
||||
public class BTCACCTTests {
|
||||
|
||||
private static final long TIMEOUT = 600L;
|
||||
private static final Coin sendValue = Coin.valueOf(6_000L);
|
||||
private static final Coin fee = Coin.valueOf(2_000L);
|
||||
|
||||
private static final byte[] senderPrivKeyBytes = HashCode.fromString("027fb5828c5e201eaf6de4cd3b0b340d16a191ef848cd691f35ef8f727358c9c").asBytes();
|
||||
private static final byte[] recipientPrivKeyBytes = HashCode.fromString("ec199a4abc9d3bf024349e397535dfee9d287e174aeabae94237eb03a0118c03").asBytes();
|
||||
|
||||
// The following need to be updated manually
|
||||
private static final String prevTxHash = "70ee97f20afea916c2e7b47f6abf3c75f97c4c2251b4625419406a2dd47d16b5";
|
||||
private static final Coin prevTxBalance = Coin.valueOf(562_000L); // This is NOT the amount but the unspent balance
|
||||
private static final long prevTxOutputIndex = 1L;
|
||||
|
||||
// For when we want to re-run
|
||||
private static final byte[] prevSecret = HashCode.fromString("30a13291e350214bea5318f990b77bc11d2cb709f7c39859f248bef396961dcc").asBytes();
|
||||
private static final long prevLockTime = 1539347892L;
|
||||
private static final boolean usePreviousFundingTx = true;
|
||||
|
||||
private static final boolean doRefundNotRedeem = false;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
Security.insertProviderAt(new BouncyCastleProvider(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildBTCACCTTest() throws NoSuchAlgorithmException, InsufficientMoneyException, InterruptedException, ExecutionException, UnknownHostException {
|
||||
byte[] secret = new byte[32];
|
||||
new SecureRandom().nextBytes(secret);
|
||||
|
||||
if (usePreviousFundingTx)
|
||||
secret = prevSecret;
|
||||
|
||||
System.out.println("Secret: " + HashCode.fromBytes(secret).toString());
|
||||
|
||||
MessageDigest sha256Digester = MessageDigest.getInstance("SHA-256");
|
||||
|
||||
byte[] secretHash = sha256Digester.digest(secret);
|
||||
String secretHashHex = HashCode.fromBytes(secretHash).toString();
|
||||
|
||||
System.out.println("SHA256(secret): " + secretHashHex);
|
||||
|
||||
NetworkParameters params = TestNet3Params.get();
|
||||
// NetworkParameters params = RegTestParams.get();
|
||||
System.out.println("Network: " + params.getId());
|
||||
|
||||
WalletAppKit kit = new WalletAppKit(params, new File("."), "btc-tests");
|
||||
|
||||
kit.setBlockingStartup(false);
|
||||
kit.startAsync();
|
||||
kit.awaitRunning();
|
||||
|
||||
long now = System.currentTimeMillis() / 1000L;
|
||||
long lockTime = now + TIMEOUT;
|
||||
|
||||
if (usePreviousFundingTx)
|
||||
lockTime = prevLockTime;
|
||||
|
||||
System.out.println("LockTime: " + lockTime);
|
||||
|
||||
ECKey senderKey = ECKey.fromPrivate(senderPrivKeyBytes);
|
||||
kit.wallet().importKey(senderKey);
|
||||
ECKey recipientKey = ECKey.fromPrivate(recipientPrivKeyBytes);
|
||||
kit.wallet().importKey(recipientKey);
|
||||
|
||||
byte[] senderPubKey = senderKey.getPubKey();
|
||||
System.out.println("Sender address: " + senderKey.toAddress(params).toBase58());
|
||||
System.out.println("Sender pubkey: " + HashCode.fromBytes(senderPubKey).toString());
|
||||
|
||||
byte[] recipientPubKey = recipientKey.getPubKey();
|
||||
System.out.println("Recipient address: " + recipientKey.toAddress(params).toBase58());
|
||||
System.out.println("Recipient pubkey: " + HashCode.fromBytes(recipientPubKey).toString());
|
||||
|
||||
byte[] redeemScriptBytes = buildRedeemScript(secret, senderPubKey, recipientPubKey, lockTime);
|
||||
System.out.println("Redeem script: " + HashCode.fromBytes(redeemScriptBytes).toString());
|
||||
|
||||
byte[] redeemScriptHash = hash160(redeemScriptBytes);
|
||||
|
||||
Address p2shAddress = Address.fromP2SHHash(params, redeemScriptHash);
|
||||
System.out.println("P2SH address: " + p2shAddress.toBase58());
|
||||
|
||||
// Send amount to P2SH address
|
||||
Transaction fundingTransaction = buildFundingTransaction(params, Sha256Hash.wrap(prevTxHash), prevTxOutputIndex, prevTxBalance, senderKey,
|
||||
sendValue.add(fee), redeemScriptHash);
|
||||
|
||||
System.out.println("Sending " + sendValue.add(fee).toPlainString() + " to " + p2shAddress.toBase58());
|
||||
if (!usePreviousFundingTx)
|
||||
broadcastWithConfirmation(kit, fundingTransaction);
|
||||
|
||||
if (doRefundNotRedeem) {
|
||||
// Refund
|
||||
System.out.println("Refunding " + sendValue.toPlainString() + " back to " + senderKey.toAddress(params));
|
||||
|
||||
now = System.currentTimeMillis() / 1000L;
|
||||
long refundLockTime = now - 60 * 30; // 30 minutes in the past, needs to before 'now' and before "median block time" (median of previous 11 block
|
||||
// timestamps)
|
||||
if (refundLockTime < lockTime)
|
||||
throw new RuntimeException("Too soon to refund");
|
||||
|
||||
TransactionOutPoint fundingOutPoint = new TransactionOutPoint(params, 0, fundingTransaction);
|
||||
Transaction refundTransaction = buildRefundTransaction(params, fundingOutPoint, senderKey, sendValue, redeemScriptBytes, refundLockTime);
|
||||
broadcastWithConfirmation(kit, refundTransaction);
|
||||
} else {
|
||||
// Redeem
|
||||
System.out.println("Redeeming " + sendValue.toPlainString() + " to " + recipientKey.toAddress(params));
|
||||
|
||||
TransactionOutPoint fundingOutPoint = new TransactionOutPoint(params, 0, fundingTransaction);
|
||||
Transaction redeemTransaction = buildRedeemTransaction(params, fundingOutPoint, recipientKey, sendValue, secret, redeemScriptBytes);
|
||||
broadcastWithConfirmation(kit, redeemTransaction);
|
||||
}
|
||||
|
||||
kit.wallet().cleanup();
|
||||
|
||||
for (Transaction transaction : kit.wallet().getTransactionPool(Pool.PENDING).values())
|
||||
System.out.println("Pending tx: " + transaction.getHashAsString());
|
||||
}
|
||||
|
||||
private static final byte[] redeemScript1 = HashCode.fromString("76a820").asBytes();
|
||||
private static final byte[] redeemScript2 = HashCode.fromString("87637576a914").asBytes();
|
||||
private static final byte[] redeemScript3 = HashCode.fromString("88ac6704").asBytes();
|
||||
private static final byte[] redeemScript4 = HashCode.fromString("b17576a914").asBytes();
|
||||
private static final byte[] redeemScript5 = HashCode.fromString("88ac68").asBytes();
|
||||
|
||||
private byte[] buildRedeemScript(byte[] secret, byte[] senderPubKey, byte[] recipientPubKey, long lockTime) {
|
||||
try {
|
||||
MessageDigest sha256Digester = MessageDigest.getInstance("SHA-256");
|
||||
|
||||
byte[] secretHash = sha256Digester.digest(secret);
|
||||
byte[] senderPubKeyHash = hash160(senderPubKey);
|
||||
byte[] recipientPubKeyHash = hash160(recipientPubKey);
|
||||
|
||||
return Bytes.concat(redeemScript1, secretHash, redeemScript2, recipientPubKeyHash, redeemScript3, toLEByteArray((int) (lockTime & 0xffffffffL)),
|
||||
redeemScript4, senderPubKeyHash, redeemScript5);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Message digest unsupported", e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] hash160(byte[] input) {
|
||||
try {
|
||||
MessageDigest rmd160Digester = MessageDigest.getInstance("RIPEMD160");
|
||||
MessageDigest sha256Digester = MessageDigest.getInstance("SHA-256");
|
||||
|
||||
return rmd160Digester.digest(sha256Digester.digest(input));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Message digest unsupported", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Transaction buildFundingTransaction(NetworkParameters params, Sha256Hash prevTxHash, long outputIndex, Coin balance, ECKey sigKey, Coin value,
|
||||
byte[] redeemScriptHash) {
|
||||
Transaction fundingTransaction = new Transaction(params);
|
||||
|
||||
// Outputs (needed before input so inputs can be signed)
|
||||
// Fixed amount to P2SH
|
||||
fundingTransaction.addOutput(value, ScriptBuilder.createP2SHOutputScript(redeemScriptHash));
|
||||
// Change to sender
|
||||
fundingTransaction.addOutput(balance.minus(value).minus(fee), ScriptBuilder.createOutputScript(sigKey.toAddress(params)));
|
||||
|
||||
// Input
|
||||
// We create fake "to address" scriptPubKey for prev tx so our spending input is P2PKH type
|
||||
Script fakeScriptPubKey = ScriptBuilder.createOutputScript(sigKey.toAddress(params));
|
||||
TransactionOutPoint prevOut = new TransactionOutPoint(params, outputIndex, prevTxHash);
|
||||
fundingTransaction.addSignedInput(prevOut, fakeScriptPubKey, sigKey);
|
||||
|
||||
return fundingTransaction;
|
||||
}
|
||||
|
||||
private Transaction buildRedeemTransaction(NetworkParameters params, TransactionOutPoint fundingOutPoint, ECKey recipientKey, Coin value, byte[] secret,
|
||||
byte[] redeemScriptBytes) {
|
||||
Transaction redeemTransaction = new Transaction(params);
|
||||
redeemTransaction.setVersion(2);
|
||||
|
||||
// Outputs
|
||||
redeemTransaction.addOutput(value, ScriptBuilder.createOutputScript(recipientKey.toAddress(params)));
|
||||
|
||||
// Input
|
||||
byte[] recipientPubKey = recipientKey.getPubKey();
|
||||
ScriptBuilder scriptBuilder = new ScriptBuilder();
|
||||
scriptBuilder.addChunk(new ScriptChunk(recipientPubKey.length, recipientPubKey));
|
||||
scriptBuilder.addChunk(new ScriptChunk(secret.length, secret));
|
||||
scriptBuilder.addChunk(new ScriptChunk(ScriptOpCodes.OP_PUSHDATA1, redeemScriptBytes));
|
||||
byte[] scriptPubKey = scriptBuilder.build().getProgram();
|
||||
|
||||
TransactionInput input = new TransactionInput(params, null, scriptPubKey, fundingOutPoint);
|
||||
input.setSequenceNumber(0xffffffffL); // Final
|
||||
redeemTransaction.addInput(input);
|
||||
|
||||
// Generate transaction signature for input
|
||||
boolean anyoneCanPay = false;
|
||||
Sha256Hash hash = redeemTransaction.hashForSignature(0, redeemScriptBytes, SigHash.ALL, anyoneCanPay);
|
||||
System.out.println("redeem transaction's input hash: " + hash.toString());
|
||||
|
||||
ECKey.ECDSASignature ecSig = recipientKey.sign(hash);
|
||||
TransactionSignature txSig = new TransactionSignature(ecSig, SigHash.ALL, anyoneCanPay);
|
||||
byte[] txSigBytes = txSig.encodeToBitcoin();
|
||||
System.out.println("redeem transaction's signature: " + HashCode.fromBytes(txSigBytes).toString());
|
||||
|
||||
// Prepend signature to input
|
||||
scriptBuilder.addChunk(0, new ScriptChunk(txSigBytes.length, txSigBytes));
|
||||
input.setScriptSig(scriptBuilder.build());
|
||||
|
||||
return redeemTransaction;
|
||||
}
|
||||
|
||||
private Transaction buildRefundTransaction(NetworkParameters params, TransactionOutPoint fundingOutPoint, ECKey senderKey, Coin value,
|
||||
byte[] redeemScriptBytes, long lockTime) {
|
||||
Transaction refundTransaction = new Transaction(params);
|
||||
refundTransaction.setVersion(2);
|
||||
|
||||
// Outputs
|
||||
refundTransaction.addOutput(value, ScriptBuilder.createOutputScript(senderKey.toAddress(params)));
|
||||
|
||||
// Input
|
||||
byte[] recipientPubKey = senderKey.getPubKey();
|
||||
ScriptBuilder scriptBuilder = new ScriptBuilder();
|
||||
scriptBuilder.addChunk(new ScriptChunk(recipientPubKey.length, recipientPubKey));
|
||||
scriptBuilder.addChunk(new ScriptChunk(ScriptOpCodes.OP_PUSHDATA1, redeemScriptBytes));
|
||||
byte[] scriptPubKey = scriptBuilder.build().getProgram();
|
||||
|
||||
TransactionInput input = new TransactionInput(params, null, scriptPubKey, fundingOutPoint);
|
||||
input.setSequenceNumber(0);
|
||||
refundTransaction.addInput(input);
|
||||
|
||||
// Set locktime after input but before input signature is generated
|
||||
refundTransaction.setLockTime(lockTime);
|
||||
|
||||
// Generate transaction signature for input
|
||||
boolean anyoneCanPay = false;
|
||||
Sha256Hash hash = refundTransaction.hashForSignature(0, redeemScriptBytes, SigHash.ALL, anyoneCanPay);
|
||||
System.out.println("refund transaction's input hash: " + hash.toString());
|
||||
|
||||
ECKey.ECDSASignature ecSig = senderKey.sign(hash);
|
||||
TransactionSignature txSig = new TransactionSignature(ecSig, SigHash.ALL, anyoneCanPay);
|
||||
byte[] txSigBytes = txSig.encodeToBitcoin();
|
||||
System.out.println("refund transaction's signature: " + HashCode.fromBytes(txSigBytes).toString());
|
||||
|
||||
// Prepend signature to input
|
||||
scriptBuilder.addChunk(0, new ScriptChunk(txSigBytes.length, txSigBytes));
|
||||
input.setScriptSig(scriptBuilder.build());
|
||||
|
||||
return refundTransaction;
|
||||
}
|
||||
|
||||
private void broadcastWithConfirmation(WalletAppKit kit, Transaction transaction) {
|
||||
System.out.println("Broadcasting tx: " + transaction.getHashAsString());
|
||||
System.out.println("TX hex: " + HashCode.fromBytes(transaction.bitcoinSerialize()).toString());
|
||||
|
||||
System.out.println("Number of connected peers: " + kit.peerGroup().numConnectedPeers());
|
||||
TransactionBroadcast txBroadcast = kit.peerGroup().broadcastTransaction(transaction);
|
||||
|
||||
try {
|
||||
txBroadcast.future().get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException("Transaction broadcast failed", e);
|
||||
}
|
||||
|
||||
// wait for confirmation
|
||||
System.out.println("Waiting for confirmation of tx: " + transaction.getHashAsString());
|
||||
|
||||
try {
|
||||
transaction.getConfidence().getDepthFuture(1).get();
|
||||
} catch (CancellationException | ExecutionException | InterruptedException e) {
|
||||
throw new RuntimeException("Transaction confirmation failed", e);
|
||||
}
|
||||
|
||||
System.out.println("Confirmed tx: " + transaction.getHashAsString());
|
||||
}
|
||||
|
||||
/** Convert int to little-endian byte array */
|
||||
private byte[] toLEByteArray(int value) {
|
||||
return new byte[] { (byte) (value), (byte) (value >> 8), (byte) (value >> 16), (byte) (value >> 24) };
|
||||
}
|
||||
|
||||
}
|
57
src/test/java/test/BTCTests.java
Normal file
57
src/test/java/test/BTCTests.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package test;
|
||||
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
|
||||
import crosschain.BTC;
|
||||
|
||||
public class BTCTests {
|
||||
|
||||
@Test
|
||||
public void testWatchAddress() throws Exception {
|
||||
// String testAddress = "mrTDPdM15cFWJC4g223BXX5snicfVJBx6M";
|
||||
String testAddress = "1GRENT17xMQe2ukPhwAeZU1TaUUon1Qc65";
|
||||
|
||||
long testStartTime = 1539000000L;
|
||||
|
||||
BTC btc = BTC.getInstance();
|
||||
|
||||
btc.watch(testAddress, testStartTime);
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
||||
btc.watch(testAddress, testStartTime);
|
||||
|
||||
btc.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWatchScript() throws Exception {
|
||||
long testStartTime = 1539000000L;
|
||||
|
||||
BTC btc = BTC.getInstance();
|
||||
|
||||
byte[] redeemScriptHash = HashCode.fromString("3dbcc35e69ebc449f616fa3eb3723dfad9cbb5b3").asBytes();
|
||||
Script redeemScript = ScriptBuilder.createP2SHOutputScript(redeemScriptHash);
|
||||
redeemScript.setCreationTimeSeconds(testStartTime);
|
||||
|
||||
// btc.watch(redeemScript);
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
||||
// btc.watch(redeemScript);
|
||||
|
||||
btc.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateCheckpoints() throws Exception {
|
||||
BTC btc = BTC.getInstance();
|
||||
|
||||
btc.updateCheckpoints();
|
||||
}
|
||||
|
||||
}
|
121
src/test/java/test/BlockTests.java
Normal file
121
src/test/java/test/BlockTests.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import data.block.BlockData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.block.Block;
|
||||
import qora.block.GenesisBlock;
|
||||
import qora.transaction.Transaction;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import transform.TransformationException;
|
||||
import transform.block.BlockTransformer;
|
||||
|
||||
public class BlockTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testGenesisBlockTransactions() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
GenesisBlock block = GenesisBlock.getInstance(repository);
|
||||
|
||||
assertNotNull(block);
|
||||
assertTrue(block.isSignatureValid());
|
||||
// only true if blockchain is empty
|
||||
// assertTrue(block.isValid());
|
||||
|
||||
List<Transaction> transactions = block.getTransactions();
|
||||
assertNotNull(transactions);
|
||||
|
||||
for (Transaction transaction : transactions) {
|
||||
assertNotNull(transaction);
|
||||
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType());
|
||||
assertTrue(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0);
|
||||
assertNull(transactionData.getReference());
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
assertEquals(Transaction.ValidationResult.OK, transaction.isValid());
|
||||
}
|
||||
|
||||
// Attempt to load first transaction directly from database
|
||||
TransactionData transactionData = repository.getTransactionRepository().fromSignature(transactions.get(0).getTransactionData().getSignature());
|
||||
assertNotNull(transactionData);
|
||||
|
||||
assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType());
|
||||
assertTrue(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0);
|
||||
assertNull(transactionData.getReference());
|
||||
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
assertNotNull(transaction);
|
||||
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
assertEquals(Transaction.ValidationResult.OK, transaction.isValid());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockPaymentTransactions() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
// Block 949 has lots of varied transactions
|
||||
// Blocks 390 & 754 have only payment transactions
|
||||
BlockData blockData = repository.getBlockRepository().fromHeight(754);
|
||||
assertNotNull(blockData, "Block 754 is required for this test");
|
||||
|
||||
Block block = new Block(repository, blockData);
|
||||
assertTrue(block.isSignatureValid());
|
||||
|
||||
List<Transaction> transactions = block.getTransactions();
|
||||
assertNotNull(transactions);
|
||||
|
||||
for (Transaction transaction : transactions) {
|
||||
assertNotNull(transaction);
|
||||
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
assertEquals(Transaction.TransactionType.PAYMENT, transactionData.getType());
|
||||
assertFalse(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0);
|
||||
assertNotNull(transactionData.getReference());
|
||||
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
// Attempt to load first transaction directly from database
|
||||
TransactionData transactionData = repository.getTransactionRepository().fromSignature(transactions.get(0).getTransactionData().getSignature());
|
||||
assertNotNull(transactionData);
|
||||
|
||||
assertEquals(Transaction.TransactionType.PAYMENT, transactionData.getType());
|
||||
assertFalse(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0);
|
||||
assertNotNull(transactionData.getReference());
|
||||
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
assertNotNull(transaction);
|
||||
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockSerialization() throws DataException, TransformationException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
// Block 949 has lots of varied transactions
|
||||
// Blocks 390 & 754 have only payment transactions
|
||||
BlockData blockData = repository.getBlockRepository().fromHeight(754);
|
||||
assertNotNull(blockData, "Block 754 is required for this test");
|
||||
|
||||
Block block = new Block(repository, blockData);
|
||||
assertTrue(block.isSignatureValid());
|
||||
|
||||
byte[] bytes = BlockTransformer.toBytes(block);
|
||||
|
||||
assertEquals(BlockTransformer.getDataLength(block), bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
15
src/test/java/test/BlockchainTests.java
Normal file
15
src/test/java/test/BlockchainTests.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import qora.block.BlockChain;
|
||||
import repository.DataException;
|
||||
|
||||
public class BlockchainTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testValidateOrRebuild() throws DataException {
|
||||
BlockChain.validate();
|
||||
}
|
||||
|
||||
}
|
27
src/test/java/test/Common.java
Normal file
27
src/test/java/test/Common.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import controller.Controller;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
|
||||
import repository.DataException;
|
||||
import repository.RepositoryFactory;
|
||||
import repository.RepositoryManager;
|
||||
import repository.hsqldb.HSQLDBRepositoryFactory;
|
||||
|
||||
public class Common {
|
||||
|
||||
@BeforeAll
|
||||
public static void setRepository() throws DataException {
|
||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.connectionUrl);
|
||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void closeRepository() throws DataException {
|
||||
RepositoryManager.closeRepositoryFactory();
|
||||
}
|
||||
|
||||
}
|
66
src/test/java/test/CompatibilityTests.java
Normal file
66
src/test/java/test/CompatibilityTests.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
|
||||
import data.transaction.TransactionData;
|
||||
import qora.transaction.CreateOrderTransaction;
|
||||
import qora.transaction.CreatePollTransaction;
|
||||
import qora.transaction.IssueAssetTransaction;
|
||||
import transform.TransformationException;
|
||||
import transform.transaction.TransactionTransformer;
|
||||
|
||||
public class CompatibilityTests {
|
||||
|
||||
@Test
|
||||
public void testCreateOrderTransactionSignature() throws TransformationException {
|
||||
// 4EsGzQ87rXqXw2nic8LiihGCrM5iNErK53u9TRo2AJv4FWWyCK7bUKrCmswnrBbkB7Dsk7wfzi9hM2TGGqm6LVpd
|
||||
byte[] rawTx = HashCode
|
||||
.fromString("0000000d" + "000001489be3ef8e"
|
||||
+ "10b52b229c73afb40a56df4f1c9f65072041011cf9ae25a053397d9fc5578bc8f1412eb404de4e318e24302863fc52889eb848af65a6b17cfc964267388f5802"
|
||||
+ "bf497fa72ed16894f3acab6c4a101fd8b5fd42f0420dad45474388d5492d38d0" + "0000000000000000" + "0000000000000001"
|
||||
+ "000000000000000005f5e100" + "000000000000000005f5e100" + "0000000005f5e100"
|
||||
+ "a2025bfde5c90254e16150db6aef6189bb2856df51940b6a15b1d5f174451236062c982af4da3429941337abc7002a862782fb9c726bfc95aea31e30bf66a502")
|
||||
.asBytes();
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(rawTx);
|
||||
|
||||
CreateOrderTransaction transaction = new CreateOrderTransaction(null, transactionData);
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePollTransactionSignature() throws TransformationException {
|
||||
// 5xo8YxDVTFVR1pdmtxYkRbq3PkcKVttyH7wCVAfgqokDMKE1XW6zrqFgJG8vRQz9qi5r8cqBoSgFKLnQRoSyzpgF
|
||||
byte[] rawTx = HashCode
|
||||
.fromString("00000008" + "00000146d4237f03"
|
||||
+ "c201817ee2d4363801b63cbe154f6796719feb5a9673758dfda7b5e616cddd1263bbb75ce6a14ca116abe2d34ea68f353379d0c0d48da62180677053792f3b00"
|
||||
+ "ef893a99782612754157d868fc4194577cca8ca5dd264c90855829f0e4bbec3a" + "3a91655f3c70d7a38980b449ccf7acd84de41f99dae6215ed5" + "0000000a"
|
||||
+ "746869736973706f6c6c" + "00000004" + "74657374" + "00000002" + "00000011" + "546869732069732073706f6e6765626f62" + "00000000"
|
||||
+ "0000000f" + "54686973206973207061747269636b" + "00000000" + "0000000005f5e100"
|
||||
+ "f82f0c7421333c2cae5d0d0200e7f4726cda60baecad4ba067c7da17c681e2fb20612991f75763791b228c258f79ec2ecc40788fdda71b8f11a9032417ec7e08")
|
||||
.asBytes();
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(rawTx);
|
||||
|
||||
CreatePollTransaction transaction = new CreatePollTransaction(null, transactionData);
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssueAssetTransactionSignature() throws TransformationException {
|
||||
// 3JeJ8yGnG8RCQH51S2qYJT5nfbokjHnBmM7KZsj61HPRy8K3ZWkGHh99QQ6HbRHxnknnjjAsffHRaeca1ap3tcFv
|
||||
byte[] rawTx = HashCode
|
||||
.fromString(
|
||||
"0000000b000001489376bea34d4cbdb644be00b5848a2beeee087fdb98de49a010e686de9540f7d83720cdd182ca6efd1a6225f72f2821ed8a19f236002aef33afa4e2e419fe641c2bc4800a8dd3440f3ce0526c924f2cc15f3fdc1afcf4d57e4502c7a13bfed9851e81abc93a6a24ae1a453205b39d0c3bd24fb5eb675cd199e7cb5b316c00000003787878000000117878787878787878787878787878787878000000000000006400733fa8fa762c404ca1ddd799e93cc8ea292cd9fdd84d5c8b094050d4f576ea56071055f9fe337bf610624514f673e66462f8719759242b5635f19da088b311050000000005f5e100733fa8fa762c404ca1ddd799e93cc8ea292cd9fdd84d5c8b094050d4f576ea56071055f9fe337bf610624514f673e66462f8719759242b5635f19da088b31105")
|
||||
.asBytes();
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(rawTx);
|
||||
|
||||
IssueAssetTransaction transaction = new IssueAssetTransaction(null, transactionData);
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
}
|
38
src/test/java/test/CryptoTests.java
Normal file
38
src/test/java/test/CryptoTests.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
|
||||
import qora.crypto.Crypto;
|
||||
|
||||
public class CryptoTests {
|
||||
|
||||
@Test
|
||||
public void testCryptoDigest() {
|
||||
byte[] input = HashCode.fromString("00").asBytes();
|
||||
byte[] digest = Crypto.digest(input);
|
||||
byte[] expected = HashCode.fromString("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d").asBytes();
|
||||
|
||||
assertArrayEquals(expected, digest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCryptoDoubleDigest() {
|
||||
byte[] input = HashCode.fromString("00").asBytes();
|
||||
byte[] digest = Crypto.doubleDigest(input);
|
||||
byte[] expected = HashCode.fromString("1406e05881e299367766d313e26c05564ec91bf721d31726bd6e46e60689539a").asBytes();
|
||||
|
||||
assertArrayEquals(expected, digest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCryptoQoraAddress() {
|
||||
byte[] publicKey = HashCode.fromString("775ada64a48a30b3bfc4f1db16bca512d4088704975a62bde78781ce0cba90d6").asBytes();
|
||||
String expected = "QUD9y7NZqTtNwvSAUfewd7zKUGoVivVnTW";
|
||||
|
||||
assertEquals(expected, Crypto.toAddress(publicKey));
|
||||
}
|
||||
|
||||
}
|
90
src/test/java/test/ExceptionTests.java
Normal file
90
src/test/java/test/ExceptionTests.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import qora.block.Block;
|
||||
|
||||
public class ExceptionTests {
|
||||
|
||||
/**
|
||||
* Proof of concept for block processing throwing transaction-related SQLException rather than savepoint-rollback-related SQLException.
|
||||
* <p>
|
||||
* See {@link Block#isValid(Connection)}.
|
||||
*/
|
||||
@Test
|
||||
public void testBlockProcessingExceptions() {
|
||||
try {
|
||||
simulateThrow();
|
||||
fail("Should not return result");
|
||||
} catch (Exception e) {
|
||||
assertEquals("Transaction issue", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
boolean result = simulateFalse();
|
||||
assertFalse(result);
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
boolean result = simulateTrue();
|
||||
assertTrue(result);
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean simulateThrow() throws Exception {
|
||||
// simulate create savepoint (no-op)
|
||||
|
||||
try {
|
||||
// simulate processing transactions but an exception is thrown
|
||||
throw new Exception("Transaction issue");
|
||||
} finally {
|
||||
// attempt to rollback
|
||||
try {
|
||||
// simulate failing to rollback due to prior exception
|
||||
throw new Exception("Rollback issue");
|
||||
} catch (Exception e) {
|
||||
// test discard of rollback exception, leaving prior exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean simulateFalse() throws Exception {
|
||||
// simulate create savepoint (no-op)
|
||||
|
||||
try {
|
||||
// simulate processing transactions but false returned
|
||||
return false;
|
||||
} finally {
|
||||
// attempt to rollback
|
||||
try {
|
||||
// simulate successful rollback (no-op)
|
||||
} catch (Exception e) {
|
||||
// test discard of rollback exception, leaving prior exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean simulateTrue() throws Exception {
|
||||
// simulate create savepoint (no-op)
|
||||
|
||||
try {
|
||||
// simulate processing transactions successfully
|
||||
} finally {
|
||||
// attempt to rollback
|
||||
try {
|
||||
// simulate successful rollback (no-op)
|
||||
} catch (Exception e) {
|
||||
// test discard of rollback exception, leaving prior exception
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
93
src/test/java/test/GenesisTests.java
Normal file
93
src/test/java/test/GenesisTests.java
Normal file
@@ -0,0 +1,93 @@
|
||||
package test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
|
||||
import data.transaction.TransactionData;
|
||||
import qora.account.Account;
|
||||
import qora.assets.Asset;
|
||||
import qora.block.Block;
|
||||
import qora.block.GenesisBlock;
|
||||
import qora.transaction.Transaction;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryFactory;
|
||||
import repository.RepositoryManager;
|
||||
import repository.hsqldb.HSQLDBRepositoryFactory;
|
||||
|
||||
// Don't extend Common as we want an in-memory database
|
||||
public class GenesisTests {
|
||||
|
||||
public static final String connectionUrl = "jdbc:hsqldb:mem:db/blockchain;create=true";
|
||||
|
||||
@BeforeAll
|
||||
public static void setRepository() throws DataException {
|
||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void closeRepository() throws DataException {
|
||||
RepositoryManager.closeRepositoryFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenesisBlockTransactions() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
assertEquals(0, repository.getBlockRepository().getBlockchainHeight(), "Blockchain should be empty for this test");
|
||||
|
||||
GenesisBlock block = GenesisBlock.getInstance(repository);
|
||||
|
||||
assertNotNull(block);
|
||||
assertTrue(block.isSignatureValid());
|
||||
// Note: only true if blockchain is empty
|
||||
assertEquals(Block.ValidationResult.OK, block.isValid());
|
||||
|
||||
List<Transaction> transactions = block.getTransactions();
|
||||
assertNotNull(transactions);
|
||||
|
||||
for (Transaction transaction : transactions) {
|
||||
assertNotNull(transaction);
|
||||
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType());
|
||||
assertTrue(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0);
|
||||
assertNull(transactionData.getReference());
|
||||
assertNotNull(transactionData.getSignature());
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
assertEquals(Transaction.ValidationResult.OK, transaction.isValid());
|
||||
}
|
||||
|
||||
// Actually try to process genesis block onto empty blockchain
|
||||
block.process();
|
||||
repository.saveChanges();
|
||||
|
||||
// Attempt to load first transaction directly from database
|
||||
TransactionData transactionData = repository.getTransactionRepository().fromSignature(transactions.get(0).getTransactionData().getSignature());
|
||||
assertNotNull(transactionData);
|
||||
|
||||
assertEquals(Transaction.TransactionType.GENESIS, transactionData.getType());
|
||||
assertTrue(transactionData.getFee().compareTo(BigDecimal.ZERO) == 0);
|
||||
assertNull(transactionData.getReference());
|
||||
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
assertNotNull(transaction);
|
||||
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
assertEquals(Transaction.ValidationResult.OK, transaction.isValid());
|
||||
|
||||
// Check known balance
|
||||
Account testAccount = new Account(repository, "QegT2Ws5YjLQzEZ9YMzWsAZMBE8cAygHZN");
|
||||
BigDecimal testBalance = testAccount.getConfirmedBalance(Asset.QORA);
|
||||
BigDecimal expectedBalance = new BigDecimal("12606834").setScale(8);
|
||||
assertTrue(testBalance.compareTo(expectedBalance) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
94
src/test/java/test/LoadTests.java
Normal file
94
src/test/java/test/LoadTests.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import data.transaction.PaymentTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.transaction.Transaction.TransactionType;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import repository.TransactionRepository;
|
||||
import utils.Base58;
|
||||
|
||||
public class LoadTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testLoadPaymentTransaction() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TransactionRepository transactionRepository = repository.getTransactionRepository();
|
||||
|
||||
assertTrue(repository.getBlockRepository().getBlockchainHeight() >= 49778,
|
||||
"Migrate from old database to at least block 49778 before running this test");
|
||||
|
||||
String signature58 = "1211ZPwG3hk5evWzXCZi9hMDRpwumWmkENjwWkeTCik9xA5uoYnxzF7rwR5hmHH3kG2RXo7ToCAaRc7dvnynByJt";
|
||||
byte[] signature = Base58.decode(signature58);
|
||||
|
||||
TransactionData transactionData = transactionRepository.fromSignature(signature);
|
||||
assertNotNull(transactionData, "Transaction data not loaded from repository");
|
||||
assertEquals(TransactionType.PAYMENT, transactionData.getType(), "Transaction data not PAYMENT type");
|
||||
assertEquals("QXwu8924WdgPoRmtiWQBUMF6eedmp1Hu2E", PublicKeyAccount.getAddress(transactionData.getCreatorPublicKey()));
|
||||
|
||||
PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData;
|
||||
|
||||
assertNotNull(paymentTransactionData);
|
||||
assertEquals("QXwu8924WdgPoRmtiWQBUMF6eedmp1Hu2E", PublicKeyAccount.getAddress(paymentTransactionData.getSenderPublicKey()));
|
||||
assertEquals("QZsv8vbJ6QfrBNba4LMp5UtHhAzhrxvVUU", paymentTransactionData.getRecipient());
|
||||
assertEquals(1416209264000L, paymentTransactionData.getTimestamp());
|
||||
assertEquals("31dC6kHHBeG5vYb8LMaZDjLEmhc9kQB2VUApVd8xWncSRiXu7yMejdprjYFMP2rUnzZxWd4KJhkq6LsV7rQvU1kY",
|
||||
Base58.encode(paymentTransactionData.getReference()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadFactory() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TransactionRepository transactionRepository = repository.getTransactionRepository();
|
||||
|
||||
assertTrue(repository.getBlockRepository().getBlockchainHeight() >= 49778,
|
||||
"Migrate from old database to at least block 49778 before running this test");
|
||||
|
||||
String signature58 = "1211ZPwG3hk5evWzXCZi9hMDRpwumWmkENjwWkeTCik9xA5uoYnxzF7rwR5hmHH3kG2RXo7ToCAaRc7dvnynByJt";
|
||||
byte[] signature = Base58.decode(signature58);
|
||||
|
||||
while (true) {
|
||||
TransactionData transactionData = transactionRepository.fromSignature(signature);
|
||||
if (transactionData == null)
|
||||
break;
|
||||
|
||||
if (transactionData.getType() != TransactionType.PAYMENT)
|
||||
break;
|
||||
|
||||
PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData;
|
||||
System.out.println(PublicKeyAccount.getAddress(paymentTransactionData.getSenderPublicKey()) + " sent " + paymentTransactionData.getAmount()
|
||||
+ " QORA to " + paymentTransactionData.getRecipient());
|
||||
|
||||
signature = transactionData.getReference();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadNonexistentTransaction() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TransactionRepository transactionRepository = repository.getTransactionRepository();
|
||||
|
||||
String signature58 = "1111222233334444";
|
||||
byte[] signature = Base58.decode(signature58);
|
||||
|
||||
TransactionData transactionData = transactionRepository.fromSignature(signature);
|
||||
|
||||
if (transactionData != null) {
|
||||
PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData;
|
||||
|
||||
System.out.println(PublicKeyAccount.getAddress(paymentTransactionData.getSenderPublicKey()) + " sent " + paymentTransactionData.getAmount()
|
||||
+ " QORA to " + paymentTransactionData.getRecipient());
|
||||
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
46
src/test/java/test/NavigationTests.java
Normal file
46
src/test/java/test/NavigationTests.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import data.block.BlockData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.transaction.Transaction.TransactionType;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import repository.TransactionRepository;
|
||||
import utils.Base58;
|
||||
|
||||
public class NavigationTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testNavigateFromTransactionToBlock() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TransactionRepository transactionRepository = repository.getTransactionRepository();
|
||||
|
||||
assertTrue(repository.getBlockRepository().getBlockchainHeight() >= 49778,
|
||||
"Migrate from old database to at least block 49778 before running this test");
|
||||
|
||||
String signature58 = "1211ZPwG3hk5evWzXCZi9hMDRpwumWmkENjwWkeTCik9xA5uoYnxzF7rwR5hmHH3kG2RXo7ToCAaRc7dvnynByJt";
|
||||
byte[] signature = Base58.decode(signature58);
|
||||
|
||||
System.out.println("Navigating to Block from transaction " + signature58);
|
||||
|
||||
TransactionData transactionData = transactionRepository.fromSignature(signature);
|
||||
assertNotNull(transactionData, "Transaction data not loaded from repository");
|
||||
assertEquals(TransactionType.PAYMENT, transactionData.getType(), "Transaction data not PAYMENT type");
|
||||
|
||||
int transactionHeight = transactionRepository.getHeightFromSignature(signature);
|
||||
assertNotEquals(0, transactionHeight, "Transaction not found or transaction's block not found");
|
||||
assertEquals(49778, transactionHeight, "Transaction's block height expected to be 49778");
|
||||
|
||||
BlockData blockData = repository.getBlockRepository().fromHeight(transactionHeight);
|
||||
assertNotNull(blockData, "Block 49778 not loaded from database");
|
||||
System.out.println("Block " + blockData.getHeight() + ", signature: " + Base58.encode(blockData.getSignature()));
|
||||
|
||||
assertEquals((Integer) 49778, blockData.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
57
src/test/java/test/RepositoryTests.java
Normal file
57
src/test/java/test/RepositoryTests.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
|
||||
public class RepositoryTests extends Common {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(RepositoryTests.class);
|
||||
|
||||
@Test
|
||||
public void testGetRepository() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
assertNotNull(repository);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleInstances() throws DataException {
|
||||
int n_instances = 5;
|
||||
Repository[] repositories = new Repository[n_instances];
|
||||
|
||||
for (int i = 0; i < n_instances; ++i) {
|
||||
repositories[i] = RepositoryManager.getRepository();
|
||||
assertNotNull(repositories[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_instances; ++i) {
|
||||
repositories[i].close();
|
||||
repositories[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessAfterClose() throws DataException {
|
||||
try (Repository repository = RepositoryManager.getRepository()) {
|
||||
assertNotNull(repository);
|
||||
|
||||
repository.close();
|
||||
|
||||
try {
|
||||
repository.discardChanges();
|
||||
fail();
|
||||
} catch (NullPointerException | DataException e) {
|
||||
}
|
||||
|
||||
LOGGER.warn("Expect \"repository already closed\" complaint below");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
35
src/test/java/test/SaveTests.java
Normal file
35
src/test/java/test/SaveTests.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import data.transaction.PaymentTransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import utils.Base58;
|
||||
|
||||
public class SaveTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testSavePaymentTransaction() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
String reference58 = "rrrr";
|
||||
byte[] reference = Base58.decode(reference58);
|
||||
String signature58 = "ssss";
|
||||
byte[] signature = Base58.decode(signature58);
|
||||
PublicKeyAccount sender = new PublicKeyAccount(repository, "Qsender".getBytes());
|
||||
|
||||
PaymentTransactionData paymentTransactionData = new PaymentTransactionData(sender.getPublicKey(), "Qrecipient", BigDecimal.valueOf(12345L),
|
||||
BigDecimal.ONE, Instant.now().getEpochSecond(), reference, signature);
|
||||
|
||||
repository.getTransactionRepository().save(paymentTransactionData);
|
||||
|
||||
repository.discardChanges();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
156
src/test/java/test/SerializationTests.java
Normal file
156
src/test/java/test/SerializationTests.java
Normal file
@@ -0,0 +1,156 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import data.block.BlockData;
|
||||
import data.transaction.GenesisTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.block.Block;
|
||||
import qora.block.GenesisBlock;
|
||||
import qora.transaction.GenesisTransaction;
|
||||
import qora.transaction.Transaction;
|
||||
import qora.transaction.Transaction.TransactionType;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import transform.TransformationException;
|
||||
import transform.transaction.TransactionTransformer;
|
||||
|
||||
public class SerializationTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testGenesisSerialization() throws TransformationException, DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
GenesisBlock block = GenesisBlock.getInstance(repository);
|
||||
|
||||
GenesisTransaction transaction = (GenesisTransaction) block.getTransactions().get(1);
|
||||
assertNotNull(transaction);
|
||||
|
||||
GenesisTransactionData genesisTransactionData = (GenesisTransactionData) transaction.getTransactionData();
|
||||
|
||||
System.out.println(genesisTransactionData.getTimestamp() + ": " + genesisTransactionData.getRecipient() + " received "
|
||||
+ genesisTransactionData.getAmount().toPlainString());
|
||||
|
||||
byte[] bytes = TransactionTransformer.toBytes(genesisTransactionData);
|
||||
|
||||
GenesisTransactionData parsedTransactionData = (GenesisTransactionData) TransactionTransformer.fromBytes(bytes);
|
||||
|
||||
System.out.println(parsedTransactionData.getTimestamp() + ": " + parsedTransactionData.getRecipient() + " received "
|
||||
+ parsedTransactionData.getAmount().toPlainString());
|
||||
|
||||
/*
|
||||
* NOTE: parsedTransactionData.getSignature() will be null as no signature is present in serialized bytes and calculating the signature is performed
|
||||
* by GenesisTransaction, not GenesisTransactionData
|
||||
*/
|
||||
// Not applicable: assertTrue(Arrays.equals(genesisTransactionData.getSignature(), parsedTransactionData.getSignature()));
|
||||
|
||||
GenesisTransaction parsedTransaction = new GenesisTransaction(repository, parsedTransactionData);
|
||||
assertTrue(Arrays.equals(genesisTransactionData.getSignature(), parsedTransaction.getTransactionData().getSignature()));
|
||||
}
|
||||
}
|
||||
|
||||
private void testGenericSerialization(TransactionData transactionData) throws TransformationException {
|
||||
assertNotNull(transactionData);
|
||||
|
||||
byte[] bytes = TransactionTransformer.toBytes(transactionData);
|
||||
|
||||
TransactionData parsedTransactionData = TransactionTransformer.fromBytes(bytes);
|
||||
|
||||
assertTrue(Arrays.equals(transactionData.getSignature(), parsedTransactionData.getSignature()), "Transaction signature mismatch");
|
||||
|
||||
assertEquals(bytes.length, TransactionTransformer.getDataLength(transactionData), "Data length mismatch");
|
||||
}
|
||||
|
||||
private void testSpecificBlockTransactions(int height, TransactionType type) throws DataException, TransformationException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
BlockData blockData = repository.getBlockRepository().fromHeight(height);
|
||||
assertNotNull(blockData, "Block " + height + " is required for this test");
|
||||
|
||||
Block block = new Block(repository, blockData);
|
||||
|
||||
List<Transaction> transactions = block.getTransactions();
|
||||
assertNotNull(transactions);
|
||||
|
||||
for (Transaction transaction : transactions)
|
||||
if (transaction.getTransactionData().getType() == type)
|
||||
testGenericSerialization(transaction.getTransactionData());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaymentSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(754, TransactionType.PAYMENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterNameSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(120, TransactionType.REGISTER_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateNameSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(673, TransactionType.UPDATE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSellNameSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(200, TransactionType.SELL_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelSellNameSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(741, TransactionType.CANCEL_SELL_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuyNameSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(973, TransactionType.BUY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePollSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(10537, TransactionType.CREATE_POLL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteOnPollSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(10540, TransactionType.CREATE_POLL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssueAssetSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(33661, TransactionType.ISSUE_ASSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransferAssetSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(39039, TransactionType.TRANSFER_ASSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAssetOrderSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(35611, TransactionType.CREATE_ASSET_ORDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelAssetOrderSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(36176, TransactionType.CANCEL_ASSET_ORDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPaymentSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(34500, TransactionType.MULTIPAYMENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageSerialization() throws TransformationException, DataException {
|
||||
// Message transactions went live block 99000
|
||||
// Some transactions to be found in block 99001/2/5/6
|
||||
testSpecificBlockTransactions(99001, TransactionType.MESSAGE);
|
||||
}
|
||||
|
||||
}
|
67
src/test/java/test/SignatureTests.java
Normal file
67
src/test/java/test/SignatureTests.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import data.block.BlockData;
|
||||
import qora.account.PrivateKeyAccount;
|
||||
import qora.block.Block;
|
||||
import qora.block.GenesisBlock;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.RepositoryManager;
|
||||
import utils.Base58;
|
||||
import utils.NTP;
|
||||
|
||||
public class SignatureTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testGenesisBlockSignature() throws DataException {
|
||||
String expected58 = "6pHMBFif7jXFG654joT8GPaymau1fMtaxacRyqSrnAwQMQDvqRuLpHpfFyqX4gWVvj4pF1mwQhFgqWAvjVvPJUjmBZQvL751dM9cEcQBTaUcxtNLuWZCVUAtbnWN9f7FsLppHhkPbxwpoodL3UJYRGt3EZrG17mhv1RJbmq8j6rr7Mk";
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
GenesisBlock block = GenesisBlock.getInstance(repository);
|
||||
BlockData blockData = block.getBlockData();
|
||||
|
||||
System.out
|
||||
.println("Generator: " + block.getGenerator().getAddress() + ", generator signature: " + Base58.encode(blockData.getGeneratorSignature()));
|
||||
|
||||
assertEquals(expected58, Base58.encode(block.getSignature()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockSignature() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount generator = new PrivateKeyAccount(repository,
|
||||
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 });
|
||||
|
||||
int version = 3;
|
||||
|
||||
byte[] reference = Base58.decode(
|
||||
"BSfgEr6r1rXGGJCv8criR5NcBWfpHdJnm9x5unPwxvojEKCESv1wH1zJm7yvCeC48wshymYtARbHdUojbqWCCWW7h2UTc8g5oEx59C9M41dM7H48My8gVkcEZdxR1of3VgpE5UcowFp3kFC12hVcD9hUttJ2i2nZWMwprbFtUGyVv1U");
|
||||
|
||||
int transactionCount = 0;
|
||||
BigDecimal totalFees = BigDecimal.ZERO.setScale(8);
|
||||
byte[] transactionsSignature = null;
|
||||
int height = 0;
|
||||
long timestamp = NTP.getTime() - 5000;
|
||||
BigDecimal generatingBalance = BigDecimal.valueOf(10_000_000L).setScale(8);
|
||||
byte[] generatorPublicKey = generator.getPublicKey();
|
||||
byte[] generatorSignature = null;
|
||||
int atCount = 0;
|
||||
BigDecimal atFees = BigDecimal.valueOf(10_000_000L).setScale(8);
|
||||
|
||||
BlockData blockData = new BlockData(version, reference, transactionCount, totalFees, transactionsSignature, height, timestamp, generatingBalance,
|
||||
generatorPublicKey, generatorSignature, atCount, atFees);
|
||||
|
||||
Block block = new Block(repository, blockData, generator);
|
||||
block.sign();
|
||||
|
||||
assertTrue(block.isSignatureValid());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1188
src/test/java/test/TransactionTests.java
Normal file
1188
src/test/java/test/TransactionTests.java
Normal file
File diff suppressed because it is too large
Load Diff
18
src/test/java/test/utils/AssertExtensions.java
Normal file
18
src/test/java/test/utils/AssertExtensions.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package test.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class AssertExtensions {
|
||||
|
||||
public static <T> void assertItemsEqual(Collection<T> expected, Iterable<T> actual) {
|
||||
assertItemsEqual(expected, actual, (String) null);
|
||||
}
|
||||
|
||||
public static <T> void assertItemsEqual(Collection<T> expected, Iterable<T> actual, String message) {
|
||||
assertThat(message, actual, containsInAnyOrder(expected.toArray()));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user