From f1c7da339cbd16d49ea11d8702d78bf2a8937db1 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 1 Sep 2016 18:17:38 +0200 Subject: [PATCH] checkpoint commit --- .settings/org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.ui.prefs | 58 +++++ opret-testapp/pom.xml | 17 +- .../java/org/tcpid/opretj/testapp/App.java | 232 ++++++++++++------ opret-testapp/src/main/resources/logback.xml | 2 +- .../org.eclipse.core.resources.prefs | 3 + ...istener.java => OPRETECEventListener.java} | 2 +- .../tcpid/opretj/OPRETECExampleParser.java | 130 ++++++++++ .../java/org/tcpid/opretj/OPRETECParser.java | 10 +- .../org/tcpid/opretj/OPRETWalletAppKit.java | 4 + 10 files changed, 370 insertions(+), 90 deletions(-) create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 opretj/.settings/org.eclipse.core.resources.prefs rename opretj/src/main/java/org/tcpid/opretj/{OPRETECRevokeEventListener.java => OPRETECEventListener.java} (66%) create mode 100644 opretj/src/main/java/org/tcpid/opretj/OPRETECExampleParser.java diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/opret-testapp/.settings/org.eclipse.jdt.ui.prefs b/opret-testapp/.settings/org.eclipse.jdt.ui.prefs index 97a17af..be768a4 100644 --- a/opret-testapp/.settings/org.eclipse.jdt.ui.prefs +++ b/opret-testapp/.settings/org.eclipse.jdt.ui.prefs @@ -57,5 +57,63 @@ cleanup.use_this_for_non_static_method_access_only_if_necessary=true cleanup_profile=_opret cleanup_settings_version=2 eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true formatter_profile=_opret 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 diff --git a/opret-testapp/pom.xml b/opret-testapp/pom.xml index 3ef8c53..62b6ed3 100644 --- a/opret-testapp/pom.xml +++ b/opret-testapp/pom.xml @@ -10,7 +10,6 @@ - org.bitcoinj bitcoinj-core @@ -47,6 +46,11 @@ 4.3 + + jline + jline + 2.12 + @@ -107,14 +111,9 @@ 1.2.1 org.tcpid.opretj.testapp.App - + diff --git a/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java index 286bf80..d2538c9 100644 --- a/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java +++ b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java @@ -4,11 +4,15 @@ import static org.bitcoinj.script.ScriptOpCodes.OP_RETURN; import java.io.BufferedReader; import java.io.File; +import java.io.IOException; import java.io.InputStreamReader; +import java.io.PrintWriter; 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.VerifyKey; import org.bitcoinj.core.Coin; @@ -34,6 +38,8 @@ import org.tcpid.opretj.OPRETWalletAppKit; import com.google.common.primitives.Bytes; import com.google.common.util.concurrent.Service; +import jline.console.ConsoleReader; +import jline.console.completer.StringsCompleter; import joptsimple.OptionParser; import joptsimple.OptionSet; 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
- 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) { 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 { + + 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 OptionSpec net = parser.accepts("net", "The network to run the examples on") .withRequiredArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.TEST); parser.accepts("help", "Displays program options"); 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"); parser.printHelpOn(System.err); return; } + if (!opts.has(net)) { + System.err.println("No net specified, using TestNet!"); + } + final NetworkParameters params = net.value(opts).get(); final OPRETECParser bs = new OPRETECParser(); @@ -119,12 +261,6 @@ public class App { // bs.addOPRET(Utils.HEX.decode("0f490dee643b01b06e0ea84c253a90050a3543cfb7c74319fb47b04afee5b872"), // 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); kit.addListener(new Service.Listener() { @@ -135,20 +271,14 @@ public class App { } }, 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)) { kit.connectToLocalHost(); } 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(); + System.out.println("Please wait for the blockchain to be downloaded!"); + try { kit.awaitRunning(); } catch (final Exception e) { @@ -166,75 +296,29 @@ public class App { 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")); - wallet.addTransactionConfidenceEventListener((wallet1, tx) -> { + wallet.addTransactionConfidenceEventListener(Threading.SAME_THREAD, (wallet1, tx) -> { System.out.println("-----> confidence changed: " + tx.getHashAsString()); final TransactionConfidence confidence = tx.getConfidence(); System.out.println("new block depth: " + confidence.getDepthInBlocks()); }); // wallet.allowSpendingUnconfirmedTransactions(); - // Ready to run. The kit syncs the blockchain and our wallet event - // 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); + handleConsole(kit); - 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"); kit.stopAsync(); kit.awaitTerminated(); } - private static boolean sendOPReturn(final OPRETWalletAppKit kit) { + private static boolean sendOPReturn(final OPRETWalletAppKit kit, PrintWriter output) { final OPRETWallet wallet = kit.opretwallet(); final NetworkParameters params = wallet.getNetworkParameters(); @@ -252,8 +336,8 @@ public class App { try { sr = wallet.sendCoins(request); } catch (final InsufficientMoneyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + output.println(e.getLocalizedMessage()); + output.flush(); return false; } logger.debug("SendRequest {}", request); @@ -277,8 +361,8 @@ public class App { try { sr = wallet.sendCoins(request); } catch (final InsufficientMoneyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + output.println(e.getLocalizedMessage()); + output.flush(); return false; } diff --git a/opret-testapp/src/main/resources/logback.xml b/opret-testapp/src/main/resources/logback.xml index 0766c01..2af399f 100644 --- a/opret-testapp/src/main/resources/logback.xml +++ b/opret-testapp/src/main/resources/logback.xml @@ -20,7 +20,7 @@ --> - + \ No newline at end of file diff --git a/opretj/.settings/org.eclipse.core.resources.prefs b/opretj/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..e9441bb --- /dev/null +++ b/opretj/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding/=UTF-8 diff --git a/opretj/src/main/java/org/tcpid/opretj/OPRETECRevokeEventListener.java b/opretj/src/main/java/org/tcpid/opretj/OPRETECEventListener.java similarity index 66% rename from opretj/src/main/java/org/tcpid/opretj/OPRETECRevokeEventListener.java rename to opretj/src/main/java/org/tcpid/opretj/OPRETECEventListener.java index a1547ff..d96122a 100644 --- a/opretj/src/main/java/org/tcpid/opretj/OPRETECRevokeEventListener.java +++ b/opretj/src/main/java/org/tcpid/opretj/OPRETECEventListener.java @@ -1,5 +1,5 @@ package org.tcpid.opretj; -public interface OPRETECRevokeEventListener { +public interface OPRETECEventListener { void onOPRETRevoke(final byte[] pkhash, final byte[] sig); } diff --git a/opretj/src/main/java/org/tcpid/opretj/OPRETECExampleParser.java b/opretj/src/main/java/org/tcpid/opretj/OPRETECExampleParser.java new file mode 100644 index 0000000..b3f3ce9 --- /dev/null +++ b/opretj/src/main/java/org/tcpid/opretj/OPRETECExampleParser.java @@ -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 OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec1d")); + protected final Map merkleHashMap = new HashMap<>(); + protected final Map transHashMap = new HashMap<>(); + private final CopyOnWriteArrayList> 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(listener, Threading.SAME_THREAD)); + } + + private boolean checkData(final OPRETTransaction t1, final OPRETTransaction t2) { + final List> opret_data = new ArrayList<>(t1.opretData); + opret_data.addAll(t2.opretData); + logger.debug("checking {}", opret_data); + + List 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 txPrevHash, + final List> 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 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); + } +} diff --git a/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java b/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java index 63e5771..3d8760f 100644 --- a/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java +++ b/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java @@ -22,17 +22,17 @@ public class OPRETECParser extends OPRETBaseHandler { private static final List OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec1d")); protected final Map merkleHashMap = new HashMap<>(); protected final Map transHashMap = new HashMap<>(); - private final CopyOnWriteArrayList> opReturnChangeListeners = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList> 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 OPRETECRevokeEventListener listener) { + public void addOPRETECRevokeEventListener(final OPRETECEventListener listener) { // This is thread safe, so we don't need to take the lock. opReturnChangeListeners - .add(new ListenerRegistration(listener, Threading.USER_THREAD)); + .add(new ListenerRegistration(listener, Threading.SAME_THREAD)); } 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) { - for (final ListenerRegistration registration : opReturnChangeListeners) { + for (final ListenerRegistration registration : opReturnChangeListeners) { 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 * 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); } } diff --git a/opretj/src/main/java/org/tcpid/opretj/OPRETWalletAppKit.java b/opretj/src/main/java/org/tcpid/opretj/OPRETWalletAppKit.java index d4a1783..aeb69d5 100644 --- a/opretj/src/main/java/org/tcpid/opretj/OPRETWalletAppKit.java +++ b/opretj/src/main/java/org/tcpid/opretj/OPRETWalletAppKit.java @@ -30,8 +30,12 @@ public class OPRETWalletAppKit extends WalletAppKit { // TODO: remove wallet.reset(); peerGroup().addBlocksDownloadedEventListener(wallet); + // setupCompleted(); } + /* + * public ListenableFuture setupCompleted() { return; } + */ public OPRETWallet opretwallet() throws RuntimeException, IllegalStateException { checkState((state() == State.STARTING) || (state() == State.RUNNING), "Cannot call until startup is complete"); final Wallet w = wallet();