checkpoint commit

This commit is contained in:
Harald Hoyer 2016-09-01 18:17:38 +02:00
parent acd704b0b8
commit f1c7da339c
10 changed files with 370 additions and 90 deletions

View file

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View file

@ -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

View file

@ -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>

View file

@ -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;
} }

View file

@ -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>

View file

@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding/<project>=UTF-8

View file

@ -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);
} }

View 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);
}
}

View file

@ -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);
} }
} }

View file

@ -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();