Merge branch 'develop'

This commit is contained in:
Nelson R. Perez 2017-05-20 16:29:10 -05:00
commit a72f8bc0c8
60 changed files with 1871 additions and 2034 deletions

1
.gitignore vendored
View file

@ -8,6 +8,7 @@
# ------
.gradle
gradle
graphenej/build
/build
/buildSrc/build
/subprojects/*/build

View file

@ -17,7 +17,7 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
VERSION_NAME=0.4.1
VERSION_NAME=0.4.1-SNAPSHOT
VERSION_CODE=3
GROUP=com.github.kenCode-de

View file

@ -1,96 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Class de.bitsharesmunich.graphenej.AssetTest</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Class de.bitsharesmunich.graphenej.AssetTest</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> &gt;
<a href="../packages/de.bitsharesmunich.graphenej.html">de.bitsharesmunich.graphenej</a> &gt; AssetTest</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">1</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">0</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.004s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox success" id="successRate">
<div class="percent">100%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Tests</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Tests</h2>
<table>
<thead>
<tr>
<th>Test</th>
<th>Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td class="success">equals</td>
<td>0.004s</td>
<td class="success">passed</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,191 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Class de.bitsharesmunich.graphenej.AuthorityTest</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Class de.bitsharesmunich.graphenej.AuthorityTest</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> &gt;
<a href="../packages/de.bitsharesmunich.graphenej.html">de.bitsharesmunich.graphenej</a> &gt; AuthorityTest</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">2</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">1</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.215s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox failures" id="successRate">
<div class="percent">50%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Failed tests</a>
</li>
<li>
<a href="#tab1">Tests</a>
</li>
<li>
<a href="#tab2">Standard output</a>
</li>
<li>
<a href="#tab3">Standard error</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Failed tests</h2>
<div class="test">
<a name="equals"></a>
<h3 class="failures">equals</h3>
<span class="code">
<pre>java.lang.AssertionError: Different authorities expected:&lt;de.bitsharesmunich.graphenej.Authority@4108679d&gt; but was:&lt;de.bitsharesmunich.graphenej.Authority@5155d26c&gt;
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at de.bitsharesmunich.graphenej.AuthorityTest.equals(AuthorityTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:377)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
</pre>
</span>
</div>
</div>
<div id="tab1" class="tab">
<h2>Tests</h2>
<table>
<thead>
<tr>
<th>Test</th>
<th>Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td class="failures">equals</td>
<td>0.214s</td>
<td class="failures">failed</td>
</tr>
<tr>
<td class="success">toBytes</td>
<td>0.001s</td>
<td class="success">passed</td>
</tr>
</table>
</div>
<div id="tab2" class="tab">
<h2>Standard output</h2>
<span class="code">
<pre>key auths match: true
account auths match: true
weight threshold matches: true
key auths match: true
account auths match: false
weight threshold matches: true
</pre>
</span>
</div>
<div id="tab3" class="tab">
<h2>Standard error</h2>
<span class="code">
<pre>SLF4J: Failed to load class &quot;org.slf4j.impl.StaticLoggerBinder&quot;.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
</pre>
</span>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,158 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Class de.bitsharesmunich.graphenej.PublicKeyTest</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Class de.bitsharesmunich.graphenej.PublicKeyTest</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> &gt;
<a href="../packages/de.bitsharesmunich.graphenej.html">de.bitsharesmunich.graphenej</a> &gt; PublicKeyTest</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">1</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">1</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.001s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox failures" id="successRate">
<div class="percent">0%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Failed tests</a>
</li>
<li>
<a href="#tab1">Tests</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Failed tests</h2>
<div class="test">
<a name="equals"></a>
<h3 class="failures">equals</h3>
<span class="code">
<pre>org.bitcoinj.core.AddressFormatException: Illegal character 0 at position 48
at org.bitcoinj.core.Base58.decode(Base58.java:110)
at de.bitsharesmunich.graphenej.Address.&lt;init&gt;(Address.java:33)
at de.bitsharesmunich.graphenej.PublicKeyTest.equals(PublicKeyTest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:377)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
</pre>
</span>
</div>
</div>
<div id="tab1" class="tab">
<h2>Tests</h2>
<table>
<thead>
<tr>
<th>Test</th>
<th>Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td class="failures">equals</td>
<td>0.001s</td>
<td class="failures">failed</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,121 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Class de.bitsharesmunich.graphenej.objects.MemoTest</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Class de.bitsharesmunich.graphenej.objects.MemoTest</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> &gt;
<a href="../packages/de.bitsharesmunich.graphenej.objects.html">de.bitsharesmunich.graphenej.objects</a> &gt; MemoTest</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">6</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">0</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.067s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox success" id="successRate">
<div class="percent">100%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Tests</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Tests</h2>
<table>
<thead>
<tr>
<th>Test</th>
<th>Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td class="success">shouldBeByteSerializable</td>
<td>0.003s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">shouldBeJsonObjectSerializable</td>
<td>0.009s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">shouldEncryptAndDecryptLongerMessage</td>
<td>0.006s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">shouldEncryptAndDecryptShortMessage</td>
<td>0.031s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">shouldMatchPredefinedChiphertext</td>
<td>0.005s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">shouldThrowException</td>
<td>0.013s</td>
<td class="success">passed</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,179 +0,0 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 12pt;
}
body, a, a:visited {
color: #303030;
}
#content {
padding-left: 50px;
padding-right: 50px;
padding-top: 30px;
padding-bottom: 30px;
}
#content h1 {
font-size: 160%;
margin-bottom: 10px;
}
#footer {
margin-top: 100px;
font-size: 80%;
white-space: nowrap;
}
#footer, #footer a {
color: #a0a0a0;
}
#line-wrapping-toggle {
vertical-align: middle;
}
#label-for-line-wrapping-toggle {
vertical-align: middle;
}
ul {
margin-left: 0;
}
h1, h2, h3 {
white-space: nowrap;
}
h2 {
font-size: 120%;
}
ul.tabLinks {
padding-left: 0;
padding-top: 10px;
padding-bottom: 10px;
overflow: auto;
min-width: 800px;
width: auto !important;
width: 800px;
}
ul.tabLinks li {
float: left;
height: 100%;
list-style: none;
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 0;
-moz-border-radius: 7px;
border-radius: 7px;
margin-right: 25px;
border: solid 1px #d4d4d4;
background-color: #f0f0f0;
}
ul.tabLinks li:hover {
background-color: #fafafa;
}
ul.tabLinks li.selected {
background-color: #c5f0f5;
border-color: #c5f0f5;
}
ul.tabLinks a {
font-size: 120%;
display: block;
outline: none;
text-decoration: none;
margin: 0;
padding: 0;
}
ul.tabLinks li h2 {
margin: 0;
padding: 0;
}
div.tab {
}
div.selected {
display: block;
}
div.deselected {
display: none;
}
div.tab table {
min-width: 350px;
width: auto !important;
width: 350px;
border-collapse: collapse;
}
div.tab th, div.tab table {
border-bottom: solid #d0d0d0 1px;
}
div.tab th {
text-align: left;
white-space: nowrap;
padding-left: 6em;
}
div.tab th:first-child {
padding-left: 0;
}
div.tab td {
white-space: nowrap;
padding-left: 6em;
padding-top: 5px;
padding-bottom: 5px;
}
div.tab td:first-child {
padding-left: 0;
}
div.tab td.numeric, div.tab th.numeric {
text-align: right;
}
span.code {
display: inline-block;
margin-top: 0em;
margin-bottom: 1em;
}
span.code pre {
font-size: 11pt;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
margin: 0;
background-color: #f7f7f7;
border: solid 1px #d0d0d0;
min-width: 700px;
width: auto !important;
width: 700px;
}
span.wrapped pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-all;
}
label.hidden {
display: none;
}

View file

@ -1,84 +0,0 @@
#summary {
margin-top: 30px;
margin-bottom: 40px;
}
#summary table {
border-collapse: collapse;
}
#summary td {
vertical-align: top;
}
.breadcrumbs, .breadcrumbs a {
color: #606060;
}
.infoBox {
width: 110px;
padding-top: 15px;
padding-bottom: 15px;
text-align: center;
}
.infoBox p {
margin: 0;
}
.counter, .percent {
font-size: 120%;
font-weight: bold;
margin-bottom: 8px;
}
#duration {
width: 125px;
}
#successRate, .summaryGroup {
border: solid 2px #d0d0d0;
-moz-border-radius: 10px;
border-radius: 10px;
}
#successRate {
width: 140px;
margin-left: 35px;
}
#successRate .percent {
font-size: 180%;
}
.success, .success a {
color: #008000;
}
div.success, #successRate.success {
background-color: #bbd9bb;
border-color: #008000;
}
.failures, .failures a {
color: #b60808;
}
.skipped, .skipped a {
color: #c09853;
}
div.failures, #successRate.failures {
background-color: #ecdada;
border-color: #b60808;
}
ul.linkList {
padding-left: 0;
}
ul.linkList li {
list-style: none;
margin-bottom: 5px;
}

View file

@ -1,185 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Test Summary</title>
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<script src="js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Test Summary</h1>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">10</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">2</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.287s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox failures" id="successRate">
<div class="percent">80%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Failed tests</a>
</li>
<li>
<a href="#tab1">Packages</a>
</li>
<li>
<a href="#tab2">Classes</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Failed tests</h2>
<ul class="linkList">
<li>
<a href="classes/de.bitsharesmunich.graphenej.AuthorityTest.html">AuthorityTest</a>.
<a href="classes/de.bitsharesmunich.graphenej.AuthorityTest.html#equals">equals</a>
</li>
<li>
<a href="classes/de.bitsharesmunich.graphenej.PublicKeyTest.html">PublicKeyTest</a>.
<a href="classes/de.bitsharesmunich.graphenej.PublicKeyTest.html#equals">equals</a>
</li>
</ul>
</div>
<div id="tab1" class="tab">
<h2>Packages</h2>
<table>
<thead>
<tr>
<th>Package</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thead>
<tbody>
<tr>
<td class="failures">
<a href="packages/de.bitsharesmunich.graphenej.html">de.bitsharesmunich.graphenej</a>
</td>
<td>4</td>
<td>2</td>
<td>0</td>
<td>0.220s</td>
<td class="failures">50%</td>
</tr>
<tr>
<td class="success">
<a href="packages/de.bitsharesmunich.graphenej.objects.html">de.bitsharesmunich.graphenej.objects</a>
</td>
<td>6</td>
<td>0</td>
<td>0</td>
<td>0.067s</td>
<td class="success">100%</td>
</tr>
</tbody>
</table>
</div>
<div id="tab2" class="tab">
<h2>Classes</h2>
<table>
<thead>
<tr>
<th>Class</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thead>
<tbody>
<tr>
<td class="success"/>
<a href="classes/de.bitsharesmunich.graphenej.AssetTest.html">de.bitsharesmunich.graphenej.AssetTest</a>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0.004s</td>
<td class="success">100%</td>
</tr>
<tr>
<td class="failures"/>
<a href="classes/de.bitsharesmunich.graphenej.AuthorityTest.html">de.bitsharesmunich.graphenej.AuthorityTest</a>
<td>2</td>
<td>1</td>
<td>0</td>
<td>0.215s</td>
<td class="failures">50%</td>
</tr>
<tr>
<td class="failures"/>
<a href="classes/de.bitsharesmunich.graphenej.PublicKeyTest.html">de.bitsharesmunich.graphenej.PublicKeyTest</a>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0.001s</td>
<td class="failures">0%</td>
</tr>
<tr>
<td class="success"/>
<a href="classes/de.bitsharesmunich.graphenej.objects.MemoTest.html">de.bitsharesmunich.graphenej.objects.MemoTest</a>
<td>6</td>
<td>0</td>
<td>0</td>
<td>0.067s</td>
<td class="success">100%</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,194 +0,0 @@
(function (window, document) {
"use strict";
var tabs = {};
function changeElementClass(element, classValue) {
if (element.getAttribute("className")) {
element.setAttribute("className", classValue);
} else {
element.setAttribute("class", classValue);
}
}
function getClassAttribute(element) {
if (element.getAttribute("className")) {
return element.getAttribute("className");
} else {
return element.getAttribute("class");
}
}
function addClass(element, classValue) {
changeElementClass(element, getClassAttribute(element) + " " + classValue);
}
function removeClass(element, classValue) {
changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
}
function initTabs() {
var container = document.getElementById("tabs");
tabs.tabs = findTabs(container);
tabs.titles = findTitles(tabs.tabs);
tabs.headers = findHeaders(container);
tabs.select = select;
tabs.deselectAll = deselectAll;
tabs.select(0);
return true;
}
function getCheckBox() {
return document.getElementById("line-wrapping-toggle");
}
function getLabelForCheckBox() {
return document.getElementById("label-for-line-wrapping-toggle");
}
function findCodeBlocks() {
var spans = document.getElementById("tabs").getElementsByTagName("span");
var codeBlocks = [];
for (var i = 0; i < spans.length; ++i) {
if (spans[i].className.indexOf("code") >= 0) {
codeBlocks.push(spans[i]);
}
}
return codeBlocks;
}
function forAllCodeBlocks(operation) {
var codeBlocks = findCodeBlocks();
for (var i = 0; i < codeBlocks.length; ++i) {
operation(codeBlocks[i], "wrapped");
}
}
function toggleLineWrapping() {
var checkBox = getCheckBox();
if (checkBox.checked) {
forAllCodeBlocks(addClass);
} else {
forAllCodeBlocks(removeClass);
}
}
function initControls() {
if (findCodeBlocks().length > 0) {
var checkBox = getCheckBox();
var label = getLabelForCheckBox();
checkBox.onclick = toggleLineWrapping;
checkBox.checked = false;
removeClass(label, "hidden");
}
}
function switchTab() {
var id = this.id.substr(1);
for (var i = 0; i < tabs.tabs.length; i++) {
if (tabs.tabs[i].id === id) {
tabs.select(i);
break;
}
}
return false;
}
function select(i) {
this.deselectAll();
changeElementClass(this.tabs[i], "tab selected");
changeElementClass(this.headers[i], "selected");
while (this.headers[i].firstChild) {
this.headers[i].removeChild(this.headers[i].firstChild);
}
var h2 = document.createElement("H2");
h2.appendChild(document.createTextNode(this.titles[i]));
this.headers[i].appendChild(h2);
}
function deselectAll() {
for (var i = 0; i < this.tabs.length; i++) {
changeElementClass(this.tabs[i], "tab deselected");
changeElementClass(this.headers[i], "deselected");
while (this.headers[i].firstChild) {
this.headers[i].removeChild(this.headers[i].firstChild);
}
var a = document.createElement("A");
a.setAttribute("id", "ltab" + i);
a.setAttribute("href", "#tab" + i);
a.onclick = switchTab;
a.appendChild(document.createTextNode(this.titles[i]));
this.headers[i].appendChild(a);
}
}
function findTabs(container) {
return findChildElements(container, "DIV", "tab");
}
function findHeaders(container) {
var owner = findChildElements(container, "UL", "tabLinks");
return findChildElements(owner[0], "LI", null);
}
function findTitles(tabs) {
var titles = [];
for (var i = 0; i < tabs.length; i++) {
var tab = tabs[i];
var header = findChildElements(tab, "H2", null)[0];
header.parentNode.removeChild(header);
if (header.innerText) {
titles.push(header.innerText);
} else {
titles.push(header.textContent);
}
}
return titles;
}
function findChildElements(container, name, targetClass) {
var elements = [];
var children = container.childNodes;
for (var i = 0; i < children.length; i++) {
var child = children.item(i);
if (child.nodeType === 1 && child.nodeName === name) {
if (targetClass && child.className.indexOf(targetClass) < 0) {
continue;
}
elements.push(child);
}
}
return elements;
}
// Entry point.
window.onload = function() {
initTabs();
initControls();
};
} (window, window.document));

View file

@ -1,139 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Package de.bitsharesmunich.graphenej</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Package de.bitsharesmunich.graphenej</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> &gt; de.bitsharesmunich.graphenej</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">4</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">2</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.220s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox failures" id="successRate">
<div class="percent">50%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Failed tests</a>
</li>
<li>
<a href="#tab1">Classes</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Failed tests</h2>
<ul class="linkList">
<li>
<a href="../classes/de.bitsharesmunich.graphenej.AuthorityTest.html">AuthorityTest</a>.
<a href="../classes/de.bitsharesmunich.graphenej.AuthorityTest.html#equals">equals</a>
</li>
<li>
<a href="../classes/de.bitsharesmunich.graphenej.PublicKeyTest.html">PublicKeyTest</a>.
<a href="../classes/de.bitsharesmunich.graphenej.PublicKeyTest.html#equals">equals</a>
</li>
</ul>
</div>
<div id="tab1" class="tab">
<h2>Classes</h2>
<table>
<thread>
<tr>
<th>Class</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thread>
<tr>
<td class="success">
<a href="../classes/de.bitsharesmunich.graphenej.AssetTest.html">AssetTest</a>
</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0.004s</td>
<td class="success">100%</td>
</tr>
<tr>
<td class="failures">
<a href="../classes/de.bitsharesmunich.graphenej.AuthorityTest.html">AuthorityTest</a>
</td>
<td>2</td>
<td>1</td>
<td>0</td>
<td>0.215s</td>
<td class="failures">50%</td>
</tr>
<tr>
<td class="failures">
<a href="../classes/de.bitsharesmunich.graphenej.PublicKeyTest.html">PublicKeyTest</a>
</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0.001s</td>
<td class="failures">0%</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,103 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Package de.bitsharesmunich.graphenej.objects</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Package de.bitsharesmunich.graphenej.objects</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> &gt; de.bitsharesmunich.graphenej.objects</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">6</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">0</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.067s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox success" id="successRate">
<div class="percent">100%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Classes</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Classes</h2>
<table>
<thread>
<tr>
<th>Class</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thread>
<tr>
<td class="success">
<a href="../classes/de.bitsharesmunich.graphenej.objects.MemoTest.html">MemoTest</a>
</td>
<td>6</td>
<td>0</td>
<td>0</td>
<td>0.067s</td>
<td class="success">100%</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 3.2</a> at Feb 15, 2017 11:30:01 PM</p>
</div>
</div>
</body>
</html>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="de.bitsharesmunich.graphenej.AssetTest" tests="1" skipped="0" failures="0" errors="0" timestamp="2017-02-16T04:30:01" hostname="Nelsons-MacBook-Pro.local" time="0.004">
<properties/>
<testcase name="equals" classname="de.bitsharesmunich.graphenej.AssetTest" time="0.004"/>
<system-out><![CDATA[]]></system-out>
<system-err><![CDATA[]]></system-err>
</testsuite>

View file

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="de.bitsharesmunich.graphenej.AuthorityTest" tests="2" skipped="0" failures="1" errors="0" timestamp="2017-02-16T04:30:01" hostname="Nelsons-MacBook-Pro.local" time="0.215">
<properties/>
<testcase name="equals" classname="de.bitsharesmunich.graphenej.AuthorityTest" time="0.214">
<failure message="java.lang.AssertionError: Different authorities expected:&lt;de.bitsharesmunich.graphenej.Authority@4108679d&gt; but was:&lt;de.bitsharesmunich.graphenej.Authority@5155d26c&gt;" type="java.lang.AssertionError">java.lang.AssertionError: Different authorities expected:&lt;de.bitsharesmunich.graphenej.Authority@4108679d&gt; but was:&lt;de.bitsharesmunich.graphenej.Authority@5155d26c&gt;
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at de.bitsharesmunich.graphenej.AuthorityTest.equals(AuthorityTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:377)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
</failure>
</testcase>
<testcase name="toBytes" classname="de.bitsharesmunich.graphenej.AuthorityTest" time="0.001"/>
<system-out><![CDATA[key auths match: true
account auths match: true
weight threshold matches: true
key auths match: true
account auths match: false
weight threshold matches: true
]]></system-out>
<system-err><![CDATA[SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
]]></system-err>
</testsuite>

View file

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="de.bitsharesmunich.graphenej.PublicKeyTest" tests="1" skipped="0" failures="1" errors="0" timestamp="2017-02-16T04:30:01" hostname="Nelsons-MacBook-Pro.local" time="0.001">
<properties/>
<testcase name="equals" classname="de.bitsharesmunich.graphenej.PublicKeyTest" time="0.001">
<failure message="org.bitcoinj.core.AddressFormatException: Illegal character 0 at position 48" type="org.bitcoinj.core.AddressFormatException">org.bitcoinj.core.AddressFormatException: Illegal character 0 at position 48
at org.bitcoinj.core.Base58.decode(Base58.java:110)
at de.bitsharesmunich.graphenej.Address.&lt;init&gt;(Address.java:33)
at de.bitsharesmunich.graphenej.PublicKeyTest.equals(PublicKeyTest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:377)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
</failure>
</testcase>
<system-out><![CDATA[]]></system-out>
<system-err><![CDATA[]]></system-err>
</testsuite>

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="de.bitsharesmunich.graphenej.objects.MemoTest" tests="6" skipped="0" failures="0" errors="0" timestamp="2017-02-16T04:30:01" hostname="Nelsons-MacBook-Pro.local" time="0.07">
<properties/>
<testcase name="shouldEncryptAndDecryptShortMessage" classname="de.bitsharesmunich.graphenej.objects.MemoTest" time="0.031"/>
<testcase name="shouldBeJsonObjectSerializable" classname="de.bitsharesmunich.graphenej.objects.MemoTest" time="0.009"/>
<testcase name="shouldBeByteSerializable" classname="de.bitsharesmunich.graphenej.objects.MemoTest" time="0.003"/>
<testcase name="shouldThrowException" classname="de.bitsharesmunich.graphenej.objects.MemoTest" time="0.013"/>
<testcase name="shouldEncryptAndDecryptLongerMessage" classname="de.bitsharesmunich.graphenej.objects.MemoTest" time="0.006"/>
<testcase name="shouldMatchPredefinedChiphertext" classname="de.bitsharesmunich.graphenej.objects.MemoTest" time="0.005"/>
<system-out><![CDATA[]]></system-out>
<system-err><![CDATA[]]></system-err>
</testsuite>

View file

@ -1,5 +0,0 @@
Manifest-Version: 1.0
Implementation-Title: Graphenej test
Implementation-Version: 0.1-SNAPSHOT
Main-Class: de.bitsharesmunich.graphenej.Main

View file

@ -1,2 +0,0 @@
Manifest-Version: 1.0

View file

@ -1,14 +1,20 @@
package de.bitsharesmunich.graphenej;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
import de.bitsharesmunich.graphenej.errors.MalformedAddressException;
import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import de.bitsharesmunich.graphenej.errors.MalformedAddressException;
import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable;
/**
* Created by nelson on 12/5/16.
*/
@ -107,6 +113,9 @@ public class AccountOptions implements GrapheneSerializable {
//TODO: Check this serialization
byteArray.addAll(Bytes.asList(vote.toBytes()));
}
// Account options's extensions
byteArray.addAll(Bytes.asList(extensions.toBytes()));
}else{
byteArray.add((byte) 0);
}

View file

@ -1,17 +1,27 @@
package de.bitsharesmunich.graphenej;
import com.google.common.math.DoubleMath;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedLong;
import com.google.gson.*;
import de.bitsharesmunich.graphenej.errors.IncompatibleOperation;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.math.RoundingMode;
import de.bitsharesmunich.graphenej.errors.IncompatibleOperation;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
/**
* Created by nelson on 11/7/16.
@ -73,6 +83,49 @@ public class AssetAmount implements ByteSerializable, JsonSerializable {
return new AssetAmount(result, asset);
}
/**
* Multiplies the current amount by a factor provided as the first parameter. The second parameter
* specifies the rounding method to be used.
* @param factor: The multiplying factor
* @param roundingMode: The rounding mode as an instance of the {@link RoundingMode} class
* @return The same AssetAmount instance, but with the changed amount value.
*/
public AssetAmount multiplyBy(double factor, RoundingMode roundingMode){
this.amount = UnsignedLong.valueOf(DoubleMath.roundToLong(this.amount.longValue() * factor, roundingMode));
return this;
}
/**
* Multiplies the current amount by a factor, using the {@link RoundingMode#HALF_DOWN} constant.
* @param factor: The multiplying factor
* @return The same AssetAmount instance, but with the changed amount value.
*/
public AssetAmount multiplyBy(double factor){
return this.multiplyBy(factor, RoundingMode.HALF_DOWN);
}
/**
* Divides the current amount by a divisor provided as the first parameter. The second parameter
* specifies the rounding method to be used.
* @param divisor: The divisor
* @return: The same AssetAMount instance, but with the divided amount value
*/
public AssetAmount dividedBy(double divisor, RoundingMode roundingMode){
this.amount = UnsignedLong.valueOf(DoubleMath.roundToLong(this.amount.longValue() / divisor, roundingMode));
return this;
}
/**
* Divides the current amount by a divisor provided as the first parameter, using
* the {@link RoundingMode#HALF_DOWN} constant
* @param divisor: The divisor
* @return: The same AssetAMount instance, but with the divided amount value
*/
public AssetAmount dividedBy(double divisor){
return this.dividedBy(divisor, RoundingMode.HALF_DOWN);
}
public void setAmount(UnsignedLong amount){
this.amount = amount;
}

View file

@ -1,15 +1,25 @@
package de.bitsharesmunich.graphenej;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import de.bitsharesmunich.graphenej.errors.MalformedAddressException;
import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable;
import java.lang.reflect.Type;
import java.util.*;
/**
* Created by nelson on 11/30/16.
* Class used to represent the weighted set of keys and accounts that must approve operations.
*
* {@see <a href="https://bitshares.org/doxygen/structgraphene_1_1chain_1_1authority.html">Authority</a>}
*/
public class Authority implements GrapheneSerializable {
public static final String KEY_ACCOUNT_AUTHS = "account_auths";
@ -18,14 +28,14 @@ public class Authority implements GrapheneSerializable {
public static final String KEY_EXTENSIONS = "extensions";
private long weight_threshold;
private HashMap<UserAccount, Integer> account_auths;
private HashMap<PublicKey, Integer> key_auths;
private HashMap<UserAccount, Long> account_auths;
private HashMap<PublicKey, Long> key_auths;
private Extensions extensions;
public Authority(){
this.weight_threshold = 1;
this.account_auths = new HashMap<UserAccount, Integer>();
this.key_auths = new HashMap<PublicKey, Integer>();
this.account_auths = new HashMap<UserAccount, Long>();
this.key_auths = new HashMap<PublicKey, Long>();
extensions = new Extensions();
}
@ -36,7 +46,7 @@ public class Authority implements GrapheneSerializable {
* @param accountAuths: Map of account to weights relationships. Can be null.
* @throws MalformedAddressException
*/
public Authority(long weight_threshold, HashMap<PublicKey, Integer> keyAuths, HashMap<UserAccount, Integer> accountAuths) {
public Authority(long weight_threshold, HashMap<PublicKey, Long> keyAuths, HashMap<UserAccount, Long> accountAuths) {
this();
this.weight_threshold = weight_threshold;
if(keyAuths != null)
@ -49,7 +59,7 @@ public class Authority implements GrapheneSerializable {
this.account_auths = new HashMap<>();
}
public void setKeyAuthorities(HashMap<Address, Integer> keyAuths){
public void setKeyAuthorities(HashMap<Address, Long> keyAuths){
if(keyAuths != null){
for(Address address : keyAuths.keySet()){
key_auths.put(address.getPublicKey(), keyAuths.get(address));
@ -57,10 +67,13 @@ public class Authority implements GrapheneSerializable {
}
}
public void setAccountAuthorities(HashMap<UserAccount, Integer> accountAuthorities){
public void setAccountAuthorities(HashMap<UserAccount, Long> accountAuthorities){
this.account_auths = accountAuthorities;
}
/**
* @return: Returns a list of public keys linked to this authority
*/
public List<PublicKey> getKeyAuthList(){
ArrayList<PublicKey> keys = new ArrayList<>();
for(PublicKey pk : key_auths.keySet()){
@ -69,11 +82,22 @@ public class Authority implements GrapheneSerializable {
return keys;
}
public HashMap<PublicKey, Integer> getKeyAuths(){
/**
* @return: Returns a list of accounts linked to this authority
*/
public List<UserAccount> getAccountAuthList(){
ArrayList<UserAccount> accounts = new ArrayList<>();
for(UserAccount account : account_auths.keySet()){
accounts.add(account);
}
return accounts;
}
public HashMap<PublicKey, Long> getKeyAuths(){
return this.key_auths;
}
public HashMap<UserAccount, Integer> getAccountAuths(){
public HashMap<UserAccount, Long> getAccountAuths(){
return this.account_auths;
}
@ -149,8 +173,8 @@ public class Authority implements GrapheneSerializable {
@Override
public boolean equals(Object obj) {
Authority authority = (Authority) obj;
HashMap<PublicKey, Integer> keyAuths = authority.getKeyAuths();
HashMap<UserAccount, Integer> accountAuths = authority.getAccountAuths();
HashMap<PublicKey, Long> keyAuths = authority.getKeyAuths();
HashMap<UserAccount, Long> accountAuths = authority.getAccountAuths();
System.out.println("key auths match: "+this.key_auths.equals(keyAuths));
System.out.println("account auths match: "+this.account_auths.equals(accountAuths));
System.out.println("weight threshold matches: "+(this.weight_threshold == authority.weight_threshold));
@ -179,12 +203,12 @@ public class Authority implements GrapheneSerializable {
long weightThreshold = baseObject.get(KEY_WEIGHT_THRESHOLD).getAsLong();
JsonArray keyAuthArray = baseObject.getAsJsonArray(KEY_KEY_AUTHS);
JsonArray accountAuthArray = baseObject.getAsJsonArray(KEY_ACCOUNT_AUTHS);
HashMap<PublicKey, Integer> keyAuthMap = new HashMap<>();
HashMap<UserAccount, Integer> accountAuthMap = new HashMap<>();
HashMap<PublicKey, Long> keyAuthMap = new HashMap<>();
HashMap<UserAccount, Long> accountAuthMap = new HashMap<>();
for(int i = 0; i < keyAuthArray.size(); i++){
JsonArray subArray = keyAuthArray.get(i).getAsJsonArray();
String addr = subArray.get(0).getAsString();
int weight = subArray.get(1).getAsInt();
long weight = subArray.get(1).getAsLong();
try {
keyAuthMap.put(new Address(addr).getPublicKey(), weight);
} catch (MalformedAddressException e) {
@ -192,7 +216,11 @@ public class Authority implements GrapheneSerializable {
}
}
for(int i = 0; i < accountAuthArray.size(); i++){
//TODO: Implement this
JsonArray subArray = accountAuthArray.get(i).getAsJsonArray();
String userId = subArray.get(0).getAsString();
long weight = subArray.get(1).getAsLong();
UserAccount userAccount = new UserAccount(userId);
accountAuthMap.put(userAccount, weight);
}
return new Authority(weightThreshold, keyAuthMap, accountAuthMap);
}

View file

@ -1,6 +1,5 @@
package de.bitsharesmunich.graphenej;
import de.bitsharesmunich.graphenej.crypto.SecureRandomGenerator;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
@ -11,6 +10,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import de.bitsharesmunich.graphenej.crypto.SecureRandomGenerator;
/**
* Class used to encapsulate all BrainKey-related operations.
*/
@ -22,6 +23,9 @@ public class BrainKey {
/* The required number of words */
public static final int BRAINKEY_WORD_COUNT = 12;
/* The default sequence number is zero */
public static final int DEFAULT_SEQUENCE_NUMBER = 0;
/* The corresponding private key derivated from the brain key */
private ECKey mPrivateKey;
@ -106,10 +110,28 @@ public class BrainKey {
return wif.toString();
}
/**
* Returns the public address derived from this brain key
* @param prefix: The prefix to use in this address.
* @return An instance of the {@link Address} class
*/
public Address getPublicAddress(String prefix){
return new Address(ECKey.fromPublicOnly(getPublicKey()), prefix);
}
/**
* Brain key words getter
* @return: The word sequence that comprises this brain key
*/
public String getBrainKey(){
return mBrainKey;
}
/**
* Sequence number getter
* @return: The sequence number used alongside with the brain key words in order
* to derive the private key
*/
public int getSequenceNumber(){
return sequenceNumber;
}

View file

@ -3,7 +3,6 @@ package de.bitsharesmunich.graphenej;
import java.math.BigDecimal;
import java.math.MathContext;
import com.google.common.primitives.UnsignedLong;
import de.bitsharesmunich.graphenej.errors.IncompleteAssetError;
import de.bitsharesmunich.graphenej.models.BucketObject;

View file

@ -1,7 +1,7 @@
package de.bitsharesmunich.graphenej;
/**
* Created by nelson on 1/12/17.
* Enum type used to list all possible object types and obtain their space + type id
*/
public enum ObjectType {
@ -33,5 +33,150 @@ public enum ObjectType {
CHAIN_PROPERTY_OBJECT,
WITNESS_SCHEDULE_OBJECT,
BUDGET_RECORD_OBJECT,
SPECIAL_AUTHORITY_OBJECT
SPECIAL_AUTHORITY_OBJECT;
private int getSpace(){
int space = 1;
switch(this){
case BASE_OBJECT:
case ACCOUNT_OBJECT:
case ASSET_OBJECT:
case FORCE_SETTLEMENT_OBJECT:
case COMMITTEE_MEMBER_OBJECT:
case WITNESS_OBJECT:
case LIMIT_ORDER_OBJECT:
case CALL_ORDER_OBJECT:
case CUSTOM_OBJECT:
case PROPOSAL_OBJECT:
case OPERATION_HISTORY_OBJECT:
case WITHDRAW_PERMISSION_OBJECT:
case VESTING_BALANCE_OBJECT:
case WORKER_OBJECT:
case BALANCE_OBJECT:
space = 1;
break;
case GLOBAL_PROPERTY_OBJECT:
case DYNAMIC_GLOBAL_PROPERTY_OBJECT:
case ASSET_DYNAMIC_DATA:
case ASSET_BITASSET_DATA:
case ACCOUNT_BALANCE_OBJECT:
case ACCOUNT_STATISTICS_OBJECT:
case TRANSACTION_OBJECT:
case BLOCK_SUMMARY_OBJECT:
case ACCOUNT_TRANSACTION_HISTORY_OBJECT:
case BLINDED_BALANCE_OBJECT:
case CHAIN_PROPERTY_OBJECT:
case WITNESS_SCHEDULE_OBJECT:
case BUDGET_RECORD_OBJECT:
case SPECIAL_AUTHORITY_OBJECT:
space = 2;
break;
}
return space;
}
private int getType(){
int type = 0;
switch(this){
case BASE_OBJECT:
type = 1;
break;
case ACCOUNT_OBJECT:
type = 2;
break;
case ASSET_OBJECT:
type = 3;
break;
case FORCE_SETTLEMENT_OBJECT:
type = 4;
break;
case COMMITTEE_MEMBER_OBJECT:
type = 5;
break;
case WITNESS_OBJECT:
type = 6;
break;
case LIMIT_ORDER_OBJECT:
type = 7;
break;
case CALL_ORDER_OBJECT:
type = 8;
break;
case CUSTOM_OBJECT:
type = 9;
break;
case PROPOSAL_OBJECT:
type = 10;
break;
case OPERATION_HISTORY_OBJECT:
type = 11;
break;
case WITHDRAW_PERMISSION_OBJECT:
type = 12;
break;
case VESTING_BALANCE_OBJECT:
type = 13;
break;
case WORKER_OBJECT:
type = 14;
break;
case BALANCE_OBJECT:
type = 15;
break;
case GLOBAL_PROPERTY_OBJECT:
type = 0;
break;
case DYNAMIC_GLOBAL_PROPERTY_OBJECT:
type = 1;
break;
case ASSET_DYNAMIC_DATA:
type = 3;
break;
case ASSET_BITASSET_DATA:
type = 4;
break;
case ACCOUNT_BALANCE_OBJECT:
type = 5;
break;
case ACCOUNT_STATISTICS_OBJECT:
type = 6;
break;
case TRANSACTION_OBJECT:
type = 7;
break;
case BLOCK_SUMMARY_OBJECT:
type = 8;
break;
case ACCOUNT_TRANSACTION_HISTORY_OBJECT:
type = 9;
break;
case BLINDED_BALANCE_OBJECT:
type = 10;
break;
case CHAIN_PROPERTY_OBJECT:
type = 11;
break;
case WITNESS_SCHEDULE_OBJECT:
type = 12;
break;
case BUDGET_RECORD_OBJECT:
type = 13;
break;
case SPECIAL_AUTHORITY_OBJECT:
type = 14;
}
return type;
}
/**
* This method is used to return the generic object type in the form space.type.0.
*
* Not to be confused with {@link GrapheneObject#getObjectId()}, which will return
* the full object id in the form space.type.id.
*
* @return: The generic object type
*/
public String getGenericObjectId(){
return String.format("%d.%d.0", getSpace(), getType());
}
}

View file

@ -1,10 +1,19 @@
package de.bitsharesmunich.graphenej;
import com.google.gson.JsonElement;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable;
/**
* Used whenever we have an optional field.
* Container template class used whenever we have an optional field.
*
* The idea here is that the binary serialization of this field should be performed
* in a specific way determined by the field implementing the {@link ByteSerializable}
* interface, more specifically using the {@link ByteSerializable#toBytes()} method.
*
* However, if the field is missing, the Optional class should be able to know how
* to serialize it, as this is always done by placing an zero byte.
*/
public class Optional<T extends GrapheneSerializable> implements GrapheneSerializable {
private T optionalField;

View file

@ -0,0 +1,98 @@
package de.bitsharesmunich.graphenej;
import com.google.common.math.DoubleMath;
import com.google.common.primitives.UnsignedLong;
import java.math.RoundingMode;
import java.util.List;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
/**
* This class will maintain a snapshot of the order book between two assets.
*
* It also provides a handy method that should return the appropriate LimitOrderCreateOperation
* object needed in case the user wants to perform market-priced operations.
*
* It is important to keep the order book updated, ideally by listening to blockchain events, and calling the 'update' method.
*
* Created by nelson on 3/25/17.
*/
public class OrderBook {
private List<LimitOrder> limitOrders;
public OrderBook(List<LimitOrder> limitOrders){
this.limitOrders = limitOrders;
}
/**
* Replaces the current limit order by the list provided as parameter.
* @param limitOrders: New list of orders
*/
public void update(List<LimitOrder> limitOrders){
this.limitOrders = limitOrders;
}
public void update(LimitOrder limitOrder){
//TODO: Implement the method that will update a single limit order from the order book
}
/**
* High level method used to exchange a specific amount of an asset (The base) for another
* one (The quote) at market value.
*
* It should analyze the order book and figure out the optimal amount of the base asset to give
* away in order to obtain the desired amount of the quote asset.
*
* @param seller: User account of the seller, used to build the limit order create operation
* @param myBaseAsset: The asset the user is willing to give away
* @param myQuoteAmount: The amount of a given asset the user wants
* @param expiration: The expiration time of the limit order
*
* @return An instance of the LimitOrderCreateOperation class, which is ready to be broadcasted.
*/
public LimitOrderCreateOperation exchange(UserAccount seller, Asset myBaseAsset, AssetAmount myQuoteAmount, int expiration){
AssetAmount toSell = new AssetAmount(UnsignedLong.valueOf(calculateRequiredBase(myQuoteAmount)), myBaseAsset);
AssetAmount toReceive = myQuoteAmount;
LimitOrderCreateOperation buyOrder = new LimitOrderCreateOperation(seller, toSell, toReceive, expiration, true);
return buyOrder;
}
/**
* Given a specific amount of a desired asset, this method will calculate how much of the corresponding
* asset we need to offer to perform a successful transaction with the current order book.
* @param quoteAmount: The amount of the desired asset.
* @return: The minimum amount of the base asset that we need to give away
*/
public long calculateRequiredBase(AssetAmount quoteAmount){
long totalBought = 0;
long totalSold = 0;
for(int i = 0; i < this.limitOrders.size() && totalBought < quoteAmount.getAmount().longValue(); i++){
LimitOrder order = this.limitOrders.get(i);
// If the base asset is the same as our quote asset, we have a match
if(order.getSellPrice().base.getAsset().getObjectId().equals(quoteAmount.getAsset().getObjectId())){
// My quote amount, is the order's base amount
long orderAmount = order.getForSale();
// The amount of the quote asset we still need
long stillNeed = quoteAmount.getAmount().longValue() - totalBought;
// If the offered amount is greater than what we still need, we exchange just what we need
if(orderAmount >= stillNeed) {
totalBought += stillNeed;
double additionalRatio = (double) stillNeed / (double) order.getSellPrice().base.getAmount().longValue();
double additionalAmount = order.getSellPrice().quote.getAmount().longValue() * additionalRatio;
long longAdditional = DoubleMath.roundToLong(additionalAmount, RoundingMode.HALF_UP);
totalSold += longAdditional;
}else{
// If the offered amount is less than what we need, we exchange the whole order
totalBought += orderAmount;
totalSold += order.getSellPrice().quote.getAmount().longValue();
}
}
}
return totalSold;
}
}

View file

@ -1,11 +1,16 @@
package de.bitsharesmunich.graphenej;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
@ -19,6 +24,11 @@ import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
/**
* Class used to represent a generic Graphene transaction.
*/
@ -263,10 +273,9 @@ public class Transaction implements ByteSerializable, JsonSerializable {
for (JsonElement jsonOperation : jsonObject.get(KEY_OPERATIONS).getAsJsonArray()) {
int operationId = jsonOperation.getAsJsonArray().get(0).getAsInt();
if (operationId == OperationType.TRANSFER_OPERATION.ordinal()) {
System.out.println("Transfer operation detected!");
operation = context.deserialize(jsonOperation, TransferOperation.class);
} else if (operationId == OperationType.LIMIT_ORDER_CREATE_OPERATION.ordinal()) {
//TODO: Add operation deserialization support
operation = context.deserialize(jsonOperation, LimitOrderCreateOperation.class);
} else if (operationId == OperationType.LIMIT_ORDER_CANCEL_OPERATION.ordinal()) {
//TODO: Add operation deserialization support
} else if (operationId == OperationType.CALL_ORDER_UPDATE_OPERATION.ordinal()) {

View file

@ -1,15 +1,23 @@
package de.bitsharesmunich.graphenej;
import com.google.gson.*;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
/**
* Class tha represents a graphene user account.
@ -18,8 +26,39 @@ import java.util.ArrayList;
public class UserAccount extends GrapheneObject implements ByteSerializable, JsonSerializable {
public static final String PROXY_TO_SELF = "1.2.5";
public static final String KEY_MEMBERSHIP_EXPIRATION_DATE = "membership_expiration_date";
public static final String KEY_REGISTRAR = "registrar";
public static final String KEY_REFERRER = "referrer";
public static final String KEY_LIFETIME_REFERRER = "lifetime_referrer";
public static final String KEY_NETWORK_FEE_PERCENTAGE = "network_fee_percentage";
public static final String KEY_LIFETIME_REFERRER_FEE_PERCENTAGE = "lifetime_referrer_fee_percentage";
public static final String KEY_REFERRER_REWARD_PERCENTAGE = "referrer_rewards_percentage";
public static final String KEY_NAME = "name";
public static final String KEY_OWNER = "owner";
public static final String KEY_ACTIVE = "active";
public static final String KEY_OPTIONS = "options";
public static final String KEY_STATISTICS = "statistics";
public static final String KEY_WHITELISTING_ACCOUNTS = "whitelisting_accounts";
public static final String KEY_BLACKLISTING_ACCOUNTS = "blacklisting_accounts";
public static final String KEY_WHITELISTED_ACCOUNTS = "whitelisted_accounts";
public static final String KEY_BLACKLISTED_ACCOUNTS = "blacklisted_accounts";
public static final String KEY_OWNER_SPECIAL_AUTHORITY = "owner_special_authority";
public static final String KEY_ACTIVE_SPECIAL_AUTHORITY = "active_special_authority";
public static final String KEY_N_CONTROL_FLAGS = "top_n_control_flags";
private long membershipExpirationDate;
private String registrar;
private String referrer;
private String lifetimeReferrer;
private long networkFeePercentage;
private long lifetimeReferrerFeePercentage;
private long referrerRewardsPercentage;
private String name;
private Authority owner;
private Authority active;
private AccountOptions options;
private String statistics;
private String accountName;
/**
* Constructor that expects a user account in the string representation.
@ -37,24 +76,24 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
*/
public UserAccount(String id, String name){
super(id);
this.accountName = name;
this.name = name;
}
/**
* Getter for the account name field.
* @return: The name of this account.
*/
public String getAccountName() {
return accountName;
public String getName() {
return name;
}
/**
* Setter for the account name field.
* @param accountName: The account name.
* @param name: The account name.
*/
public void setAccountName(String accountName) {
this.accountName = accountName;
public void setName(String name) {
this.name = name;
}
@Override
@ -94,6 +133,140 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
return this.toJsonString();
}
public long getMembershipExpirationDate() {
return membershipExpirationDate;
}
public void setMembershipExpirationDate(long membershipExpirationDate) {
this.membershipExpirationDate = membershipExpirationDate;
}
public String getRegistrar() {
return registrar;
}
public void setRegistrar(String registrar) {
this.registrar = registrar;
}
public String getReferrer() {
return referrer;
}
public void setReferrer(String referrer) {
this.referrer = referrer;
}
public String getLifetimeReferrer() {
return lifetimeReferrer;
}
public void setLifetimeReferrer(String lifetimeReferrer) {
this.lifetimeReferrer = lifetimeReferrer;
}
public long getNetworkFeePercentage() {
return networkFeePercentage;
}
public void setNetworkFeePercentage(long networkFeePercentage) {
this.networkFeePercentage = networkFeePercentage;
}
public long getLifetimeReferrerFeePercentage() {
return lifetimeReferrerFeePercentage;
}
public void setLifetimeReferrerFeePercentage(long lifetimeReferrerFeePercentage) {
this.lifetimeReferrerFeePercentage = lifetimeReferrerFeePercentage;
}
public long getReferrerRewardsPercentage() {
return referrerRewardsPercentage;
}
public void setReferrerRewardsPercentage(long referrerRewardsPercentage) {
this.referrerRewardsPercentage = referrerRewardsPercentage;
}
public Authority getOwner() {
return owner;
}
public void setOwner(Authority owner) {
this.owner = owner;
}
public Authority getActive() {
return active;
}
public void setActive(Authority active) {
this.active = active;
}
public AccountOptions getOptions() {
return options;
}
public void setOptions(AccountOptions options) {
this.options = options;
}
public String getStatistics() {
return statistics;
}
public void setStatistics(String statistics) {
this.statistics = statistics;
}
/**
* Deserializer used to build a UserAccount instance from the full JSON-formatted response obtained
* by the 'get_objects' API call.
*/
public static class UserAccountFullDeserializer implements JsonDeserializer<UserAccount> {
@Override
public UserAccount deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonAccount = json.getAsJsonObject();
SimpleDateFormat dateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
// Retrieving and deserializing fields
String id = jsonAccount.get(KEY_ID).getAsString();
String name = jsonAccount.get(KEY_NAME).getAsString();
UserAccount userAccount = new UserAccount(id, name);
AccountOptions options = context.deserialize(jsonAccount.get(KEY_OPTIONS), AccountOptions.class);
Authority owner = context.deserialize(jsonAccount.get(KEY_OWNER), Authority.class);
Authority active = context.deserialize(jsonAccount.get(KEY_ACTIVE), Authority.class);
// Setting deserialized fields into the created instance
userAccount.setRegistrar(jsonAccount.get(KEY_REGISTRAR).getAsString());
// Handling the deserialization and assignation of the membership date, which internally
// is stored as a long POSIX time value
try{
Date date = dateFormat.parse(jsonAccount.get(KEY_MEMBERSHIP_EXPIRATION_DATE).getAsString());
userAccount.setMembershipExpirationDate(date.getTime());
} catch (ParseException e) {
System.out.println("ParseException. Msg: "+e.getMessage());
}
// Setting the other fields
userAccount.setReferrer(jsonAccount.get(KEY_REFERRER).getAsString());
userAccount.setLifetimeReferrer(jsonAccount.get(KEY_LIFETIME_REFERRER).getAsString());
userAccount.setNetworkFeePercentage(jsonAccount.get(KEY_NETWORK_FEE_PERCENTAGE).getAsLong());
userAccount.setLifetimeReferrerFeePercentage(jsonAccount.get(KEY_LIFETIME_REFERRER_FEE_PERCENTAGE).getAsLong());
userAccount.setReferrerRewardsPercentage(jsonAccount.get(KEY_REFERRER_REWARD_PERCENTAGE).getAsLong());
userAccount.setOwner(owner);
userAccount.setActive(active);
userAccount.setOptions(options);
userAccount.setStatistics(jsonAccount.get(KEY_STATISTICS).getAsString());
return userAccount;
}
}
/**
* Custom deserializer used to deserialize user accounts provided as response from the 'lookup_accounts' api call.
* This response contains serialized user accounts in the form [[{id1},{name1}][{id1},{name1}]].

View file

@ -1,19 +1,8 @@
package de.bitsharesmunich.graphenej.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.AccountProperties;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import java.io.Serializable;
@ -22,15 +11,24 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.AccountProperties;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 11/15/16.
*/
public class GetAccountByName extends WebSocketAdapter {
public class GetAccountByName extends BaseGrapheneHandler {
private String accountName;
private WitnessResponseListener mListener;
public GetAccountByName(String accountName, WitnessResponseListener listener){
super(listener);
this.accountName = accountName;
this.mListener = listener;
}
@ -70,17 +68,4 @@ public class GetAccountByName extends WebSocketAdapter {
System.out.println(">>> "+frame.getPayloadText());
}
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -1,23 +1,9 @@
package de.bitsharesmunich.graphenej.api;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.AccountProperties;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -25,22 +11,33 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.AccountProperties;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
*
* @author henry
*/
public class GetAccounts extends WebSocketAdapter {
public class GetAccounts extends BaseGrapheneHandler {
private String accountId;
private List<UserAccount> userAccounts;
private WitnessResponseListener mListener;
public GetAccounts(String accountId, WitnessResponseListener listener){
super(listener);
this.accountId = accountId;
this.mListener = listener;
}
public GetAccounts(List<UserAccount> accounts, WitnessResponseListener listener){
super(listener);
this.userAccounts = accounts;
this.mListener = listener;
}
@ -85,22 +82,4 @@ public class GetAccounts extends WebSocketAdapter {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
System.out.println("onError");
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
System.out.println("handleCallbackError. Msg: "+cause.getMessage());
StackTraceElement[] stack = cause.getStackTrace();
for(StackTraceElement element : stack) {
System.out.println("> "+element.getClassName()+"."+element.getMethodName()+" : "+element.getLineNumber());
}
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -3,12 +3,7 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.*;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -16,10 +11,18 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.BlockHeader;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 12/13/16.
*/
public class GetBlockHeader extends WebSocketAdapter {
public class GetBlockHeader extends BaseGrapheneHandler {
// Sequence of message ids
private final static int LOGIN_ID = 1;
private final static int GET_DATABASE_ID = 2;
@ -32,6 +35,7 @@ public class GetBlockHeader extends WebSocketAdapter {
private int apiId = -1;
public GetBlockHeader(long blockNumber, WitnessResponseListener listener){
super(listener);
this.blockNumber = blockNumber;
this.mListener = listener;
}
@ -87,16 +91,4 @@ public class GetBlockHeader extends WebSocketAdapter {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
System.out.println("onError. Msg: "+cause.getMessage());
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
System.out.println("handleCallbackError. Msg: "+cause.getMessage());
websocket.disconnect();
}
}

View file

@ -2,16 +2,7 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.Address;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import java.io.Serializable;
@ -20,25 +11,41 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.Address;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 11/15/16.
*/
public class GetAccountsByAddress extends WebSocketAdapter {
public class GetKeyReferences extends BaseGrapheneHandler {
private Address address;
private WitnessResponseListener mListener;
private List<Address> addresses;
public GetAccountsByAddress(Address address, WitnessResponseListener listener) {
this.address = address;
public GetKeyReferences(Address address, WitnessResponseListener listener){
super(listener);
addresses = new ArrayList<>();
addresses.add(address);
}
public GetKeyReferences(List<Address> addresses, WitnessResponseListener listener) {
super(listener);
this.addresses = addresses;
this.mListener = listener;
}
@Override
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
ArrayList<Serializable> params = new ArrayList();
ArrayList<Serializable> addresses = new ArrayList();
addresses.add(address.toString());
params.add(addresses);
ArrayList<Serializable> inner = new ArrayList();
for(Address addr : addresses){
inner.add(addr.toString());
}
ArrayList<Serializable> params = new ArrayList<>();
params.add(inner);
ApiCall getAccountByAddress = new ApiCall(0, RPC.CALL_GET_KEY_REFERENCES, params, RPC.VERSION, 1);
websocket.sendText(getAccountByAddress.toJsonString());
}
@ -65,16 +72,4 @@ public class GetAccountsByAddress extends WebSocketAdapter {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -3,9 +3,15 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.LimitOrder;
import de.bitsharesmunich.graphenej.RPC;
@ -15,16 +21,10 @@ import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by nelson on 11/15/16.
*/
public class GetLimitOrders extends WebSocketAdapter {
public class GetLimitOrders extends BaseGrapheneHandler {
private String a;
private String b;
@ -32,6 +32,7 @@ public class GetLimitOrders extends WebSocketAdapter {
private WitnessResponseListener mListener;
public GetLimitOrders(String a, String b, int limit, WitnessResponseListener mListener) {
super(mListener);
this.a = a;
this.b = b;
this.limit = limit;

View file

@ -4,13 +4,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.*;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -20,10 +14,19 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.BucketObject;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 12/22/16.
*/
public class GetMarketHistory extends WebSocketAdapter {
public class GetMarketHistory extends BaseGrapheneHandler {
// Sequence of message ids
private final static int LOGIN_ID = 1;
private final static int GET_HISTORY_ID = 2;
@ -36,11 +39,13 @@ public class GetMarketHistory extends WebSocketAdapter {
private Date start;
private Date end;
private WitnessResponseListener mListener;
private WebSocket mWebsocket;
private int currentId = 1;
private int apiId = -1;
private int counter = 0;
public GetMarketHistory(Asset base, Asset quote, long bucket, Date start, Date end, WitnessResponseListener listener){
super(listener);
this.base = base;
this.quote = quote;
this.bucket = bucket;
@ -49,8 +54,68 @@ public class GetMarketHistory extends WebSocketAdapter {
this.mListener = listener;
}
public Asset getBase() {
return base;
}
public void setBase(Asset base) {
this.base = base;
}
public Asset getQuote() {
return quote;
}
public void setQuote(Asset quote) {
this.quote = quote;
}
public long getBucket() {
return bucket;
}
public void setBucket(long bucket) {
this.bucket = bucket;
}
public Date getStart() {
return start;
}
public void setStart(Date start) {
this.start = start;
}
public Date getEnd() {
return end;
}
public void setEnd(Date end) {
this.end = end;
}
public int getCount(){
return this.counter;
}
public void disconnect(){
if(mWebsocket != null && mWebsocket.isOpen()){
mWebsocket.disconnect();
}
}
/**
* Retries the 'get_market_history' API call.
* Hopefully with different 'start' and 'stop' parameters.
*/
public void retry(){
sendHistoricalMarketDataRequest();
}
@Override
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
mWebsocket = websocket;
ArrayList<Serializable> loginParams = new ArrayList<>();
loginParams.add(null);
loginParams.add(null);
@ -89,37 +154,40 @@ public class GetMarketHistory extends WebSocketAdapter {
ApiCall getRelativeAccountHistoryCall = new ApiCall(apiId, RPC.CALL_GET_MARKET_HISTORY, params, RPC.VERSION, currentId);
websocket.sendText(getRelativeAccountHistoryCall.toJsonString());
}else if(baseResponse.id == GET_HISTORY_DATA){
}else if(baseResponse.id >= GET_HISTORY_DATA){
GsonBuilder builder = new GsonBuilder();
Type MarketHistoryResponse = new TypeToken<WitnessResponse<List<BucketObject>>>(){}.getType();
builder.registerTypeAdapter(BucketObject.class, new BucketObject.BucketDeserializer());
WitnessResponse<List<BucketObject>> marketHistoryResponse = builder.create().fromJson(response, MarketHistoryResponse);
mListener.onSuccess(marketHistoryResponse);
websocket.disconnect();
}
}
}
/**
* Actually sends the 'get_market_history' API call request. This method might be called multiple
* times during the life-cycle of this instance because we might not have gotten anything
* in the first requested interval.
*/
private void sendHistoricalMarketDataRequest(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
ArrayList<Serializable> params = new ArrayList<>();
params.add(this.base.getObjectId());
params.add(this.quote.getObjectId());
params.add(this.bucket);
params.add(dateFormat.format(this.start));
params.add(dateFormat.format(this.end));
ApiCall getRelativeAccountHistoryCall = new ApiCall(apiId, RPC.CALL_GET_MARKET_HISTORY, params, RPC.VERSION, currentId);
mWebsocket.sendText(getRelativeAccountHistoryCall.toJsonString());
counter++;
}
@Override
public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
System.out.println("onError. Msg: "+cause.getMessage());
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
System.out.println("handleCallbackError. cause: "+cause.getMessage()+", error: "+cause.getClass());
for (StackTraceElement element : cause.getStackTrace()){
System.out.println(element.getFileName()+"#"+element.getClassName()+":"+element.getLineNumber());
}
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -1,15 +1,13 @@
package de.bitsharesmunich.graphenej.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BitAssetData;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -17,6 +15,18 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BitAssetData;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 1/8/17.
*/
@ -48,16 +58,40 @@ public class GetObjects extends BaseGrapheneHandler {
String response = frame.getPayloadText();
GsonBuilder gsonBuilder = new GsonBuilder();
//TODO: Uncomment this line after the deserializer is implemented.
gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
// gsonBuilder.registerTypeAdapter(BitAssetData.class, new BitAssetData.BitAssetDeserializer());
gsonBuilder.registerTypeAdapter(Asset.class, new Asset.AssetDeserializer());
gsonBuilder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountFullDeserializer());
gsonBuilder.registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer());
gsonBuilder.registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer());
Gson gson = gsonBuilder.create();
// Only homogeneus array is currently supported
if(ids.get(0).split("\\.")[1].equals("4")){
Type BitAssetDataType = new TypeToken<WitnessResponse<List<BitAssetData>>>(){}.getType();
WitnessResponse<List<BitAssetData>> witnessResponse = gsonBuilder.create().fromJson(response, BitAssetDataType);
mListener.onSuccess(witnessResponse);
List<GrapheneObject> parsedResult = new ArrayList<>();
JsonParser parser = new JsonParser();
JsonArray resultArray = parser.parse(response).getAsJsonObject().get(WitnessResponse.KEY_RESULT).getAsJsonArray();
for(JsonElement element : resultArray){
String id = element.getAsJsonObject().get(GrapheneObject.KEY_ID).getAsString();
GrapheneObject grapheneObject = new GrapheneObject(id);
switch (grapheneObject.getObjectType()){
case ASSET_OBJECT:
Asset asset = gson.fromJson(element, Asset.class);
parsedResult.add(asset);
break;
case ACCOUNT_OBJECT:
UserAccount account = gson.fromJson(element, UserAccount.class);
parsedResult.add(account);
break;
case ASSET_BITASSET_DATA:
Type BitAssetDataType = new TypeToken<WitnessResponse<List<BitAssetData>>>(){}.getType();
WitnessResponse<List<BitAssetData>> witnessResponse = gsonBuilder.create().fromJson(response, BitAssetDataType);
BitAssetData bitAssetData = witnessResponse.result.get(0);
parsedResult.add(bitAssetData);
}
}
WitnessResponse<List<GrapheneObject>> output = new WitnessResponse<>();
output.result = parsedResult;
mListener.onSuccess(output);
websocket.disconnect();
}

View file

@ -3,18 +3,7 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.HistoricalTransfer;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import java.io.Serializable;
@ -23,11 +12,21 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.HistoricalTransfer;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
/**
* Class used to encapsulate the communication sequence used to retrieve the transaction history of
* a given user.
*/
public class GetRelativeAccountHistory extends WebSocketAdapter {
public class GetRelativeAccountHistory extends BaseGrapheneHandler {
// Sequence of message ids
private final static int LOGIN_ID = 1;
private final static int GET_HISTORY_ID = 2;
@ -44,6 +43,7 @@ public class GetRelativeAccountHistory extends WebSocketAdapter {
private int limit;
private int start;
private WitnessResponseListener mListener;
private WebSocket mWebsocket;
private int currentId = 1;
private int apiId = -1;
@ -57,6 +57,7 @@ public class GetRelativeAccountHistory extends WebSocketAdapter {
* @param listener Listener to be notified with the result of this query
*/
public GetRelativeAccountHistory(UserAccount userAccount, int stop, int limit, int start, WitnessResponseListener listener){
super(listener);
if(limit > MAX_LIMIT) limit = MAX_LIMIT;
this.mUserAccount = userAccount;
this.stop = stop;
@ -71,6 +72,7 @@ public class GetRelativeAccountHistory extends WebSocketAdapter {
* @param listener Listener to be notified with the result of this query
*/
public GetRelativeAccountHistory(UserAccount userAccount, WitnessResponseListener listener){
super(listener);
this.mUserAccount = userAccount;
this.stop = DEFAULT_STOP;
this.limit = MAX_LIMIT;
@ -80,6 +82,7 @@ public class GetRelativeAccountHistory extends WebSocketAdapter {
@Override
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
mWebsocket = websocket;
ArrayList<Serializable> loginParams = new ArrayList<>();
loginParams.add(null);
loginParams.add(null);
@ -107,43 +110,57 @@ public class GetRelativeAccountHistory extends WebSocketAdapter {
WitnessResponse<Integer> witnessResponse = gson.fromJson(response, ApiIdResponse);
apiId = witnessResponse.result.intValue();
ArrayList<Serializable> params = new ArrayList<>();
params.add(mUserAccount.toJsonString());
params.add(this.stop);
params.add(this.limit);
params.add(this.start);
ApiCall getRelativeAccountHistoryCall = new ApiCall(apiId, RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY, params, RPC.VERSION, currentId);
websocket.sendText(getRelativeAccountHistoryCall.toJsonString());
}else if(baseResponse.id == GET_HISTORY_DATA){
sendRelativeAccountHistoryRequest();
}else if(baseResponse.id >= GET_HISTORY_DATA){
Type RelativeAccountHistoryResponse = new TypeToken<WitnessResponse<List<HistoricalTransfer>>>(){}.getType();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer());
gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
WitnessResponse<List<HistoricalTransfer>> transfersResponse = gsonBuilder.create().fromJson(response, RelativeAccountHistoryResponse);
mListener.onSuccess(transfersResponse);
websocket.disconnect();
}
}
}
/**
* Sends the actual get_relative_account_history request.
*/
private void sendRelativeAccountHistoryRequest(){
ArrayList<Serializable> params = new ArrayList<>();
params.add(mUserAccount.toJsonString());
params.add(this.stop);
params.add(this.limit);
params.add(this.start);
ApiCall getRelativeAccountHistoryCall = new ApiCall(apiId, RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY, params, RPC.VERSION, currentId);
mWebsocket.sendText(getRelativeAccountHistoryCall.toJsonString());
}
/**
* Updates the arguments and makes a new call to the get_relative_account_history API
* @param stop Sequence number of earliest operation
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start Sequence number of the most recent operation to retrieve
*/
public void retry(int stop, int limit, int start){
this.stop = stop;
this.limit = limit;
this.start = start;
sendRelativeAccountHistoryRequest();
}
/**
* Disconnects the websocket
*/
public void disconnect(){
if(mWebsocket != null && mWebsocket.isOpen()){
mWebsocket.disconnect();
}
}
@Override
public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
System.out.println("onError. Msg: "+cause.getMessage());
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
System.out.println("handleCallbackError. Msg: "+cause.getMessage());
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -3,15 +3,7 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.MarketTrade;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -19,10 +11,16 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.MarketTrade;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* @author henry
*/
public class GetTradeHistory extends WebSocketAdapter {
public class GetTradeHistory extends BaseGrapheneHandler {
private String a;
private String b;
@ -32,6 +30,7 @@ public class GetTradeHistory extends WebSocketAdapter {
private WitnessResponseListener mListener;
public GetTradeHistory(String a, String b, String toTime, String fromTime,int limit, WitnessResponseListener mListener) {
super(mListener);
this.a = a;
this.b = b;
this.toTime = toTime;
@ -82,16 +81,4 @@ public class GetTradeHistory extends WebSocketAdapter {
System.out.println(">>> " + frame.getPayloadText());
}
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -2,15 +2,7 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import java.io.Serializable;
@ -19,10 +11,16 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by henry on 07/12/16.
*/
public class LookupAccounts extends WebSocketAdapter {
public class LookupAccounts extends BaseGrapheneHandler {
public static final int DEFAULT_MAX = 1000;
private final String accountName;
@ -30,12 +28,14 @@ public class LookupAccounts extends WebSocketAdapter {
private final WitnessResponseListener mListener;
public LookupAccounts(String accountName, WitnessResponseListener listener){
super(listener);
this.accountName = accountName;
this.maxAccounts = DEFAULT_MAX;
this.mListener = listener;
}
public LookupAccounts(String accountName, int maxAccounts, WitnessResponseListener listener){
super(listener);
this.accountName = accountName;
this.maxAccounts = maxAccounts;
this.mListener = listener;
@ -73,16 +73,4 @@ public class LookupAccounts extends WebSocketAdapter {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -3,15 +3,7 @@ package de.bitsharesmunich.graphenej.api;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -19,14 +11,21 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 12/12/16.
*/
public class LookupAssetSymbols extends WebSocketAdapter {
public class LookupAssetSymbols extends BaseGrapheneHandler {
private WitnessResponseListener mListener;
private List<Asset> assets;
public LookupAssetSymbols(List<Asset> assets, WitnessResponseListener listener){
super(listener);
this.assets = assets;
this.mListener = listener;
}
@ -59,21 +58,4 @@ public class LookupAssetSymbols extends WebSocketAdapter {
if(frame.isTextFrame())
System.out.println(">>> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
System.out.println("onError. cause: "+cause.getMessage());
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
System.out.println("handleCallbackError. cause: "+cause.getMessage()+", error: "+cause.getClass());
for (StackTraceElement element : cause.getStackTrace()){
System.out.println(element.getFileName()+"#"+element.getClassName()+":"+element.getLineNumber());
}
mListener.onError(new BaseResponse.Error(cause.getMessage()));
websocket.disconnect();
}
}

View file

@ -4,18 +4,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.SubscriptionResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -23,12 +12,27 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.ObjectType;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties;
import de.bitsharesmunich.graphenej.models.SubscriptionResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
/**
* A websocket adapter prepared to be used as a basic dispatch hub for subscription messages.
*
* Created by nelson on 1/26/17.
*/
public class SubscriptionMessagesHub extends WebSocketAdapter implements SubscriptionHub {
public class SubscriptionMessagesHub extends BaseGrapheneHandler implements SubscriptionHub {
// Sequence of message ids
private final static int LOGIN_ID = 1;
private final static int GET_DATABASE_ID = 2;
@ -41,21 +45,60 @@ public class SubscriptionMessagesHub extends WebSocketAdapter implements Subscri
private Gson gson;
private String user;
private String password;
private int currentId = LOGIN_ID;
private boolean clearFilter;
private List<ObjectType> objectTypes;
private int currentId;
private int databaseApiId = -1;
private int subscriptionCounter = 0;
public SubscriptionMessagesHub(String user, String password){
/**
* Id used to separate requests regarding the subscriptions
*/
private final int SUBSCRIPTION_ID = 10;
/**
* Constructor used to create a subscription message hub that will call the set_subscribe_callback
* API with the clear_filter parameter set to false, meaning that it will only receive automatic updates
* from objects we register.
*
* A list of ObjectTypes must be provided, otherwise we won't get any update.
*
* @param user: User name, in case the node to which we're going to connect to requires authentication
* @param password: Password, same as above
* @param objectTypes: List of objects of interest
* @param errorListener: Callback that will be fired in case there is an error.
*/
public SubscriptionMessagesHub(String user, String password, List<ObjectType> objectTypes, WitnessResponseListener errorListener){
super(errorListener);
this.objectTypes = objectTypes;
this.user = user;
this.password = password;
this.clearFilter = true;
this.mSubscriptionDeserializer = new SubscriptionResponse.SubscriptionResponseDeserializer();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(SubscriptionResponse.class, mSubscriptionDeserializer);
builder.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer());
builder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer());
builder.registerTypeAdapter(LimitOrderCreateOperation.class, new LimitOrderCreateOperation.LimitOrderCreateDeserializer());
builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer());
builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer());
this.gson = builder.create();
}
/**
* Constructor used to create a subscription message hub that will call the set_subscribe_callback
* API with the clear_filter parameter set to true, meaning that it will receive automatic updates
* on all network events.
*
* @param user: User name, in case the node to which we're going to connect to requires authentication
* @param password: Password, same as above
* @param errorListener: Callback that will be fired in case there is an error.
*/
public SubscriptionMessagesHub(String user, String password, WitnessResponseListener errorListener){
this(user, password, new ArrayList<ObjectType>(), errorListener);
}
@Override
public void addSubscriptionListener(SubscriptionListener listener){
this.mSubscriptionDeserializer.addSubscriptionListener(listener);
@ -74,6 +117,7 @@ public class SubscriptionMessagesHub extends WebSocketAdapter implements Subscri
@Override
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
ArrayList<Serializable> loginParams = new ArrayList<>();
currentId = LOGIN_ID;
loginParams.add(user);
loginParams.add(password);
ApiCall loginCall = new ApiCall(1, RPC.CALL_LOGIN, loginParams, RPC.VERSION, currentId);
@ -88,6 +132,7 @@ public class SubscriptionMessagesHub extends WebSocketAdapter implements Subscri
ArrayList<Serializable> emptyParams = new ArrayList<>();
ApiCall getDatabaseId = new ApiCall(1, RPC.CALL_DATABASE, emptyParams, RPC.VERSION, currentId);
websocket.sendText(getDatabaseId.toJsonString());
currentId++;
}else if(currentId == GET_DATABASE_ID){
Type ApiIdResponse = new TypeToken<WitnessResponse<Integer>>() {}.getType();
WitnessResponse<Integer> witnessResponse = gson.fromJson(message, ApiIdResponse);
@ -95,15 +140,23 @@ public class SubscriptionMessagesHub extends WebSocketAdapter implements Subscri
ArrayList<Serializable> subscriptionParams = new ArrayList<>();
subscriptionParams.add(String.format("%d", SUBCRIPTION_NOTIFICATION));
subscriptionParams.add(false);
ApiCall getDatabaseId = new ApiCall(databaseApiId, RPC.CALL_SET_SUBSCRIBE_CALLBACK, subscriptionParams, RPC.VERSION, currentId);
subscriptionParams.add(clearFilter);
ApiCall getDatabaseId = new ApiCall(databaseApiId, RPC.CALL_SET_SUBSCRIBE_CALLBACK, subscriptionParams, RPC.VERSION, SUBCRIPTION_REQUEST);
websocket.sendText(getDatabaseId.toJsonString());
}else if(currentId == SUBCRIPTION_REQUEST){
// Listeners are called from within the SubscriptionResponseDeserializer, so there's nothing to handle here.
}else{
SubscriptionResponse subscriptionResponse = gson.fromJson(message, SubscriptionResponse.class);
currentId++;
} else if(currentId == SUBCRIPTION_REQUEST){
if(objectTypes != null && objectTypes.size() > 0 && subscriptionCounter < objectTypes.size()){
ArrayList<Serializable> objectOfInterest = new ArrayList<>();
objectOfInterest.add(objectTypes.get(subscriptionCounter).getGenericObjectId());
ArrayList<Serializable> payload = new ArrayList<>();
payload.add(objectOfInterest);
ApiCall subscribe = new ApiCall(databaseApiId, RPC.GET_OBJECTS, payload, RPC.VERSION, SUBSCRIPTION_ID);
websocket.sendText(subscribe.toJsonString());
subscriptionCounter++;
}else{
gson.fromJson(message, SubscriptionResponse.class);
}
}
currentId++;
}
@Override
@ -111,13 +164,9 @@ public class SubscriptionMessagesHub extends WebSocketAdapter implements Subscri
System.out.println(">> "+frame.getPayloadText());
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
super.onError(websocket, cause);
}
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
super.handleCallbackError(websocket, cause);
public void reset(){
currentId = 0;
databaseApiId = -1;
subscriptionCounter = 0;
}
}

View file

@ -1,27 +1,33 @@
package de.bitsharesmunich.graphenej.api;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.*;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.BlockData;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFrame;
/**
* Class that will handle the transaction publication procedure.
*/
public class TransactionBroadcastSequence extends WebSocketAdapter {
public class TransactionBroadcastSequence extends BaseGrapheneHandler {
private final String TAG = this.getClass().getName();
private final static int LOGIN_ID = 1;
@ -45,6 +51,7 @@ public class TransactionBroadcastSequence extends WebSocketAdapter {
* of the transaction broadcast operation.
*/
public TransactionBroadcastSequence(Transaction transaction, Asset feeAsset, WitnessResponseListener listener){
super(listener);
this.transaction = transaction;
this.feeAsset = feeAsset;
this.mListener = listener;
@ -64,7 +71,9 @@ public class TransactionBroadcastSequence extends WebSocketAdapter {
if(frame.isTextFrame())
System.out.println("<<< "+frame.getPayloadText());
String response = frame.getPayloadText();
Gson gson = new Gson();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer());
Gson gson = builder.create();
BaseResponse baseResponse = gson.fromJson(response, BaseResponse.class);
if(baseResponse.error != null){
mListener.onError(baseResponse.error);
@ -94,12 +103,8 @@ public class TransactionBroadcastSequence extends WebSocketAdapter {
WitnessResponse<DynamicGlobalProperties> witnessResponse = gson.fromJson(response, DynamicGlobalPropertiesResponse);
DynamicGlobalProperties dynamicProperties = witnessResponse.result;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
Date date = dateFormat.parse(dynamicProperties.time);
// Adjusting dynamic block data to every transaction
long expirationTime = (date.getTime() / 1000) + Transaction.DEFAULT_EXPIRATION_TIME;
long expirationTime = (dynamicProperties.time.getTime() / 1000) + Transaction.DEFAULT_EXPIRATION_TIME;
String headBlockId = dynamicProperties.head_block_id;
long headBlockNumber = dynamicProperties.head_block_number;
transaction.setBlockData(new BlockData(headBlockNumber, headBlockId, expirationTime));

View file

@ -1,5 +1,6 @@
package de.bitsharesmunich.graphenej.models;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.Price;
/**
@ -8,8 +9,7 @@ import de.bitsharesmunich.graphenej.Price;
*
* Created by nelson on 1/8/17.
*/
public class BitAssetData {
public String id;
public class BitAssetData extends GrapheneObject {
public Object[] feeds;
public AssetFeed current_feed;
public String current_feed_publication_time;
@ -18,4 +18,8 @@ public class BitAssetData {
public boolean is_prediction_market;
public Price settlement_price;
public long settlement_fund;
public BitAssetData(String id) {
super(id);
}
}

View file

@ -1,8 +1,20 @@
package de.bitsharesmunich.graphenej.models;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.Util;
/**
* Class used to deserialize the 'result' field returned by the full node after making a call
@ -25,19 +37,63 @@ public class DynamicGlobalProperties extends GrapheneObject implements Serializa
public long head_block_number;
public String head_block_id;
public String time;
public Date time;
public String current_witness;
public String next_maintenance_time;
public Date next_maintenance_time;
public String last_budget_time;
public long witness_budget;
public long accounts_registered_this_interval;
public long recently_missed_count;
public long current_aslot;
public String recent_slots_filled;
public long dynamic_flags;
public int dynamic_flags;
public long last_irreversible_block_num;
public DynamicGlobalProperties(String id) {
super(id);
}
/**
* Class that will parse the JSON element containing the dynamic global properties object and
* return an instance of the {@link DynamicGlobalProperties} class.
*/
public static class DynamicGlobalPropertiesDeserializer implements JsonDeserializer<DynamicGlobalProperties> {
@Override
public DynamicGlobalProperties deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = jsonElement.getAsJsonObject();
// Creating an instance of the DynamicGlobalProperties
DynamicGlobalProperties dynamicGlobal = new DynamicGlobalProperties(jsonElement.getAsJsonObject().get(KEY_ID).getAsString());
// Start to fill in the parsed details
dynamicGlobal.head_block_number = jsonObject.get(DynamicGlobalProperties.KEY_HEAD_BLOCK_NUMBER).getAsLong();
dynamicGlobal.head_block_id = jsonObject.get(DynamicGlobalProperties.KEY_HEAD_BLOCK_ID).getAsString();
SimpleDateFormat dateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
dynamicGlobal.time = dateFormat.parse(jsonObject.get(DynamicGlobalProperties.KEY_TIME).getAsString());
} catch (ParseException e) {
System.out.println("ParseException. Msg: "+e.getMessage());
}
try {
dynamicGlobal.next_maintenance_time = dateFormat.parse(jsonObject.get(DynamicGlobalProperties.KEY_NEXT_MAINTENANCE_TIME).getAsString());
} catch (ParseException e) {
System.out.println("ParseException. Msg: "+e.getMessage());
}
dynamicGlobal.current_witness = jsonObject.get(DynamicGlobalProperties.KEY_CURRENT_WITNESS).getAsString();
dynamicGlobal.last_budget_time = jsonObject.get(DynamicGlobalProperties.KEY_LAST_BUDGET_TIME).getAsString();
dynamicGlobal.witness_budget = jsonObject.get(DynamicGlobalProperties.KEY_WITNESS_BUDGET).getAsLong();
dynamicGlobal.accounts_registered_this_interval = jsonObject.get(DynamicGlobalProperties.KEY_ACCOUNTS_REGISTERED_THIS_INTERVAL).getAsLong();
dynamicGlobal.recently_missed_count = jsonObject.get(DynamicGlobalProperties.KEY_RECENTLY_MISSED_COUNT).getAsLong();
dynamicGlobal.current_aslot = jsonObject.get(DynamicGlobalProperties.KEY_CURRENT_ASLOT).getAsLong();
dynamicGlobal.recent_slots_filled = jsonObject.get(DynamicGlobalProperties.KEY_RECENT_SLOTS_FILLED).getAsString();
dynamicGlobal.dynamic_flags = jsonObject.get(DynamicGlobalProperties.KEY_DYNAMIC_FLAGS).getAsInt();
dynamicGlobal.last_irreversible_block_num = jsonObject.get(DynamicGlobalProperties.KEY_LAST_IRREVERSIBLE_BLOCK_NUM).getAsLong();
return dynamicGlobal;
}
}
}

View file

@ -9,9 +9,14 @@ import com.google.gson.JsonParseException;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import de.bitsharesmunich.graphenej.*;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.ObjectType;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
/**
@ -57,7 +62,14 @@ public class SubscriptionResponse {
* objects that might come once the are subscribed to the witness notifications.
*/
public static class SubscriptionResponseDeserializer implements JsonDeserializer<SubscriptionResponse> {
/**
* Map of ObjectType to Integer used to keep track of the current amount of listener per type
*/
private HashMap<ObjectType, Integer> listenerTypeCount;
/**
* List of listeners
*/
private LinkedList<SubscriptionListener> mListeners;
/**
@ -97,6 +109,9 @@ public class SubscriptionResponse {
public SubscriptionResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
SubscriptionResponse response = new SubscriptionResponse();
JsonObject responseObject = json.getAsJsonObject();
if(!responseObject.has(KEY_METHOD)){
return response;
}
response.method = responseObject.get(KEY_METHOD).getAsString();
JsonArray paramsArray = responseObject.get(KEY_PARAMS).getAsJsonArray();
@ -105,11 +120,15 @@ public class SubscriptionResponse {
ArrayList<Serializable> secondArgument = new ArrayList<>();
response.params.add(secondArgument);
// Hash map used to record the type of objects present in this subscription message
// and only alert listeners that might be interested
HashMap<ObjectType, Boolean> objectMap = new HashMap<>();
JsonArray subArray = paramsArray.get(1).getAsJsonArray().get(0).getAsJsonArray();
for(JsonElement object : subArray){
if(object.isJsonObject()){
GrapheneObject grapheneObject = new GrapheneObject(object.getAsJsonObject().get(KEY_ID).getAsString());
int listenerTypeCount = 0;
if(this.listenerTypeCount.containsKey(grapheneObject.getObjectType())){
listenerTypeCount = this.listenerTypeCount.get(grapheneObject.getObjectType());
@ -126,18 +145,17 @@ public class SubscriptionResponse {
balanceObject.owner = jsonObject.get(AccountBalanceUpdate.KEY_OWNER).getAsString();
balanceObject.asset_type = jsonObject.get(AccountBalanceUpdate.KEY_ASSET_TYPE).getAsString();
balanceObject.balance = jsonObject.get(AccountBalanceUpdate.KEY_BALANCE).getAsLong();
objectMap.put(ObjectType.ACCOUNT_BALANCE_OBJECT, true);
secondArgument.add(balanceObject);
}else if(grapheneObject.getObjectType() == ObjectType.DYNAMIC_GLOBAL_PROPERTY_OBJECT){
DynamicGlobalProperties dynamicGlobal = new DynamicGlobalProperties(grapheneObject.getObjectId());
dynamicGlobal.head_block_number = jsonObject.get(DynamicGlobalProperties.KEY_HEAD_BLOCK_NUMBER).getAsLong();
dynamicGlobal.head_block_id = jsonObject.get(DynamicGlobalProperties.KEY_HEAD_BLOCK_ID).getAsString();
dynamicGlobal.time = jsonObject.get(DynamicGlobalProperties.KEY_TIME).getAsString();
//TODO: Deserialize all other attributes
secondArgument.add(dynamicGlobal);
DynamicGlobalProperties dynamicGlobalProperties = context.deserialize(object, DynamicGlobalProperties.class);
objectMap.put(ObjectType.DYNAMIC_GLOBAL_PROPERTY_OBJECT, true);
secondArgument.add(dynamicGlobalProperties);
}else if(grapheneObject.getObjectType() == ObjectType.TRANSACTION_OBJECT){
BroadcastedTransaction broadcastedTransaction = new BroadcastedTransaction(grapheneObject.getObjectId());
broadcastedTransaction.setTransaction((Transaction) context.deserialize(jsonObject.get(BroadcastedTransaction.KEY_TRX), Transaction.class));
broadcastedTransaction.setTransactionId(jsonObject.get(BroadcastedTransaction.KEY_TRX_ID).getAsString());
objectMap.put(ObjectType.TRANSACTION_OBJECT, true);
secondArgument.add(broadcastedTransaction);
}else{
//TODO: Add support for other types of objects
@ -148,7 +166,11 @@ public class SubscriptionResponse {
}
}
for(SubscriptionListener listener : mListeners){
listener.onSubscriptionUpdate(response);
// Only notify the listener if there is an object of interest in
// this notification
if(objectMap.containsKey(listener.getInterestObjectType())){
listener.onSubscriptionUpdate(response);
}
}
return response;
}

View file

@ -4,5 +4,8 @@ package de.bitsharesmunich.graphenej.models;
* Generic witness response
*/
public class WitnessResponse<T> extends BaseResponse{
public static final String KEY_ID = "id";
public static final String KEY_RESULT = "result";
public T result;
}

View file

@ -24,7 +24,6 @@ public class AccountUpdateOperation extends BaseOperation {
private Optional<Authority> owner;
private Optional<Authority> active;
private Optional<AccountOptions> new_options;
private Extensions extensions;
/**
* Account update operation constructor.

View file

@ -2,15 +2,25 @@ package de.bitsharesmunich.graphenej.operations;
import com.google.common.primitives.Bytes;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import de.bitsharesmunich.graphenej.*;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.BaseOperation;
import de.bitsharesmunich.graphenej.OperationType;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.Util;
/**
* Operation used to denote the creation of a limit order on the blockchain.
*
@ -88,6 +98,48 @@ public class LimitOrderCreateOperation extends BaseOperation {
this.fee = assetAmount;
}
public AssetAmount getFee(){ return this.fee; }
public UserAccount getSeller() {
return seller;
}
public void setSeller(UserAccount seller) {
this.seller = seller;
}
public AssetAmount getAmountToSell() {
return amountToSell;
}
public void setAmountToSell(AssetAmount amountToSell) {
this.amountToSell = amountToSell;
}
public AssetAmount getMinToReceive() {
return minToReceive;
}
public void setMinToReceive(AssetAmount minToReceive) {
this.minToReceive = minToReceive;
}
public int getExpiration() {
return expiration;
}
public void setExpiration(int expiration) {
this.expiration = expiration;
}
public boolean isFillOrKill() {
return fillOrKill;
}
public void setFillOrKill(boolean fillOrKill) {
this.fillOrKill = fillOrKill;
}
@Override
public byte[] toBytes() {
byte[] feeBytes = this.fee.toBytes();
@ -104,4 +156,78 @@ public class LimitOrderCreateOperation extends BaseOperation {
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill, extensions);
}
/**
* Deserializer used to convert the JSON-formatted representation of a limit_order_create_operation
* into its java object version.
*
* The following is an example of the serialized form of this operation:
*
* [
* 1,
* {
* "fee": {
* "amount": 14676,
* "asset_id": "1.3.0"
* },
* "seller": "1.2.36449",
* "amount_to_sell": {
* "amount": 945472,
* "asset_id": "1.3.850"
* },
* "min_to_receive": {
* "amount": 4354658,
* "asset_id": "1.3.861"
* },
* "expiration": "1963-11-25T06:31:44",
* "fill_or_kill": false,
* "extensions": []
* }
* ]
*
*
*/
public static class LimitOrderCreateDeserializer implements JsonDeserializer<LimitOrderCreateOperation> {
@Override
public LimitOrderCreateOperation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if(json.isJsonArray()){
// This block is used just to check if we are in the first step of the deserialization
// when we are dealing with an array.
JsonArray serializedTransfer = json.getAsJsonArray();
if(serializedTransfer.get(0).getAsInt() != OperationType.LIMIT_ORDER_CREATE_OPERATION.ordinal()){
// If the operation type does not correspond to a transfer operation, we return null
return null;
}else{
// Calling itself recursively, this is only done once, so there will be no problems.
return context.deserialize(serializedTransfer.get(1), LimitOrderCreateOperation.class);
}
}else{
// This block is called in the second recursion and takes care of deserializing the
// limit order data itself.
JsonObject jsonObject = json.getAsJsonObject();
AssetAmount fee = context.deserialize(jsonObject.get(KEY_FEE), AssetAmount.class);
UserAccount seller = context.deserialize(jsonObject.get(KEY_SELLER), UserAccount.class);
AssetAmount amountToSell = context.deserialize(jsonObject.get(KEY_AMOUNT_TO_SELL), AssetAmount.class);
AssetAmount minToReceive = context.deserialize(jsonObject.get(KEY_MIN_TO_RECEIVE), AssetAmount.class);
String expiration = jsonObject.get(KEY_EXPIRATION).getAsString();
boolean fillOrKill = jsonObject.get(KEY_FILL_OR_KILL).getAsBoolean();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
int expirationPosix = 0;
try {
Date expirationDate = simpleDateFormat.parse(expiration);
expirationPosix = (int) (expirationDate.getTime() / 1000);
} catch (ParseException e) {
e.printStackTrace();
}
// Creating an instance of the LimitOrderCreateOperation and setting the fee
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, expirationPosix, fillOrKill);
operation.setFee(fee);
return operation;
}
}
}
}

View file

@ -1,14 +1,23 @@
package de.bitsharesmunich.graphenej.operations;
import com.google.common.primitives.Bytes;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.BaseOperation;
import de.bitsharesmunich.graphenej.OperationType;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.objects.Memo;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
import java.lang.reflect.Type;
/**
* Class used to encapsulate the TransferOperation operation related functionalities.
@ -70,6 +79,14 @@ public class TransferOperation extends BaseOperation {
this.to = to;
}
public void setMemo(Memo memo) {
this.memo = memo;
}
public Memo getMemo() {
return this.memo;
}
@Override
public void setFee(AssetAmount newFee){
this.fee = newFee;
@ -110,10 +127,6 @@ public class TransferOperation extends BaseOperation {
return array;
}
public void setMemo(Memo memo) {
this.memo = memo;
}
public static class TransferSerializer implements JsonSerializer<TransferOperation> {
@Override

View file

@ -1,15 +1,12 @@
package de.bitsharesmunich.graphenej;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.InputMismatchException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
/**
* Created by nelson on 12/16/16.
@ -25,19 +22,19 @@ public class AuthorityTest {
public void setUp() throws Exception {
authority = new Authority();
sameAuthority = new Authority();
HashMap<UserAccount, Integer> accountAuthorityMap = new HashMap<>();
HashMap<UserAccount, Long> accountAuthorityMap = new HashMap<>();
UserAccount userAccount = new UserAccount("1.2.20000");
accountAuthorityMap.put(userAccount, 1);
accountAuthorityMap.put(userAccount, 1l);
differentAuthority = new Authority(1, null, accountAuthorityMap);
Address address1 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
Address address2 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
PublicKey publicKey = address1.getPublicKey();
PublicKey samePublicKey = address2.getPublicKey();
HashMap<PublicKey, Integer> keyMap1 = new HashMap<>();
HashMap<PublicKey, Integer> keyMap2 = new HashMap<>();
keyMap1.put(publicKey, 1);
keyMap2.put(samePublicKey, 1);
HashMap<PublicKey, Long> keyMap1 = new HashMap<>();
HashMap<PublicKey, Long> keyMap2 = new HashMap<>();
keyMap1.put(publicKey, 1l);
keyMap2.put(samePublicKey, 1l);
keyAuthority1 = new Authority(1, keyMap1, null);
keyAuthority2 = new Authority(1, keyMap2, null);

View file

@ -0,0 +1,27 @@
package de.bitsharesmunich.graphenej;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Created by nelson on 4/18/17.
*/
public class BrainKeyTest {
public final String TEST_BRAINKEY = "BARIC BICKERN LITZ TIPFUL JINGLED POOL TUMBAK PURIST APOPYLE DURAIN SATLIJK FAUCAL";
private BrainKey mBrainKey;
@Before
public void setup(){
mBrainKey = new BrainKey(TEST_BRAINKEY, BrainKey.DEFAULT_SEQUENCE_NUMBER);
}
@Test
public void testAddress(){
Address address = mBrainKey.getPublicAddress(Address.BITSHARES_PREFIX);
Assert.assertEquals("Assert that the address created is the expected one",
"BTS61UqqgE3ARuTGcckzARsdQm4EMFdBEwYyi1pbwyHrZZWrCDhT2",
address.toString());
}
}

View file

@ -0,0 +1,26 @@
package de.bitsharesmunich.graphenej;
import junit.framework.Assert;
import org.junit.Test;
/**
* Created by nelson on 5/5/17.
*/
public class ObjectTypeTest {
@Test
public void getGenericObjectId() throws Exception {
ObjectType baseObject = ObjectType.BASE_OBJECT;
ObjectType accountObject = ObjectType.ACCOUNT_OBJECT;
ObjectType forceSettlementObject = ObjectType.FORCE_SETTLEMENT_OBJECT;
ObjectType globalPropertiesObject = ObjectType.GLOBAL_PROPERTY_OBJECT;
ObjectType specialAuthorityObject = ObjectType.SPECIAL_AUTHORITY_OBJECT;
Assert.assertEquals("1.1.0", baseObject.getGenericObjectId());
Assert.assertEquals("1.2.0", accountObject.getGenericObjectId());
Assert.assertEquals("1.4.0", forceSettlementObject.getGenericObjectId());
Assert.assertEquals("2.0.0", globalPropertiesObject.getGenericObjectId());
Assert.assertEquals("2.14.0", specialAuthorityObject.getGenericObjectId());
}
}

View file

@ -0,0 +1,33 @@
package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketFactory;
import org.junit.Before;
import javax.net.ssl.SSLContext;
import de.bitsharesmunich.graphenej.test.NaiveSSLContext;
/**
* Created by nelson on 4/14/17.
*/
public class BaseApiTest {
protected String BLOCK_PAY_DE = System.getenv("OPENLEDGER_EU");
protected SSLContext context;
protected WebSocket mWebSocket;
@Before
public void setUp() throws Exception {
context = NaiveSSLContext.getInstance("TLS");
WebSocketFactory factory = new WebSocketFactory();
// Set the custom SSL context.
factory.setSSLContext(context);
mWebSocket = factory.createSocket(BLOCK_PAY_DE);
}
}

View file

@ -0,0 +1,81 @@
package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocketException;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import de.bitsharesmunich.graphenej.Address;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.errors.MalformedAddressException;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 4/14/17.
*/
public class GetKeyReferencesTest extends BaseApiTest {
private String[] publicKeys = new String[] {
"BTS8DuGHXpHYedq7qhT65BEEdQPvLT8nxZ862Hf8NgvSZUMuwUFkn",
"BTS53ehf9Qoeg9o4E1KuxdZRXCVg3Z9ApbEDHVdQhERDJDEFkPkGs"
};
@Test
public void testGetKeyReferences(){
ArrayList<Address> addresses = new ArrayList<>();
for(String addr : publicKeys){
try {
Address address = new Address(addr);
addresses.add(address);
} catch (MalformedAddressException e) {
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
}
}
mWebSocket.addListener(new GetKeyReferences(addresses, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
int counter = 0;
List<List<UserAccount>> accountListList = (List<List<UserAccount>>) response.result;
for(List<UserAccount> accountList : accountListList){
for(UserAccount userAccount : accountList){
System.out.println("User account: "+userAccount.getObjectId());
}
if(accountList.size() > 1){
System.out.println("Key with address: "+publicKeys[counter]+" controls more than one role in account: "+accountList.get(0).getObjectId());
}else if(accountList.size() == 1){
System.out.println("Key with address: "+publicKeys[counter]+" controls just one role in account: "+accountList.get(0).getObjectId());
}
counter++;
}
synchronized (GetKeyReferencesTest.this){
GetKeyReferencesTest.this.notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError. Msg: "+error.message);
synchronized (GetKeyReferencesTest.this){
GetKeyReferencesTest.this.notifyAll();
}
}
}));
try{
mWebSocket.connect();
synchronized (this){
wait();
}
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
}

View file

@ -1,70 +1,67 @@
package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocket;
import com.google.common.primitives.UnsignedLong;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.net.ssl.SSLContext;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.Converter;
import de.bitsharesmunich.graphenej.LimitOrder;
import de.bitsharesmunich.graphenej.OrderBook;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import de.bitsharesmunich.graphenej.test.NaiveSSLContext;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
import static org.hamcrest.CoreMatchers.is;
/**
* Created by nelson on 3/24/17.
*/
public class GetLimitOrdersTest {
private String BLOCK_PAY_DE = System.getenv("BLOCKPAY_DE");
private final Asset base = new Asset("1.3.120", "EUR", 4);
private final Asset quote = new Asset("1.3.121", "USD", 4);
@Before
public void setUp() throws Exception {
}
public class GetLimitOrdersTest extends BaseApiTest {
private UserAccount seller = new UserAccount("1.2.143563");
private final Asset base = new Asset("1.3.121", "USD", 4);
private final Asset quote = new Asset("1.3.0", "BTS", 5);
@Test
public void testGetLimitOrders(){
SSLContext context = null;
try {
context = NaiveSSLContext.getInstance("TLS");
WebSocketFactory factory = new WebSocketFactory();
// Set the custom SSL context.
factory.setSSLContext(context);
WebSocket mWebSocket = factory.createSocket(BLOCK_PAY_DE);
mWebSocket.addListener(new GetLimitOrders(base.getObjectId(), quote.getObjectId(), 100, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
List<LimitOrder> orders = (List<LimitOrder>) response.result;
Assert.assertThat("Checking that we have orders", orders.isEmpty(), is(false));
Converter converter = new Converter();
System.out.println();
for(LimitOrder order : orders){
order.getSellPrice().base.getAsset().setPrecision(base.getPrecision());
order.getSellPrice().quote.getAsset().setPrecision(quote.getPrecision());
double baseToQuoteExchange = converter.getConversionRate(order.getSellPrice(), Converter.BASE_TO_QUOTE);
double quoteToBaseExchange = converter.getConversionRate(order.getSellPrice(), Converter.QUOTE_TO_BASE);
System.out.println(String.format("base to quote: %.5f, quote to base: %.5f", baseToQuoteExchange, quoteToBaseExchange));
double baseToQuoteExchange, quoteToBaseExchange;
synchronized (GetLimitOrdersTest.this){
GetLimitOrdersTest.this.notifyAll();
for(LimitOrder order : orders){
if(order.getSellPrice().base.getAsset().getObjectId().equals(base.getObjectId())){
order.getSellPrice().base.getAsset().setPrecision(base.getPrecision());
order.getSellPrice().quote.getAsset().setPrecision(quote.getPrecision());
baseToQuoteExchange = converter.getConversionRate(order.getSellPrice(), Converter.BASE_TO_QUOTE);
quoteToBaseExchange = converter.getConversionRate(order.getSellPrice(), Converter.QUOTE_TO_BASE);
System.out.println(String.format("> id: %s, base to quote: %.5f, quote to base: %.5f", order.getObjectId(), baseToQuoteExchange, quoteToBaseExchange));
}else{
order.getSellPrice().base.getAsset().setPrecision(quote.getPrecision());
order.getSellPrice().quote.getAsset().setPrecision(base.getPrecision());
baseToQuoteExchange = converter.getConversionRate(order.getSellPrice(), Converter.BASE_TO_QUOTE);
quoteToBaseExchange = converter.getConversionRate(order.getSellPrice(), Converter.QUOTE_TO_BASE);
System.out.println(String.format("< id: %s, base to quote: %.5f, quote to base: %.5f", order.getObjectId(), baseToQuoteExchange, quoteToBaseExchange));
}
}
synchronized (GetLimitOrdersTest.this){
GetLimitOrdersTest.this.notifyAll();
}
}
@Override
@ -75,18 +72,64 @@ public class GetLimitOrdersTest {
}
}
}));
mWebSocket.connect();
System.out.println("Waiting..");
synchronized (this){
wait();
}
System.out.println("Released!");
} catch (NoSuchAlgorithmException e) {
System.out.println("NoSuchAlgorithmException. Msg: " + e.getMessage());
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (IOException e) {
System.out.println("IOException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
/**
* This method is designed to test how the OrderBook class handles data obtained
* from the GetLimitOrders API call.
*/
@Test
public void testOrderBook(){
LimitOrderCreateOperation limitOrderOperation;
try {
mWebSocket.addListener(new GetLimitOrders(base.getObjectId(), quote.getObjectId(), 100, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
List<LimitOrder> orders = (List<LimitOrder>) response.result;
OrderBook orderBook = new OrderBook(orders);
AssetAmount toBuy = new AssetAmount(UnsignedLong.valueOf(100000), quote);
int expiration = (int) ((System.currentTimeMillis() + 60000) / 1000);
LimitOrderCreateOperation operation = orderBook.exchange(seller, base, toBuy, expiration);
// Testing the successfull creation of a limit order create operation
Assert.assertTrue(operation != null);
double price = (double) Math.pow(10, base.getPrecision() - quote.getPrecision()) * operation.getMinToReceive().getAmount().longValue() / operation.getAmountToSell().getAmount().longValue();
System.out.println("price: "+price);
synchronized (GetLimitOrdersTest.this){
GetLimitOrdersTest.this.notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError. Msg: "+error.message);
synchronized (GetLimitOrdersTest.this){
GetLimitOrdersTest.this.notifyAll();
}
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
@ -94,7 +137,6 @@ public class GetLimitOrdersTest {
@After
public void tearDown() throws Exception {
mWebSocket.disconnect();
}
}

View file

@ -0,0 +1,141 @@
package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocketException;
import junit.framework.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.BitAssetData;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Testing the {@link GetObjects} API wrapper and its deserialization
*
* Created by nelson on 5/10/17.
*/
public class GetObjectsTest extends BaseApiTest{
private final Asset asset = new Asset("1.3.0", "BTS", 5);
private final UserAccount account = new UserAccount("1.2.116354");
private final UserAccount bilthon_25 = new UserAccount("1.2.151069");
private final String bitAssetId = "2.4.13";
@Test
public void testGetAsset(){
try{
ArrayList<String> ids = new ArrayList<>();
ids.add(asset.getObjectId());
mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
List<GrapheneObject> result = (List<GrapheneObject>) response.result;
System.out.println("Got " + result.size() + " result");
Assert.assertEquals("Making sure we only get one address back", 1, result.size());
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
}catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
@Test
public void testGetAccount(){
try{
ArrayList<String> ids = new ArrayList<>();
ids.add(bilthon_25.getObjectId());
mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
List<GrapheneObject> result = (List<GrapheneObject>) response.result;
UserAccount userAccount = (UserAccount) result.get(0);
System.out.println("Account name.....: "+userAccount.getName());
System.out.println("json string......: "+userAccount.toJsonString());
System.out.println("owner............: "+userAccount.getOwner().getKeyAuthList().get(0).getAddress());
System.out.println("active key.......: "+userAccount.getActive().getKeyAuthList().get(0).getAddress());
System.out.println("active account...: "+userAccount.getActive().getAccountAuthList().get(0).getObjectId());
System.out.println("memo: "+userAccount.getOptions().getMemoKey().getAddress());
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
}catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
@Test
public void testBitAssetData(){
try{
ArrayList<String> ids = new ArrayList<>();
ids.add(bitAssetId);
mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
List<GrapheneObject> list = (List<GrapheneObject>) response.result;
BitAssetData bitAssetData = (BitAssetData) list.get(0);
System.out.println("feed time: " + bitAssetData.current_feed_publication_time);
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
}catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
} }
}

View file

@ -0,0 +1,162 @@
package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocketException;
import org.junit.Test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import de.bitsharesmunich.graphenej.ObjectType;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.BroadcastedTransaction;
import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties;
import de.bitsharesmunich.graphenej.models.SubscriptionResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 4/25/17.
*/
public class SubscriptionMessagesHubTest extends BaseApiTest {
private SubscriptionMessagesHub mMessagesHub;
private WitnessResponseListener mErrorListener = new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
}
};
@Test
public void testGlobalPropertiesDeserializer(){
ArrayList<ObjectType> interestingObjects = new ArrayList();
interestingObjects.add(ObjectType.TRANSACTION_OBJECT);
interestingObjects.add(ObjectType.DYNAMIC_GLOBAL_PROPERTY_OBJECT);
try{
mMessagesHub = new SubscriptionMessagesHub("", "", interestingObjects, mErrorListener);
mMessagesHub.addSubscriptionListener(new SubscriptionListener() {
private int MAX_MESSAGES = 10;
private int messageCounter = 0;
@Override
public ObjectType getInterestObjectType() {
return ObjectType.DYNAMIC_GLOBAL_PROPERTY_OBJECT;
}
@Override
public void onSubscriptionUpdate(SubscriptionResponse response) {
System.out.println("On block");
if(response.params.size() == 2){
try{
List<Object> payload = (List) response.params.get(1);
if(payload.size() > 0 && payload.get(0) instanceof DynamicGlobalProperties){
DynamicGlobalProperties globalProperties = (DynamicGlobalProperties) payload.get(0);
// System.out.println("time.....................: "+globalProperties.time);
// System.out.println("next_maintenance_time....: "+globalProperties.next_maintenance_time);
// System.out.println("recent_slots_filled......: "+globalProperties.recent_slots_filled);
}
}catch(Exception e){
System.out.println("Exception");
System.out.println("Type: "+e.getClass());
System.out.println("Msg: "+e.getMessage());
}
}
// Waiting for MAX_MESSAGES messages before releasing the wait lock
messageCounter++;
if(messageCounter > MAX_MESSAGES){
synchronized (SubscriptionMessagesHubTest.this){
SubscriptionMessagesHubTest.this.notifyAll();
}
}
}
});
mMessagesHub.addSubscriptionListener(new SubscriptionListener() {
@Override
public ObjectType getInterestObjectType() {
return ObjectType.TRANSACTION_OBJECT;
}
@Override
public void onSubscriptionUpdate(SubscriptionResponse response) {
System.out.println("onTx");
}
});
mWebSocket.addListener(mMessagesHub);
mWebSocket.connect();
// Holding this thread while we get update notifications
synchronized (this){
wait();
}
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
/**
* This is a basic test that will only display a count of operations per received broadcasted transactions.
*/
@Test
public void testBroadcastedTransactionDeserializer(){
try{
mMessagesHub = new SubscriptionMessagesHub("", "", mErrorListener);
mMessagesHub.addSubscriptionListener(new SubscriptionListener() {
private int MAX_MESSAGES = 15;
private int messageCounter = 0;
@Override
public ObjectType getInterestObjectType() {
return ObjectType.TRANSACTION_OBJECT;
}
@Override
public void onSubscriptionUpdate(SubscriptionResponse response) {
if(response.params.size() == 2){
List<Serializable> payload = (List) response.params.get(1);
if(payload.size() > 0){
for(Serializable item : payload){
if(item instanceof BroadcastedTransaction){
BroadcastedTransaction broadcastedTransaction = (BroadcastedTransaction) item;
Transaction tx = broadcastedTransaction.getTransaction();
System.out.println(String.format("Got %d operations", tx.getOperations().size()));
}
}
}
}
// Waiting for MAX_MESSAGES messages before releasing the wait lock
messageCounter++;
if(messageCounter > MAX_MESSAGES){
synchronized (SubscriptionMessagesHubTest.this){
SubscriptionMessagesHubTest.this.notifyAll();
}
}
}
});
mWebSocket.addListener(mMessagesHub);
mWebSocket.connect();
// Holding this thread while we get update notifications
synchronized (this){
wait();
}
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
}

View file

@ -0,0 +1,80 @@
package de.bitsharesmunich.graphenej.operations;
import com.google.common.primitives.UnsignedLong;
import org.bitcoinj.core.ECKey;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Address;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.BaseOperation;
import de.bitsharesmunich.graphenej.BlockData;
import de.bitsharesmunich.graphenej.BrainKey;
import de.bitsharesmunich.graphenej.PublicKey;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.Util;
import de.bitsharesmunich.graphenej.errors.MalformedAddressException;
/**
* Created by nelson on 4/18/17.
*/
public class AccountUpdateOperationTest {
private static final String BILTHON_16_BRAIN_KEY = "SOAPILY GASSING FIFIE OZONATE WHYO TOPLINE PRISMY ZEUGMA GLOTTIC DAVEN CORODY PFUI";
public final String ADDRESS = "BTS8RYD5ehEMtTrfmeWRVKJzvLK2AqunxRh2XhXyXVxKtDjeAhYs1";
private final Asset CORE = new Asset("1.3.0");
private Authority active;
private AccountOptions options;
@Before
public void setup(){
try{
HashMap<Address, Long> keyAuth = new HashMap<>();
keyAuth.put(new Address(ADDRESS), 1l);
active = new Authority();
active.setKeyAuthorities(keyAuth);
options = new AccountOptions();
options.setMemoKey(new PublicKey(ECKey.fromPublicOnly(new Address(ADDRESS).getPublicKey().toBytes())));
options.setNumWitness(0);
options.setNum_comittee(0);
options.setVotingAccount(new UserAccount("1.2.5"));
}catch(MalformedAddressException e){
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
}
}
@Test
public void testOperationSerialization(){
AccountUpdateOperationBuilder builder = new AccountUpdateOperationBuilder()
.setAccount(new UserAccount("1.2.143569"))
.setFee(new AssetAmount(UnsignedLong.valueOf(14676), CORE))
.setActive(active)
.setOptions(options);
AccountUpdateOperation operation = builder.build();
ArrayList<BaseOperation> operations = new ArrayList<>();
operations.add(operation);
ECKey privateKey = new BrainKey(BILTHON_16_BRAIN_KEY, 0).getPrivateKey();
BlockData blockData = new BlockData(3703, 2015738269, 1492551764);
Transaction tx = new Transaction(privateKey, blockData, operations);
// String json = tx.toJsonString();
byte[] serialized = tx.toBytes();
// System.out.println("json: "+json);
System.out.println("serialized: "+ Util.bytesToHex(serialized));
}
}