checkpoint commit
This commit is contained in:
parent
acd704b0b8
commit
f1c7da339c
2
.settings/org.eclipse.core.resources.prefs
Normal file
2
.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=UTF-8
|
|
@ -57,5 +57,63 @@ cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
||||||
cleanup_profile=_opret
|
cleanup_profile=_opret
|
||||||
cleanup_settings_version=2
|
cleanup_settings_version=2
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
|
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||||
formatter_profile=_opret
|
formatter_profile=_opret
|
||||||
formatter_settings_version=12
|
formatter_settings_version=12
|
||||||
|
sp_cleanup.add_default_serial_version_id=true
|
||||||
|
sp_cleanup.add_generated_serial_version_id=false
|
||||||
|
sp_cleanup.add_missing_annotations=true
|
||||||
|
sp_cleanup.add_missing_deprecated_annotations=true
|
||||||
|
sp_cleanup.add_missing_methods=false
|
||||||
|
sp_cleanup.add_missing_nls_tags=false
|
||||||
|
sp_cleanup.add_missing_override_annotations=true
|
||||||
|
sp_cleanup.add_missing_override_annotations_interface_methods=true
|
||||||
|
sp_cleanup.add_serial_version_id=false
|
||||||
|
sp_cleanup.always_use_blocks=true
|
||||||
|
sp_cleanup.always_use_parentheses_in_expressions=true
|
||||||
|
sp_cleanup.always_use_this_for_non_static_field_access=false
|
||||||
|
sp_cleanup.always_use_this_for_non_static_method_access=false
|
||||||
|
sp_cleanup.convert_functional_interfaces=true
|
||||||
|
sp_cleanup.convert_to_enhanced_for_loop=true
|
||||||
|
sp_cleanup.correct_indentation=true
|
||||||
|
sp_cleanup.format_source_code=true
|
||||||
|
sp_cleanup.format_source_code_changes_only=false
|
||||||
|
sp_cleanup.insert_inferred_type_arguments=false
|
||||||
|
sp_cleanup.make_local_variable_final=true
|
||||||
|
sp_cleanup.make_parameters_final=false
|
||||||
|
sp_cleanup.make_private_fields_final=true
|
||||||
|
sp_cleanup.make_type_abstract_if_missing_method=false
|
||||||
|
sp_cleanup.make_variable_declarations_final=true
|
||||||
|
sp_cleanup.never_use_blocks=false
|
||||||
|
sp_cleanup.never_use_parentheses_in_expressions=false
|
||||||
|
sp_cleanup.on_save_use_additional_actions=true
|
||||||
|
sp_cleanup.organize_imports=true
|
||||||
|
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
||||||
|
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
||||||
|
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
||||||
|
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
|
||||||
|
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
||||||
|
sp_cleanup.remove_private_constructors=true
|
||||||
|
sp_cleanup.remove_redundant_type_arguments=false
|
||||||
|
sp_cleanup.remove_trailing_whitespaces=true
|
||||||
|
sp_cleanup.remove_trailing_whitespaces_all=true
|
||||||
|
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
||||||
|
sp_cleanup.remove_unnecessary_casts=true
|
||||||
|
sp_cleanup.remove_unnecessary_nls_tags=false
|
||||||
|
sp_cleanup.remove_unused_imports=true
|
||||||
|
sp_cleanup.remove_unused_local_variables=true
|
||||||
|
sp_cleanup.remove_unused_private_fields=true
|
||||||
|
sp_cleanup.remove_unused_private_members=false
|
||||||
|
sp_cleanup.remove_unused_private_methods=true
|
||||||
|
sp_cleanup.remove_unused_private_types=true
|
||||||
|
sp_cleanup.sort_members=true
|
||||||
|
sp_cleanup.sort_members_all=false
|
||||||
|
sp_cleanup.use_anonymous_class_creation=false
|
||||||
|
sp_cleanup.use_blocks=true
|
||||||
|
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
||||||
|
sp_cleanup.use_lambda=true
|
||||||
|
sp_cleanup.use_parentheses_in_expressions=true
|
||||||
|
sp_cleanup.use_this_for_non_static_field_access=false
|
||||||
|
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
||||||
|
sp_cleanup.use_this_for_non_static_method_access=false
|
||||||
|
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bitcoinj</groupId>
|
<groupId>org.bitcoinj</groupId>
|
||||||
<artifactId>bitcoinj-core</artifactId>
|
<artifactId>bitcoinj-core</artifactId>
|
||||||
|
@ -47,6 +46,11 @@
|
||||||
<version>4.3</version>
|
<version>4.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jline</groupId>
|
||||||
|
<artifactId>jline</artifactId>
|
||||||
|
<version>2.12</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -107,14 +111,9 @@
|
||||||
<version>1.2.1</version>
|
<version>1.2.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<mainClass>org.tcpid.opretj.testapp.App</mainClass>
|
<mainClass>org.tcpid.opretj.testapp.App</mainClass>
|
||||||
<!--
|
<!-- <systemProperties> <systemProperty> <key>logback.configurationFile</key>
|
||||||
<systemProperties>
|
<value>${basedir}/opret-testapp/src/main/resources/logback.xml</value> </systemProperty>
|
||||||
<systemProperty>
|
</systemProperties> -->
|
||||||
<key>logback.configurationFile</key>
|
|
||||||
<value>${basedir}/opret-testapp/src/main/resources/logback.xml</value>
|
|
||||||
</systemProperty>
|
|
||||||
</systemProperties>
|
|
||||||
-->
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
|
@ -4,11 +4,15 @@ import static org.bitcoinj.script.ScriptOpCodes.OP_RETURN;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.InputMismatchException;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
|
import org.abstractj.kalium.crypto.Box;
|
||||||
|
import org.abstractj.kalium.crypto.Hash;
|
||||||
|
import org.abstractj.kalium.keys.KeyPair;
|
||||||
|
import org.abstractj.kalium.keys.PublicKey;
|
||||||
import org.abstractj.kalium.keys.SigningKey;
|
import org.abstractj.kalium.keys.SigningKey;
|
||||||
import org.abstractj.kalium.keys.VerifyKey;
|
import org.abstractj.kalium.keys.VerifyKey;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
@ -34,6 +38,8 @@ import org.tcpid.opretj.OPRETWalletAppKit;
|
||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import com.google.common.util.concurrent.Service;
|
import com.google.common.util.concurrent.Service;
|
||||||
|
|
||||||
|
import jline.console.ConsoleReader;
|
||||||
|
import jline.console.completer.StringsCompleter;
|
||||||
import joptsimple.OptionParser;
|
import joptsimple.OptionParser;
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import joptsimple.OptionSpec;
|
import joptsimple.OptionSpec;
|
||||||
|
@ -65,6 +71,78 @@ public class App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean cryptoSelfTest() {
|
||||||
|
final KeyPair MKpair = new KeyPair();
|
||||||
|
final KeyPair VKpair = new KeyPair();
|
||||||
|
final byte[] nonce = Arrays.copyOfRange(Sha256Hash.hash("TEST".getBytes()), 0, 8);
|
||||||
|
final byte[] cipher = doubleEnc(MKpair, VKpair, "TEST".getBytes(), nonce);
|
||||||
|
// System.err.println("Cipher len: " + cipher.length);
|
||||||
|
final byte[] chk = doubleDec(MKpair.getPublicKey(), VKpair.getPublicKey(), cipher, nonce);
|
||||||
|
return Arrays.equals(chk, "TEST".getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void displayBalance(final OPRETWalletAppKit kit, final PrintWriter out) {
|
||||||
|
out.write("Balance: " + kit.wallet().getBalance().toFriendlyString() + "\n");
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void displayHelp(PrintWriter out) {
|
||||||
|
out.write("Available Commands:\n");
|
||||||
|
out.write("\n");
|
||||||
|
out.write("help - this screen\n");
|
||||||
|
out.write("quit - exit the application\n");
|
||||||
|
out.write("balance - show your available balance\n");
|
||||||
|
out.write("receive - display an address to receive coins\n");
|
||||||
|
out.write("empty <address> - send all coins to the address\n");
|
||||||
|
out.write("opret - send opret\n");
|
||||||
|
out.write("\n");
|
||||||
|
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] doubleDec(final PublicKey MK, final PublicKey VK, final byte[] cipher, final byte[] nonce) {
|
||||||
|
final Hash h = new Hash();
|
||||||
|
|
||||||
|
final KeyPair Epair = new KeyPair(
|
||||||
|
Arrays.copyOfRange(h.blake2(Bytes.concat(nonce, VK.toBytes(), MK.toBytes())), 0, 32));
|
||||||
|
|
||||||
|
final Box boxVK = new Box(VK.toBytes(), Epair.getPrivateKey().toBytes());
|
||||||
|
final byte[] nonceVK = Arrays
|
||||||
|
.copyOfRange(h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), VK.toBytes())), 0, 24);
|
||||||
|
|
||||||
|
final byte[] cipherMK = boxVK.decrypt(nonceVK, cipher);
|
||||||
|
|
||||||
|
final Box boxMK = new Box(MK.toBytes(), Epair.getPrivateKey().toBytes());
|
||||||
|
|
||||||
|
final byte[] nonceMK = Arrays
|
||||||
|
.copyOfRange(h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), MK.toBytes())), 0, 24);
|
||||||
|
|
||||||
|
final byte[] clear = boxMK.decrypt(nonceMK, cipherMK);
|
||||||
|
|
||||||
|
return clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] doubleEnc(final KeyPair MKpair, final KeyPair VKpair, final byte[] clear,
|
||||||
|
final byte[] nonce) {
|
||||||
|
final Hash h = new Hash();
|
||||||
|
|
||||||
|
final KeyPair Epair = new KeyPair(Arrays.copyOfRange(
|
||||||
|
h.blake2(Bytes.concat(nonce, VKpair.getPublicKey().toBytes(), MKpair.getPublicKey().toBytes())), 0,
|
||||||
|
32));
|
||||||
|
|
||||||
|
final Box boxMK = new Box(Epair.getPublicKey().toBytes(), MKpair.getPrivateKey().toBytes());
|
||||||
|
final byte[] nonceMK = Arrays.copyOfRange(
|
||||||
|
h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), MKpair.getPublicKey().toBytes())), 0, 24);
|
||||||
|
|
||||||
|
final byte[] cipherMK = boxMK.encrypt(nonceMK, clear);
|
||||||
|
|
||||||
|
final Box boxVK = new Box(Epair.getPublicKey().toBytes(), VKpair.getPrivateKey().toBytes());
|
||||||
|
final byte[] nonceVK = Arrays.copyOfRange(
|
||||||
|
h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), VKpair.getPublicKey().toBytes())), 0, 24);
|
||||||
|
final byte[] cipherVK = boxVK.encrypt(nonceVK, cipherMK);
|
||||||
|
return cipherVK;
|
||||||
|
}
|
||||||
|
|
||||||
private static String executeCommand(final String command) {
|
private static String executeCommand(final String command) {
|
||||||
|
|
||||||
final StringBuffer output = new StringBuffer();
|
final StringBuffer output = new StringBuffer();
|
||||||
|
@ -88,17 +166,81 @@ public class App {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void handleConsole(final OPRETWalletAppKit kit) throws IOException {
|
||||||
|
final String receiveStr = kit.wallet().freshReceiveAddress().toString();
|
||||||
|
final ConsoleReader reader = new ConsoleReader();
|
||||||
|
final String[] cmds = { "help", "quit", "exit", "balance", "receive", "empty", "opret" };
|
||||||
|
reader.addCompleter(new StringsCompleter(cmds));
|
||||||
|
final PrintWriter out = new PrintWriter(reader.getOutput());
|
||||||
|
reader.setPrompt("opret> ");
|
||||||
|
String line;
|
||||||
|
displayHelp(out);
|
||||||
|
displayBalance(kit, out);
|
||||||
|
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
final String[] argv = line.split("\\s");
|
||||||
|
if (argv.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String cmd = argv[0];
|
||||||
|
final String args[] = Arrays.copyOfRange(argv, 1, argv.length);
|
||||||
|
|
||||||
|
switch (cmd.toLowerCase()) {
|
||||||
|
case "quit":
|
||||||
|
return;
|
||||||
|
case "help":
|
||||||
|
displayHelp(out);
|
||||||
|
break;
|
||||||
|
case "balance":
|
||||||
|
displayBalance(kit, out);
|
||||||
|
break;
|
||||||
|
case "receive":
|
||||||
|
out.write("send money to: " + receiveStr + "\n");
|
||||||
|
try {
|
||||||
|
out.write(executeCommand("qrencode -t UTF8 -o - " + receiveStr));
|
||||||
|
} catch (final Exception e) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
break;
|
||||||
|
case "empty":
|
||||||
|
if (args.length != 1) {
|
||||||
|
out.println("empty needs a receive address!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "opret":
|
||||||
|
sendOPReturn(kit, out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(final String[] args) throws Exception {
|
public static void main(final String[] args) throws Exception {
|
||||||
|
|
||||||
|
final boolean chk = cryptoSelfTest();
|
||||||
|
if (chk) {
|
||||||
|
System.err.println("Crypto self test: PASSED");
|
||||||
|
} else {
|
||||||
|
System.err.println("Crypto self test: FAILED");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
final OptionParser parser = new OptionParser();
|
final OptionParser parser = new OptionParser();
|
||||||
final OptionSpec<NetworkEnum> net = parser.accepts("net", "The network to run the examples on")
|
final OptionSpec<NetworkEnum> net = parser.accepts("net", "The network to run the examples on")
|
||||||
.withRequiredArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.TEST);
|
.withRequiredArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.TEST);
|
||||||
parser.accepts("help", "Displays program options");
|
parser.accepts("help", "Displays program options");
|
||||||
final OptionSet opts = parser.parse(args);
|
final OptionSet opts = parser.parse(args);
|
||||||
if (opts.has("help") || !opts.has(net)) {
|
if (opts.has("help")) {
|
||||||
System.err.println("usage: App --net=MAIN/TEST/REGTEST");
|
System.err.println("usage: App --net=MAIN/TEST/REGTEST");
|
||||||
parser.printHelpOn(System.err);
|
parser.printHelpOn(System.err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!opts.has(net)) {
|
||||||
|
System.err.println("No net specified, using TestNet!");
|
||||||
|
}
|
||||||
|
|
||||||
final NetworkParameters params = net.value(opts).get();
|
final NetworkParameters params = net.value(opts).get();
|
||||||
|
|
||||||
final OPRETECParser bs = new OPRETECParser();
|
final OPRETECParser bs = new OPRETECParser();
|
||||||
|
@ -119,12 +261,6 @@ public class App {
|
||||||
// bs.addOPRET(Utils.HEX.decode("0f490dee643b01b06e0ea84c253a90050a3543cfb7c74319fb47b04afee5b872"),
|
// bs.addOPRET(Utils.HEX.decode("0f490dee643b01b06e0ea84c253a90050a3543cfb7c74319fb47b04afee5b872"),
|
||||||
// earliestTime);
|
// earliestTime);
|
||||||
|
|
||||||
// Now we initialize a new WalletAppKit. The kit handles all the
|
|
||||||
// boilerplate for us and is the easiest way to get everything up and
|
|
||||||
// running.
|
|
||||||
// Have a look at the WalletAppKit documentation and its source to
|
|
||||||
// understand what's happening behind the scenes:
|
|
||||||
// https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java
|
|
||||||
final OPRETWalletAppKit kit = new OPRETWalletAppKit(params, new File("."), "opretwallet" + params.getId(), bs);
|
final OPRETWalletAppKit kit = new OPRETWalletAppKit(params, new File("."), "opretwallet" + params.getId(), bs);
|
||||||
|
|
||||||
kit.addListener(new Service.Listener() {
|
kit.addListener(new Service.Listener() {
|
||||||
|
@ -135,20 +271,14 @@ public class App {
|
||||||
}
|
}
|
||||||
}, Threading.SAME_THREAD);
|
}, Threading.SAME_THREAD);
|
||||||
|
|
||||||
// In case you want to connect with your local bitcoind tell the kit to
|
|
||||||
// connect to localhost.
|
|
||||||
// You must do that in reg test mode.
|
|
||||||
if (params.getId().equals(NetworkParameters.ID_REGTEST)) {
|
if (params.getId().equals(NetworkParameters.ID_REGTEST)) {
|
||||||
kit.connectToLocalHost();
|
kit.connectToLocalHost();
|
||||||
}
|
}
|
||||||
kit.setCheckpoints(App.class.getResourceAsStream("/" + params.getId() + ".checkpoints"));
|
kit.setCheckpoints(App.class.getResourceAsStream("/" + params.getId() + ".checkpoints"));
|
||||||
// Now we start the kit and sync the blockchain.
|
|
||||||
// bitcoinj is working a lot with the Google Guava libraries. The
|
|
||||||
// WalletAppKit extends the AbstractIdleService. Have a look at the
|
|
||||||
// introduction to Guava services:
|
|
||||||
// https://github.com/google/guava/wiki/ServiceExplained
|
|
||||||
kit.startAsync();
|
kit.startAsync();
|
||||||
|
|
||||||
System.out.println("Please wait for the blockchain to be downloaded!");
|
System.out.println("Please wait for the blockchain to be downloaded!");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
kit.awaitRunning();
|
kit.awaitRunning();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
@ -166,75 +296,29 @@ public class App {
|
||||||
System.out.println("received: " + tx.getValue(wallet1));
|
System.out.println("received: " + tx.getValue(wallet1));
|
||||||
});
|
});
|
||||||
|
|
||||||
wallet.addCoinsSentEventListener((wallet1, tx, prevBalance, newBalance) -> System.out.println("coins sent"));
|
wallet.addCoinsSentEventListener(Threading.SAME_THREAD,
|
||||||
|
(wallet1, tx, prevBalance, newBalance) -> System.out.println("coins sent"));
|
||||||
|
|
||||||
wallet.addKeyChainEventListener(keys -> System.out.println("new key added"));
|
wallet.addKeyChainEventListener(Threading.SAME_THREAD, keys -> System.out.println("new key added"));
|
||||||
|
|
||||||
wallet.addScriptsChangeEventListener(
|
wallet.addScriptChangeEventListener(Threading.SAME_THREAD,
|
||||||
(wallet1, scripts, isAddingScripts) -> System.out.println("new script added"));
|
(wallet1, scripts, isAddingScripts) -> System.out.println("new script added"));
|
||||||
|
|
||||||
wallet.addTransactionConfidenceEventListener((wallet1, tx) -> {
|
wallet.addTransactionConfidenceEventListener(Threading.SAME_THREAD, (wallet1, tx) -> {
|
||||||
System.out.println("-----> confidence changed: " + tx.getHashAsString());
|
System.out.println("-----> confidence changed: " + tx.getHashAsString());
|
||||||
final TransactionConfidence confidence = tx.getConfidence();
|
final TransactionConfidence confidence = tx.getConfidence();
|
||||||
System.out.println("new block depth: " + confidence.getDepthInBlocks());
|
System.out.println("new block depth: " + confidence.getDepthInBlocks());
|
||||||
});
|
});
|
||||||
// wallet.allowSpendingUnconfirmedTransactions();
|
// wallet.allowSpendingUnconfirmedTransactions();
|
||||||
|
|
||||||
// Ready to run. The kit syncs the blockchain and our wallet event
|
handleConsole(kit);
|
||||||
// listener gets notified when something happens.
|
|
||||||
// To test everything we create and print a fresh receiving address.
|
|
||||||
// Send some coins to that address and see if everything works.
|
|
||||||
final String receiveStr = wallet.freshReceiveAddress().toString();
|
|
||||||
final Scanner input = new Scanner(System.in);
|
|
||||||
|
|
||||||
display: while (true) {
|
|
||||||
|
|
||||||
System.out.println("-- Actions --");
|
|
||||||
System.out.println("Select an option: \n" + " 0) QUIT\n" + " 1) Display Balance\n"
|
|
||||||
+ " 2) Display Receive Address\n" + " 3) Send OP_Return\n");
|
|
||||||
try {
|
|
||||||
final int selection = input.nextInt();
|
|
||||||
|
|
||||||
switch (selection) {
|
|
||||||
case 0:
|
|
||||||
System.out.println("Returning...");
|
|
||||||
break display;
|
|
||||||
case 1:
|
|
||||||
System.out.println("Balance: " + wallet.getBalance().toFriendlyString());
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
System.out.println("send money to: " + receiveStr);
|
|
||||||
try {
|
|
||||||
System.out.print(executeCommand("qrencode -t UTF8 -o - " + receiveStr));
|
|
||||||
} catch (final Exception e) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
sendOPReturn(kit);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.out.println("Invalid action.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (final InputMismatchException e) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
input.nextLine();
|
|
||||||
|
|
||||||
}
|
|
||||||
input.close();
|
|
||||||
|
|
||||||
// Make sure to properly shut down all the running services when you
|
|
||||||
// manually want to stop the kit. The WalletAppKit registers a runtime
|
|
||||||
// ShutdownHook so we actually do not need to worry about that when our
|
|
||||||
// application is stopping.
|
|
||||||
System.out.println("shutting down");
|
System.out.println("shutting down");
|
||||||
kit.stopAsync();
|
kit.stopAsync();
|
||||||
kit.awaitTerminated();
|
kit.awaitTerminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean sendOPReturn(final OPRETWalletAppKit kit) {
|
private static boolean sendOPReturn(final OPRETWalletAppKit kit, PrintWriter output) {
|
||||||
final OPRETWallet wallet = kit.opretwallet();
|
final OPRETWallet wallet = kit.opretwallet();
|
||||||
final NetworkParameters params = wallet.getNetworkParameters();
|
final NetworkParameters params = wallet.getNetworkParameters();
|
||||||
|
|
||||||
|
@ -252,8 +336,8 @@ public class App {
|
||||||
try {
|
try {
|
||||||
sr = wallet.sendCoins(request);
|
sr = wallet.sendCoins(request);
|
||||||
} catch (final InsufficientMoneyException e) {
|
} catch (final InsufficientMoneyException e) {
|
||||||
// TODO Auto-generated catch block
|
output.println(e.getLocalizedMessage());
|
||||||
e.printStackTrace();
|
output.flush();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logger.debug("SendRequest {}", request);
|
logger.debug("SendRequest {}", request);
|
||||||
|
@ -277,8 +361,8 @@ public class App {
|
||||||
try {
|
try {
|
||||||
sr = wallet.sendCoins(request);
|
sr = wallet.sendCoins(request);
|
||||||
} catch (final InsufficientMoneyException e) {
|
} catch (final InsufficientMoneyException e) {
|
||||||
// TODO Auto-generated catch block
|
output.println(e.getLocalizedMessage());
|
||||||
e.printStackTrace();
|
output.flush();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<logger name="eckey.OPRETSimpleParser" level="debug" />
|
<logger name="eckey.OPRETSimpleParser" level="debug" />
|
||||||
<logger name="eckey.OPRETBaseHandler" level="debug" />
|
<logger name="eckey.OPRETBaseHandler" level="debug" />
|
||||||
-->
|
-->
|
||||||
<root level="warn">
|
<root level="error">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</root>
|
</root>
|
||||||
</configuration>
|
</configuration>
|
3
opretj/.settings/org.eclipse.core.resources.prefs
Normal file
3
opretj/.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
|
@ -1,5 +1,5 @@
|
||||||
package org.tcpid.opretj;
|
package org.tcpid.opretj;
|
||||||
|
|
||||||
public interface OPRETECRevokeEventListener {
|
public interface OPRETECEventListener {
|
||||||
void onOPRETRevoke(final byte[] pkhash, final byte[] sig);
|
void onOPRETRevoke(final byte[] pkhash, final byte[] sig);
|
||||||
}
|
}
|
130
opretj/src/main/java/org/tcpid/opretj/OPRETECExampleParser.java
Normal file
130
opretj/src/main/java/org/tcpid/opretj/OPRETECExampleParser.java
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package org.tcpid.opretj;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.PartialMerkleTree;
|
||||||
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
|
import org.bitcoinj.core.Utils;
|
||||||
|
import org.bitcoinj.utils.ListenerRegistration;
|
||||||
|
import org.bitcoinj.utils.Threading;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
|
||||||
|
public class OPRETECExampleParser extends OPRETBaseHandler {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(OPRETECExampleParser.class);
|
||||||
|
private static final List<Byte> OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec1d"));
|
||||||
|
protected final Map<Sha256Hash, PartialMerkleTree> merkleHashMap = new HashMap<>();
|
||||||
|
protected final Map<Sha256Hash, OPRETTransaction> transHashMap = new HashMap<>();
|
||||||
|
private final CopyOnWriteArrayList<ListenerRegistration<OPRETECEventListener>> opReturnChangeListeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an event listener object. Methods on this object are called when
|
||||||
|
* scripts watched by this wallet change. The listener is executed by the
|
||||||
|
* given executor.
|
||||||
|
*/
|
||||||
|
public void addOPRETECRevokeEventListener(final OPRETECEventListener listener) {
|
||||||
|
// This is thread safe, so we don't need to take the lock.
|
||||||
|
opReturnChangeListeners
|
||||||
|
.add(new ListenerRegistration<OPRETECEventListener>(listener, Threading.SAME_THREAD));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkData(final OPRETTransaction t1, final OPRETTransaction t2) {
|
||||||
|
final List<List<Byte>> opret_data = new ArrayList<>(t1.opretData);
|
||||||
|
opret_data.addAll(t2.opretData);
|
||||||
|
logger.debug("checking {}", opret_data);
|
||||||
|
|
||||||
|
List<Byte> chunk;
|
||||||
|
chunk = opret_data.get(0);
|
||||||
|
if (!chunk.equals(OPRET_MAGIC)) {
|
||||||
|
logger.debug("0: != OPRET_MAGIC");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = opret_data.get(1);
|
||||||
|
if (chunk.size() != 1) {
|
||||||
|
logger.debug("1: size != 1");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk.get(0) == (byte) 0xFE) {
|
||||||
|
if (opret_data.size() != 8) {
|
||||||
|
logger.debug("FE: size != 8");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chunk = opret_data.get(4);
|
||||||
|
if (!chunk.equals(OPRET_MAGIC)) {
|
||||||
|
logger.debug("FE 4 != OPRET_MAGIC");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!opret_data.get(2).equals(opret_data.get(6))) {
|
||||||
|
logger.debug("FE 2 != 6");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chunk = opret_data.get(5);
|
||||||
|
if ((chunk.size() != 1) || (chunk.get(0) != (byte) 0xFF)) {
|
||||||
|
logger.debug("FE 5 size!=1 or != FF");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handleRevoke(t1, t2);
|
||||||
|
} else {
|
||||||
|
logger.debug("1: != 0xFE");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleRevoke(final OPRETTransaction t1, final OPRETTransaction t2) {
|
||||||
|
final byte[] pkhash = Bytes.toArray(t1.opretData.get(2));
|
||||||
|
final byte[] sig = Bytes.concat(Bytes.toArray(t1.opretData.get(3)), Bytes.toArray(t2.opretData.get(3)));
|
||||||
|
|
||||||
|
logger.debug("REVOKE PK {} - SIG {}", Utils.HEX.encode(pkhash), Utils.HEX.encode(sig));
|
||||||
|
queueOnOPRETRevoke(pkhash, sig);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushData(final Sha256Hash blockHash, final Sha256Hash txHash, final Set<Sha256Hash> txPrevHash,
|
||||||
|
final List<List<Byte>> opret_data) {
|
||||||
|
final OPRETTransaction optrans = new OPRETTransaction(blockHash, txHash, txPrevHash, opret_data);
|
||||||
|
logger.debug("pushData: {}", optrans);
|
||||||
|
for (final Sha256Hash t : txPrevHash) {
|
||||||
|
if (transHashMap.containsKey(t)) {
|
||||||
|
final OPRETTransaction opprev = transHashMap.get(t);
|
||||||
|
if (checkData(opprev, optrans)) {
|
||||||
|
transHashMap.remove(t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transHashMap.put(txHash, optrans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushMerkle(final Sha256Hash blockHash, final PartialMerkleTree partialMerkleTree) {
|
||||||
|
merkleHashMap.put(blockHash, partialMerkleTree);
|
||||||
|
logger.info("block hash {}", blockHash);
|
||||||
|
logger.info("Merkle Tree: {}", partialMerkleTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void queueOnOPRETRevoke(final byte[] pkhash, final byte[] sig) {
|
||||||
|
for (final ListenerRegistration<OPRETECEventListener> registration : opReturnChangeListeners) {
|
||||||
|
registration.executor.execute(() -> registration.listener.onOPRETRevoke(pkhash, sig));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given event listener object. Returns true if the listener was
|
||||||
|
* removed, false if that listener was never added.
|
||||||
|
*/
|
||||||
|
public boolean removeOPRETECRevokeEventListener(final OPRETECEventListener listener) {
|
||||||
|
return ListenerRegistration.removeFromList(listener, opReturnChangeListeners);
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,17 +22,17 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
private static final List<Byte> OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec1d"));
|
private static final List<Byte> OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec1d"));
|
||||||
protected final Map<Sha256Hash, PartialMerkleTree> merkleHashMap = new HashMap<>();
|
protected final Map<Sha256Hash, PartialMerkleTree> merkleHashMap = new HashMap<>();
|
||||||
protected final Map<Sha256Hash, OPRETTransaction> transHashMap = new HashMap<>();
|
protected final Map<Sha256Hash, OPRETTransaction> transHashMap = new HashMap<>();
|
||||||
private final CopyOnWriteArrayList<ListenerRegistration<OPRETECRevokeEventListener>> opReturnChangeListeners = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<ListenerRegistration<OPRETECEventListener>> opReturnChangeListeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an event listener object. Methods on this object are called when
|
* Adds an event listener object. Methods on this object are called when
|
||||||
* scripts watched by this wallet change. The listener is executed by the
|
* scripts watched by this wallet change. The listener is executed by the
|
||||||
* given executor.
|
* given executor.
|
||||||
*/
|
*/
|
||||||
public void addOPRETECRevokeEventListener(final OPRETECRevokeEventListener listener) {
|
public void addOPRETECRevokeEventListener(final OPRETECEventListener listener) {
|
||||||
// This is thread safe, so we don't need to take the lock.
|
// This is thread safe, so we don't need to take the lock.
|
||||||
opReturnChangeListeners
|
opReturnChangeListeners
|
||||||
.add(new ListenerRegistration<OPRETECRevokeEventListener>(listener, Threading.USER_THREAD));
|
.add(new ListenerRegistration<OPRETECEventListener>(listener, Threading.SAME_THREAD));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkData(final OPRETTransaction t1, final OPRETTransaction t2) {
|
private boolean checkData(final OPRETTransaction t1, final OPRETTransaction t2) {
|
||||||
|
@ -115,7 +115,7 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void queueOnOPRETRevoke(final byte[] pkhash, final byte[] sig) {
|
protected void queueOnOPRETRevoke(final byte[] pkhash, final byte[] sig) {
|
||||||
for (final ListenerRegistration<OPRETECRevokeEventListener> registration : opReturnChangeListeners) {
|
for (final ListenerRegistration<OPRETECEventListener> registration : opReturnChangeListeners) {
|
||||||
registration.executor.execute(() -> registration.listener.onOPRETRevoke(pkhash, sig));
|
registration.executor.execute(() -> registration.listener.onOPRETRevoke(pkhash, sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
* Removes the given event listener object. Returns true if the listener was
|
* Removes the given event listener object. Returns true if the listener was
|
||||||
* removed, false if that listener was never added.
|
* removed, false if that listener was never added.
|
||||||
*/
|
*/
|
||||||
public boolean removeOPRETECRevokeEventListener(final OPRETECRevokeEventListener listener) {
|
public boolean removeOPRETECRevokeEventListener(final OPRETECEventListener listener) {
|
||||||
return ListenerRegistration.removeFromList(listener, opReturnChangeListeners);
|
return ListenerRegistration.removeFromList(listener, opReturnChangeListeners);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,12 @@ public class OPRETWalletAppKit extends WalletAppKit {
|
||||||
// TODO: remove
|
// TODO: remove
|
||||||
wallet.reset();
|
wallet.reset();
|
||||||
peerGroup().addBlocksDownloadedEventListener(wallet);
|
peerGroup().addBlocksDownloadedEventListener(wallet);
|
||||||
|
// setupCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public ListenableFuture setupCompleted() { return; }
|
||||||
|
*/
|
||||||
public OPRETWallet opretwallet() throws RuntimeException, IllegalStateException {
|
public OPRETWallet opretwallet() throws RuntimeException, IllegalStateException {
|
||||||
checkState((state() == State.STARTING) || (state() == State.RUNNING), "Cannot call until startup is complete");
|
checkState((state() == State.STARTING) || (state() == State.RUNNING), "Cannot call until startup is complete");
|
||||||
final Wallet w = wallet();
|
final Wallet w = wallet();
|
||||||
|
|
Loading…
Reference in a new issue