initial commit

This commit is contained in:
Harald Hoyer 2016-08-30 16:05:27 +02:00
commit e72cebcb28
27 changed files with 1281 additions and 0 deletions

31
opret-testapp/.classpath Normal file
View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

4
opret-testapp/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target/
/walletappkit-example.spvchain
/walletappkit-example.wallet
/opretwalletorg.bitcoin.test.wallet

23
opret-testapp/.project Normal file
View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>opret-testapp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

84
opret-testapp/pom.xml Normal file
View file

@ -0,0 +1,84 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.tcpid</groupId>
<artifactId>opret-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>opret-testapp</artifactId>
<dependencies>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.14.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>org.abstractj.kalium</groupId>
<artifactId>kalium</artifactId>
<version>0.5.0</version>
</dependency>
<dependency>
<groupId>org.tcpid</groupId>
<artifactId>opretj</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
<version>4.3</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.tcpid.opretj.testapp.App</mainClass>
<systemProperties>
<systemProperty>
<key>logback.configurationFile</key>
<value>${basedir}/opret-testapp/src/main/resources/logback.xml</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,297 @@
package org.tcpid.opretj.testapp;
import static org.bitcoinj.script.ScriptOpCodes.OP_RETURN;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
import org.abstractj.kalium.keys.SigningKey;
import org.abstractj.kalium.keys.VerifyKey;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.wallet.KeyChain.KeyPurpose;
import org.bitcoinj.wallet.SendRequest;
import org.bitcoinj.wallet.Wallet;
import org.bitcoinj.wallet.Wallet.SendResult;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.bitcoinj.wallet.listeners.ScriptsChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsSentEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tcpid.opretj.*;
import com.google.common.primitives.Bytes;
public class App {
private static final Logger logger = LoggerFactory.getLogger(App.class);
public static final long OPRET_BIRTHDAY = 1471989600;
static byte[] rawKey = Sha256Hash.hash("TESTSEED".getBytes());
static SigningKey sk = new SigningKey(rawKey);
static VerifyKey v = sk.getVerifyKey();
private static byte[] pkhash = Sha256Hash.hash(v.toBytes());
static byte[] revokemsg = Bytes.concat("Revoke ".getBytes(), pkhash);
public static void check(final byte[] pkhash, final byte[] sig) {
logger.warn("CHECKING REVOKE PK {} - SIG {}", Utils.HEX.encode(pkhash), Utils.HEX.encode(sig));
if (!Arrays.equals(App.pkhash, pkhash)) {
logger.warn("Unknown PK {}", Utils.HEX.encode(pkhash));
return;
}
logger.warn("Using VerifyKey {}", v);
if (v.verify(revokemsg, sig)) {
logger.warn("REVOKED VerifyKey {}", v);
} else {
logger.warn("SIGNATURE does not match!");
}
}
public static void main(String[] args) throws Exception {
OptionParser parser = new OptionParser();
OptionSpec<NetworkEnum> net = parser.accepts("net", "The network to run the examples on").withRequiredArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.TEST);
parser.accepts("help", "Displays program options");
OptionSet opts = parser.parse(args);
if (opts.has("help") || !opts.has(net)) {
System.err.println("usage: App --net=MAIN/TEST/REGTEST");
parser.printHelpOn(System.err);
return;
}
final NetworkParameters params = net.value(opts).get();
final OPRETECParser bs = new OPRETECParser();
bs.addOPRETECRevokeEventListener(new OPRETECRevokeEventListener() {
public void onOPRETRevoke(final byte[] pkhash, final byte[] sig) {
// logger.warn("REVOKE PK {} - SIG {}",
// Utils.HEX.encode(pkhash), Utils.HEX.encode(sig));
check(pkhash, sig);
}
});
long earliestTime;
if (params.getId().equals(NetworkParameters.ID_REGTEST)) {
earliestTime = OPRET_BIRTHDAY;
} else if (params.getId().equals(NetworkParameters.ID_TESTNET)) {
earliestTime = OPRET_BIRTHDAY;
} else {
earliestTime = Utils.currentTimeSeconds();
}
bs.addOPRET(pkhash, earliestTime);
//bs.addOPRET(Sha256Hash.hash("test1".getBytes()), earliestTime);
//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);
// 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();
}
// 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.awaitRunning();
final OPRETWallet wallet = kit.opretwallet();
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("-----> coins resceived: " + tx.getHashAsString());
System.out.println("received: " + tx.getValue(wallet));
}
});
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("coins sent");
}
});
wallet.addKeyChainEventListener(new KeyChainEventListener() {
public void onKeysAdded(List<ECKey> keys) {
System.out.println("new key added");
}
});
wallet.addScriptsChangeEventListener(new ScriptsChangeEventListener() {
public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
System.out.println("new script added");
}
});
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
public void onTransactionConfidenceChanged(Wallet wallet, Transaction 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.
String receiveStr = wallet.freshReceiveAddress().toString();
System.out.println("send money to: " + receiveStr);
try {
System.out.print(executeCommand("qrencode -t UTF8 -o - " + receiveStr));
} catch (Exception e) {
;
}
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: " + wallet.freshReceiveAddress().toString());
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 again");
kit.stopAsync();
kit.awaitTerminated();
}
private static boolean sendOPReturn(OPRETWalletAppKit kit) {
final OPRETWallet wallet = kit.opretwallet();
final NetworkParameters params = wallet.getNetworkParameters();
Transaction t = new Transaction(params);
final byte[] sig = sk.sign(revokemsg);
Script script = new ScriptBuilder().op(OP_RETURN).data(Utils.HEX.decode("ec1d")).data(Utils.HEX.decode("fe"))
.data(pkhash).data(Arrays.copyOfRange(sig, 0, 32)).build();
t.addOutput(Coin.ZERO, script);
t.addOutput(Transaction.DEFAULT_TX_FEE, wallet.freshAddress(KeyPurpose.CHANGE));
SendRequest request = SendRequest.forTx(t);
request.ensureMinRequiredFee = true;
SendResult sr = null;
try {
sr = wallet.sendCoins(request);
} catch (final InsufficientMoneyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
logger.debug("SendRequest {}", request);
script = new ScriptBuilder().op(OP_RETURN).data(Utils.HEX.decode("ec1d")).data(Utils.HEX.decode("ff"))
.data(pkhash).data(Arrays.copyOfRange(sig, 32, 64)).build();
t = new Transaction(params);
for (final TransactionOutput out : sr.tx.getOutputs()) {
if (out.getValue().compareTo(Transaction.DEFAULT_TX_FEE) == 0) {
logger.debug("Add Output: {} of value {}", out, out.getValue());
t.addInput(out);
}
}
t.addOutput(Coin.ZERO, script);
request = SendRequest.forTx(t);
request.ensureMinRequiredFee = true;
sr = null;
try {
sr = wallet.sendCoins(request);
} catch (final InsufficientMoneyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
logger.debug("SendRequest {}", request);
return true;
}
private static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2013 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tcpid.opretj.testapp;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.params.TestNet3Params;
public enum NetworkEnum {
MAIN,
PROD, // alias for MAIN
TEST,
REGTEST;
public NetworkParameters get() {
switch(this) {
case MAIN:
case PROD:
return MainNetParams.get();
case TEST:
return TestNet3Params.get();
case REGTEST:
default:
return RegTestParams.get();
}
}
}

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder
by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.tcpid.opretj.testapp.App" level="debug" />
<logger name="org.tcpid.opretj.OPRETECParser" level="debug" />
<!--
<logger name="eckey.OPRETSimpleLogger" level="debug" />
<logger name="eckey.OPRETSimpleParser" level="debug" />
<logger name="eckey.OPRETBaseHandler" level="debug" />
-->
<root level="warn">
<appender-ref ref="STDOUT" />
</root>
</configuration>