diff --git a/lib/org/ciyam/at/1.2/at-1.2.jar b/lib/org/ciyam/at/1.2/at-1.2.jar new file mode 100644 index 00000000..862c37c6 Binary files /dev/null and b/lib/org/ciyam/at/1.2/at-1.2.jar differ diff --git a/lib/org/ciyam/at/1.2/at-1.2.pom b/lib/org/ciyam/at/1.2/at-1.2.pom new file mode 100644 index 00000000..dd16b150 --- /dev/null +++ b/lib/org/ciyam/at/1.2/at-1.2.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + org.ciyam + at + 1.2 + POM was created from install:install-file + diff --git a/lib/org/ciyam/at/maven-metadata-local.xml b/lib/org/ciyam/at/maven-metadata-local.xml index 61f9d592..ccf3a2dd 100644 --- a/lib/org/ciyam/at/maven-metadata-local.xml +++ b/lib/org/ciyam/at/maven-metadata-local.xml @@ -3,10 +3,11 @@ org.ciyam at - 1.0 + 1.2 1.0 + 1.2 - 20181105100741 + 20191120104937 diff --git a/src/main/java/org/qora/crosschain/BTCACCT.java b/src/main/java/org/qora/crosschain/BTCACCT.java new file mode 100644 index 00000000..297c6364 --- /dev/null +++ b/src/main/java/org/qora/crosschain/BTCACCT.java @@ -0,0 +1,181 @@ +package org.qora.crosschain; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import org.ciyam.at.FunctionCode; +import org.ciyam.at.MachineState; +import org.ciyam.at.OpCode; +import org.qora.utils.BitTwiddling; + +import com.google.common.hash.HashCode; +import com.google.common.primitives.Bytes; + +public class BTCACCT { + + private static final byte[] redeemScript1 = HashCode.fromString("76a820").asBytes(); // OP_DUP OP_SHA256 push(0x20 bytes) + private static final byte[] redeemScript2 = HashCode.fromString("87637576a914").asBytes(); // OP_EQUAL OP_IF OP_DROP OP_DUP OP_HASH160 push(0x14 bytes) + private static final byte[] redeemScript3 = HashCode.fromString("88ac6704").asBytes(); // OP_EQUALVERIFY OP_CHECKSIG OP_ELSE push(0x4 bytes) + private static final byte[] redeemScript4 = HashCode.fromString("b17576a914").asBytes(); // OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 push(0x14 bytes) + private static final byte[] redeemScript5 = HashCode.fromString("88ac68").asBytes(); // OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF + + /** + * Returns Bitcoin redeem script. + *

+ *

+	 * OP_DUP OP_SHA256 push(0x20) <SHA256 of secret> OP_EQUAL
+	 * OP_IF
+	 * 	OP_DROP OP_DUP OP_HASH160 push(0x14) <HASH160 of recipient pubkey>
+	 *	OP_EQUALVERIFY OP_CHECKSIG
+	 * OP_ELSE
+	 * 	push(0x04) <refund locktime> OP_CHECKLOCKTIMEVERIFY
+	 *	OP_DROP OP_DUP OP_HASH160 push(0x14) <HASH160 of sender pubkey>
+	 *	OP_EQUALVERIFY OP_CHECKSIG
+	 * OP_ENDIF
+	 * 
+ * + * @param secretHash + * @param senderPubKey + * @param recipientPubKey + * @param lockTime + * @return + */ + public static byte[] buildRedeemScript(byte[] secretHash, byte[] senderPubKey, byte[] recipientPubKey, long lockTime) { + byte[] senderPubKeyHash160 = BTC.hash160(senderPubKey); + byte[] recipientPubKeyHash160 = BTC.hash160(recipientPubKey); + + return Bytes.concat(redeemScript1, secretHash, redeemScript2, recipientPubKeyHash160, redeemScript3, BitTwiddling.toLEByteArray((int) (lockTime & 0xffffffffL)), + redeemScript4, senderPubKeyHash160, redeemScript5); + } + + public static byte[] buildCiyamAT(byte[] secretHash, byte[] destinationQortalPubKey, long refundMinutes) { + // Labels for data segment addresses + int addrCounter = 0; + final int addrHashPart1 = addrCounter++; + final int addrHashPart2 = addrCounter++; + final int addrHashPart3 = addrCounter++; + final int addrHashPart4 = addrCounter++; + final int addrAddressPart1 = addrCounter++; + final int addrAddressPart2 = addrCounter++; + final int addrAddressPart3 = addrCounter++; + final int addrAddressPart4 = addrCounter++; + final int addrRefundMinutes = addrCounter++; + final int addrRefundTimestamp = addrCounter++; + final int addrLastTimestamp = addrCounter++; + final int addrBlockTimestamp = addrCounter++; + final int addrTxType = addrCounter++; + final int addrComparator = addrCounter++; + final int addrAddressTemp1 = addrCounter++; + final int addrAddressTemp2 = addrCounter++; + final int addrAddressTemp3 = addrCounter++; + final int addrAddressTemp4 = addrCounter++; + + // Data segment + ByteBuffer dataByteBuffer = ByteBuffer.allocate(addrCounter * 8).order(ByteOrder.LITTLE_ENDIAN); + + // Hash of secret into HashPart1-4 + dataByteBuffer.put(secretHash); + + // Destination Qortal account's public key + dataByteBuffer.put(destinationQortalPubKey); + + // Expiry in minutes + dataByteBuffer.putLong(refundMinutes); + + // Code labels + final int addrTxLoop = 0x36; + final int addrCheckTx = 0x4b; + final int addrCheckSender = 0x64; + final int addrCheckMessage = 0xab; + final int addrPayout = 0xdf; + final int addrRefund = 0x102; + final int addrEndOfCode = 0x109; + + int tempPC; + ByteBuffer codeByteBuffer = ByteBuffer.allocate(addrEndOfCode * 1).order(ByteOrder.LITTLE_ENDIAN); + + // init: + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_CREATION_TIMESTAMP.value).putInt(addrRefundTimestamp); + codeByteBuffer.put(OpCode.SET_DAT.value).putInt(addrLastTimestamp).putInt(addrRefundTimestamp); + codeByteBuffer.put(OpCode.EXT_FUN_RET_DAT_2.value).putShort(FunctionCode.ADD_MINUTES_TO_TIMESTAMP.value).putInt(addrRefundTimestamp) + .putInt(addrRefundTimestamp).putInt(addrRefundMinutes); + codeByteBuffer.put(OpCode.SET_PCS.value); + + // loop: + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_BLOCK_TIMESTAMP.value).putInt(addrBlockTimestamp); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BLT_DAT.value).putInt(addrBlockTimestamp).putInt(addrRefundTimestamp).put((byte) (addrTxLoop - tempPC)); + codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(addrRefund); + + // txloop: + assert codeByteBuffer.position() == addrTxLoop : "addrTxLoop incorrect"; + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.PUT_TX_AFTER_TIMESTAMP_IN_A.value).putInt(addrLastTimestamp); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.CHECK_A_IS_ZERO.value).putInt(addrComparator); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BZR_DAT.value).putInt(addrComparator).put((byte) (addrCheckTx - tempPC)); + codeByteBuffer.put(OpCode.STP_IMD.value); + + // checkTx: + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_TIMESTAMP_FROM_TX_IN_A.value).putInt(addrLastTimestamp); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_TYPE_FROM_TX_IN_A.value).putInt(addrTxType); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BNZ_DAT.value).putInt(addrTxType).put((byte) (addrCheckSender - tempPC)); + codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(addrTxLoop); + + // checkSender + assert codeByteBuffer.position() == addrCheckSender : "addrCheckSender incorrect"; + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PUT_ADDRESS_FROM_TX_IN_A_INTO_B.value); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B1.value).putInt(addrAddressTemp1); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B2.value).putInt(addrAddressTemp2); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B3.value).putInt(addrAddressTemp3); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B4.value).putInt(addrAddressTemp4); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp1).putInt(addrAddressPart1).put((byte) (addrTxLoop - tempPC)); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp2).putInt(addrAddressPart2).put((byte) (addrTxLoop - tempPC)); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp3).putInt(addrAddressPart3).put((byte) (addrTxLoop - tempPC)); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp4).putInt(addrAddressPart4).put((byte) (addrTxLoop - tempPC)); + + // checkMessage: + assert codeByteBuffer.position() == addrCheckMessage : "addrCheckMessage incorrect"; + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PUT_MESSAGE_FROM_TX_IN_A_INTO_B.value); + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.SWAP_A_AND_B.value); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B1.value).putInt(addrHashPart1); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B2.value).putInt(addrHashPart2); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B3.value).putInt(addrHashPart3); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B4.value).putInt(addrHashPart4); + codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.CHECK_SHA256_A_WITH_B.value).putInt(addrComparator); + tempPC = codeByteBuffer.position(); + codeByteBuffer.put(OpCode.BNZ_DAT.value).putInt(addrComparator).put((byte) (addrPayout - tempPC)); + codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(addrTxLoop); + + // payout: + assert codeByteBuffer.position() == addrPayout : "addrPayout incorrect"; + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B1.value).putInt(addrAddressPart1); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B2.value).putInt(addrAddressPart2); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B3.value).putInt(addrAddressPart3); + codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B4.value).putInt(addrAddressPart4); + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.MESSAGE_A_TO_ADDRESS_IN_B.value); + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PAY_ALL_TO_ADDRESS_IN_B.value); + codeByteBuffer.put(OpCode.FIN_IMD.value); + + // refund: + assert codeByteBuffer.position() == addrRefund : "addrRefund incorrect"; + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PUT_CREATOR_INTO_B.value); + codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PAY_ALL_TO_ADDRESS_IN_B.value); + codeByteBuffer.put(OpCode.FIN_IMD.value); + + // end-of-code + assert codeByteBuffer.position() == addrEndOfCode : "addrEndOfCode incorrect"; + + final short ciyamAtVersion = 2; + final short numCallStackPages = 0; + final short numUserStackPages = 0; + final long minActivationAmount = 0L; + + return MachineState.toCreationBytes(ciyamAtVersion, codeByteBuffer.array(), dataByteBuffer.array(), numCallStackPages, numUserStackPages, minActivationAmount); + } + +} diff --git a/src/main/java/org/qortal/crosschain/BTC.java b/src/main/java/org/qortal/crosschain/BTC.java index 17b5cc66..83a8bb07 100644 --- a/src/main/java/org/qortal/crosschain/BTC.java +++ b/src/main/java/org/qortal/crosschain/BTC.java @@ -14,6 +14,7 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.DigestOutputStream; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.List; import java.util.concurrent.ExecutionException; @@ -47,8 +48,28 @@ import org.qortal.settings.Settings; public class BTC { - private static class RollbackBlockChain extends BlockChain { + private static final MessageDigest RIPE_MD160_DIGESTER; + private static final MessageDigest SHA256_DIGESTER; + static { + try { + RIPE_MD160_DIGESTER = MessageDigest.getInstance("RIPEMD160"); + SHA256_DIGESTER = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + private static BTC instance; + + private static File directory; + private static String chainFileName; + private static String checkpointsFileName; + + private static NetworkParameters params; + private static PeerGroup peerGroup; + private static BlockStore blockStore; + + private static class RollbackBlockChain extends BlockChain { public RollbackBlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException { super(params, blockStore); } @@ -57,11 +78,10 @@ public class BTC { public void setChainHead(StoredBlock chainHead) throws BlockStoreException { super.setChainHead(chainHead); } - } + private static RollbackBlockChain chain; private static class UpdateableCheckpointManager extends CheckpointManager implements NewBestBlockListener { - private static final int checkpointInterval = 500; private static final String minimalTestNet3TextFile = "TXT CHECKPOINTS 1\n0\n1\nAAAAAAAAB+EH4QfhAAAH4AEAAAApmwX6UCEnJcYIKTa7HO3pFkqqNhAzJVBMdEuGAAAAAPSAvVCBUypCbBW/OqU0oIF7ISF84h2spOqHrFCWN9Zw6r6/T///AB0E5oOO\n"; @@ -130,23 +150,24 @@ public class BTC { } } } - } - - private static BTC instance; - private static final Object instanceLock = new Object(); - - private static File directory; - private static String chainFileName; - private static String checkpointsFileName; - - private static NetworkParameters params; - private static PeerGroup peerGroup; - private static BlockStore blockStore; - private static RollbackBlockChain chain; private static UpdateableCheckpointManager manager; private BTC() { + } + + public static synchronized BTC getInstance() { + if (instance == null) + instance = new BTC(); + + return instance; + } + + public static byte[] hash160(byte[] message) { + return RIPE_MD160_DIGESTER.digest(SHA256_DIGESTER.digest(message)); + } + + public void start() { // Start wallet if (Settings.getInstance().useBitcoinTestNet()) { params = TestNet3Params.get(); @@ -196,20 +217,11 @@ public class BTC { peerGroup.start(); } - public static synchronized BTC getInstance() { + public synchronized void shutdown() { if (instance == null) - instance = new BTC(); + return; - return instance; - } - - public void shutdown() { - synchronized (instanceLock) { - if (instance == null) - return; - - instance = null; - } + instance = null; peerGroup.stop(); diff --git a/src/main/java/org/qortal/utils/BitTwiddling.java b/src/main/java/org/qortal/utils/BitTwiddling.java index e17e6034..ada2c2f5 100644 --- a/src/main/java/org/qortal/utils/BitTwiddling.java +++ b/src/main/java/org/qortal/utils/BitTwiddling.java @@ -21,4 +21,9 @@ public class BitTwiddling { return maxValue; } + /** Convert int to little-endian byte array */ + public static byte[] toLEByteArray(int value) { + return new byte[] { (byte) (value), (byte) (value >> 8), (byte) (value >> 16), (byte) (value >> 24) }; + } + } diff --git a/src/test/java/org/qora/test/btcacct/Initiate1.java b/src/test/java/org/qora/test/btcacct/Initiate1.java new file mode 100644 index 00000000..859a7d2e --- /dev/null +++ b/src/test/java/org/qora/test/btcacct/Initiate1.java @@ -0,0 +1,107 @@ +package org.qora.test.btcacct; + +import java.security.SecureRandom; +import java.security.Security; + +import org.bitcoinj.core.Address; +import org.bitcoinj.core.ECKey; +import org.bitcoinj.core.LegacyAddress; +import org.bitcoinj.core.NetworkParameters; +import org.bitcoinj.params.TestNet3Params; +import org.bitcoinj.script.Script.ScriptType; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.qora.account.PublicKeyAccount; +import org.qora.crosschain.BTC; +import org.qora.crosschain.BTCACCT; +import org.qora.crypto.Crypto; +import org.qora.utils.Base58; + +import com.google.common.hash.HashCode; + +/** + * 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 Initiate1 { + + private static final long REFUND_TIMEOUT = 600L; // seconds + + private static void usage() { + System.err.println(String.format("usage: Initiate1 ")); + System.err.println(String.format("example: Initiate1 6rNn9b3pYRrG9UKqzMWYZ9qa8F3Zgv2mVWrULGHUusb \\\n" + + "\t03aa20871c2195361f2826c7a649eab6b42639630c4d8c33c55311d5c1e476b5d6 \\\n" + + "\t123 0.00008642 \\\n" + + "\tJBNBQQDzZsm5do1BrwWAp53Ps4KYJVt749EGpCf7ofte \\\n" + + "\t032783606be32a3e639a33afe2b15f058708ab124f3b290d595ee954390a0c8559")); + System.exit(1); + } + + public static void main(String[] args) { + if (args.length != 6) + usage(); + + Security.insertProviderAt(new BouncyCastleProvider(), 0); + NetworkParameters params = TestNet3Params.get(); + + String yourQortPubKey58 = args[0]; + String yourBitcoinPubKeyHex = args[1]; + + String theirBitcoinPubKeyHex = args[5]; + + try { + System.out.println("Confirm the following is correct based on the info you've given:"); + + byte[] yourQortPubKey = Base58.decode(yourQortPubKey58); + PublicKeyAccount yourQortalAccount = new PublicKeyAccount(null, yourQortPubKey); + System.out.println(String.format("Your Qortal address: %s", yourQortalAccount.getAddress())); + + byte[] yourBitcoinPubKey = HashCode.fromString(yourBitcoinPubKeyHex).asBytes(); + ECKey yourBitcoinKey = ECKey.fromPublicOnly(yourBitcoinPubKey); + Address yourBitcoinAddress = Address.fromKey(params, yourBitcoinKey, ScriptType.P2PKH); + System.out.println(String.format("Your Bitcoin address: %s", yourBitcoinAddress.toString())); + + byte[] theirBitcoinPubKey = HashCode.fromString(theirBitcoinPubKeyHex).asBytes(); + ECKey theirBitcoinKey = ECKey.fromPublicOnly(theirBitcoinPubKey); + Address theirBitcoinAddress = Address.fromKey(params, theirBitcoinKey, ScriptType.P2PKH); + System.out.println(String.format("Their Bitcoin address: %s", theirBitcoinAddress.toString())); + + // New/derived info + + byte[] secret = new byte[32]; + new SecureRandom().nextBytes(secret); + System.out.println("\nSecret info (DO NOT share with other party):"); + System.out.println("Secret: " + HashCode.fromBytes(secret).toString()); + + System.out.println("\nGive this info to other party:"); + + byte[] secretHash = Crypto.digest(secret); + System.out.println("Hash of secret: " + HashCode.fromBytes(secretHash).toString()); + + long lockTime = System.currentTimeMillis() + REFUND_TIMEOUT; + byte[] redeemScriptBytes = BTCACCT.buildRedeemScript(secretHash, yourBitcoinPubKey, theirBitcoinPubKey, lockTime); + System.out.println("Redeem script: " + HashCode.fromBytes(redeemScriptBytes).toString()); + + byte[] redeemScriptHash = BTC.hash160(redeemScriptBytes); + + Address p2shAddress = LegacyAddress.fromScriptHash(params, redeemScriptHash); + System.out.println("P2SH address: " + p2shAddress.toString()); + } catch (NumberFormatException e) { + usage(); + } + } + +} diff --git a/src/test/java/org/qortal/test/apps/BTCACCTTests.java b/src/test/java/org/qortal/test/apps/BTCACCTTests.java index e33eacfa..499cf743 100644 --- a/src/test/java/org/qortal/test/apps/BTCACCTTests.java +++ b/src/test/java/org/qortal/test/apps/BTCACCTTests.java @@ -70,11 +70,11 @@ public class BTCACCTTests { // 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 usePreviousFundingTx = false; private static final boolean doRefundNotRedeem = false; - public void main(String[] args) throws NoSuchAlgorithmException, InsufficientMoneyException, InterruptedException, ExecutionException, UnknownHostException { + public static void main(String[] args) throws NoSuchAlgorithmException, InsufficientMoneyException, InterruptedException, ExecutionException, UnknownHostException { Security.insertProviderAt(new BouncyCastleProvider(), 0); byte[] secret = new byte[32]; @@ -173,7 +173,7 @@ public class BTCACCTTests { 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) { + private static byte[] buildRedeemScript(byte[] secret, byte[] senderPubKey, byte[] recipientPubKey, long lockTime) { try { MessageDigest sha256Digester = MessageDigest.getInstance("SHA-256"); @@ -188,7 +188,7 @@ public class BTCACCTTests { } } - private byte[] hash160(byte[] input) { + private static byte[] hash160(byte[] input) { try { MessageDigest rmd160Digester = MessageDigest.getInstance("RIPEMD160"); MessageDigest sha256Digester = MessageDigest.getInstance("SHA-256"); @@ -199,7 +199,7 @@ public class BTCACCTTests { } } - private Transaction buildFundingTransaction(NetworkParameters params, Sha256Hash prevTxHash, long outputIndex, Coin balance, ECKey sigKey, Coin value, + private static Transaction buildFundingTransaction(NetworkParameters params, Sha256Hash prevTxHash, long outputIndex, Coin balance, ECKey sigKey, Coin value, byte[] redeemScriptHash) { Transaction fundingTransaction = new Transaction(params); @@ -218,7 +218,7 @@ public class BTCACCTTests { return fundingTransaction; } - private Transaction buildRedeemTransaction(NetworkParameters params, TransactionOutPoint fundingOutPoint, ECKey recipientKey, Coin value, byte[] secret, + private static Transaction buildRedeemTransaction(NetworkParameters params, TransactionOutPoint fundingOutPoint, ECKey recipientKey, Coin value, byte[] secret, byte[] redeemScriptBytes) { Transaction redeemTransaction = new Transaction(params); redeemTransaction.setVersion(2); @@ -255,7 +255,7 @@ public class BTCACCTTests { return redeemTransaction; } - private Transaction buildRefundTransaction(NetworkParameters params, TransactionOutPoint fundingOutPoint, ECKey senderKey, Coin value, + private static Transaction buildRefundTransaction(NetworkParameters params, TransactionOutPoint fundingOutPoint, ECKey senderKey, Coin value, byte[] redeemScriptBytes, long lockTime) { Transaction refundTransaction = new Transaction(params); refundTransaction.setVersion(2); @@ -294,7 +294,7 @@ public class BTCACCTTests { return refundTransaction; } - private void broadcastWithConfirmation(WalletAppKit kit, Transaction transaction) { + private static void broadcastWithConfirmation(WalletAppKit kit, Transaction transaction) { System.out.println("Broadcasting tx: " + transaction.getTxId().toString()); System.out.println("TX hex: " + HashCode.fromBytes(transaction.bitcoinSerialize()).toString()); @@ -320,7 +320,7 @@ public class BTCACCTTests { } /** Convert int to little-endian byte array */ - private byte[] toLEByteArray(int value) { + private static byte[] toLEByteArray(int value) { return new byte[] { (byte) (value), (byte) (value >> 8), (byte) (value >> 16), (byte) (value >> 24) }; }