initial commit
This commit is contained in:
commit
e72cebcb28
27 changed files with 1281 additions and 0 deletions
31
opret-testapp/.classpath
Normal file
31
opret-testapp/.classpath
Normal 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
4
opret-testapp/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target/
|
||||
/walletappkit-example.spvchain
|
||||
/walletappkit-example.wallet
|
||||
/opretwalletorg.bitcoin.test.wallet
|
23
opret-testapp/.project
Normal file
23
opret-testapp/.project
Normal 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>
|
5
opret-testapp/.settings/org.eclipse.jdt.core.prefs
Normal file
5
opret-testapp/.settings/org.eclipse.jdt.core.prefs
Normal 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
|
4
opret-testapp/.settings/org.eclipse.m2e.core.prefs
Normal file
4
opret-testapp/.settings/org.eclipse.m2e.core.prefs
Normal file
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
84
opret-testapp/pom.xml
Normal file
84
opret-testapp/pom.xml
Normal 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>
|
297
opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java
Normal file
297
opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java
Normal 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();
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
21
opret-testapp/src/main/resources/logback.xml
Normal file
21
opret-testapp/src/main/resources/logback.xml
Normal 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>
|
Loading…
Add table
Add a link
Reference in a new issue