Initial commit
This commit is contained in:
commit
52c2c9db5e
39 changed files with 2603 additions and 0 deletions
77
.gitignore
vendored
Normal file
77
.gitignore
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Mac OS X file
|
||||
.DS_Store
|
||||
|
||||
# Gradle
|
||||
# ------
|
||||
.gradle
|
||||
/build
|
||||
/buildSrc/build
|
||||
/subprojects/*/build
|
||||
/subprojects/docs/src/samples/*/*/build
|
||||
/subprojects/internal-android-performance-testing/build-android-libs
|
||||
|
||||
# IDEA
|
||||
# ----
|
||||
.idea
|
||||
.shelf
|
||||
/*.iml
|
||||
/*.ipr
|
||||
/*.iws
|
||||
/buildSrc/*.iml
|
||||
/buildSrc/*.ipr
|
||||
/buildSrc/*.iws
|
||||
/buildSrc/out
|
||||
/out
|
||||
/subprojects/*/*.iml
|
||||
/subprojects/*/out
|
||||
|
||||
# Eclipse
|
||||
# -------
|
||||
*.classpath
|
||||
*.project
|
||||
*.settings
|
||||
/bin
|
||||
/subprojects/*/bin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# NetBeans
|
||||
# --------
|
||||
.nb-gradle
|
||||
.nb-gradle-properties
|
||||
|
||||
# Vim
|
||||
# ---
|
||||
*.sw[op]
|
||||
|
||||
# Emacs
|
||||
# -----
|
||||
*~
|
||||
|
||||
# Textmate
|
||||
# --------
|
||||
.textmate
|
||||
|
||||
# Sublime Text
|
||||
# ------------
|
||||
*.sublime-*
|
||||
|
||||
# jEnv
|
||||
# ----
|
||||
.java-version
|
||||
|
||||
# OS X
|
||||
# ----
|
||||
.DS_Store
|
||||
|
||||
# HPROF
|
||||
# -----
|
||||
*.hprof
|
||||
|
||||
# Work dirs
|
||||
# ---------
|
||||
/incoming-distributions
|
||||
/intTestHomeDir
|
||||
|
||||
# Logs
|
||||
# ----
|
||||
/*.log
|
15
build.gradle
Normal file
15
build.gradle
Normal file
|
@ -0,0 +1,15 @@
|
|||
group 'com.luminiasoft'
|
||||
version '0.1-SNAPSHOT'
|
||||
|
||||
apply plugin: 'java'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||
compile 'com.neovisionaries:nv-websocket-client:1.30'
|
||||
compile 'org.bitcoinj:bitcoinj-core:0.14.3'
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
#Mon Nov 21 11:33:11 PET 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
|
164
gradlew
vendored
Executable file
164
gradlew
vendored
Executable file
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
3
settings.gradle
Normal file
3
settings.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
rootProject.name = 'fullerene'
|
||||
include 'application'
|
||||
|
13
src/main/java/com/luminiasoft/bitshares/Asset.java
Normal file
13
src/main/java/com/luminiasoft/bitshares/Asset.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/9/16.
|
||||
*/
|
||||
public class Asset extends GrapheneObject {
|
||||
|
||||
public Asset(String id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
88
src/main/java/com/luminiasoft/bitshares/AssetAmount.java
Normal file
88
src/main/java/com/luminiasoft/bitshares/AssetAmount.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.google.common.primitives.UnsignedLong;
|
||||
import com.google.gson.*;
|
||||
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
||||
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/7/16.
|
||||
*/
|
||||
public class AssetAmount implements ByteSerializable, JsonSerializable{
|
||||
/**
|
||||
* Constants used in the JSON serialization procedure.
|
||||
*/
|
||||
public static final String KEY_AMOUNT = "amount";
|
||||
public static final String KEY_ASSET_ID = "asset_id";
|
||||
|
||||
private UnsignedLong amount;
|
||||
private Asset asset;
|
||||
|
||||
public AssetAmount(UnsignedLong amount, Asset asset){
|
||||
this.amount = amount;
|
||||
this.asset = asset;
|
||||
}
|
||||
|
||||
public void setAmount(UnsignedLong amount){
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public UnsignedLong getAmount(){
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Asset getAsset(){ return this.asset; }
|
||||
@Override
|
||||
public byte[] toBytes() {
|
||||
byte[] serialized = new byte[8 + 1];
|
||||
byte[] amountBytes = this.amount.bigIntegerValue().toByteArray();
|
||||
serialized[serialized.length - 1] = (byte) asset.instance;
|
||||
|
||||
for(int i = 0; i < amountBytes.length; i++)
|
||||
serialized[i] = amountBytes[amountBytes.length - 1 - i];
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJsonString() {
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetSerializer());
|
||||
return gsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJsonObject() {
|
||||
JsonObject jsonAmount = new JsonObject();
|
||||
jsonAmount.addProperty(KEY_AMOUNT, amount);
|
||||
jsonAmount.addProperty(KEY_ASSET_ID, asset.getObjectId());
|
||||
return jsonAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom serializer used to translate this object into the JSON-formatted entry we need for a transaction.
|
||||
*/
|
||||
public static class AssetSerializer implements JsonSerializer<AssetAmount> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(AssetAmount assetAmount, Type type, JsonSerializationContext jsonSerializationContext) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty(KEY_AMOUNT, assetAmount.amount);
|
||||
obj.addProperty(KEY_ASSET_ID, assetAmount.asset.getObjectId());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AssetDeserializer implements JsonDeserializer<AssetAmount> {
|
||||
|
||||
@Override
|
||||
public AssetAmount deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
|
||||
Long amount = json.getAsJsonObject().get(KEY_AMOUNT).getAsLong();
|
||||
String assetId = json.getAsJsonObject().get(KEY_ASSET_ID).getAsString();
|
||||
AssetAmount assetAmount = new AssetAmount(UnsignedLong.valueOf(amount), new Asset(assetId));
|
||||
return assetAmount;
|
||||
}
|
||||
}
|
||||
}
|
20
src/main/java/com/luminiasoft/bitshares/BaseOperation.java
Normal file
20
src/main/java/com/luminiasoft/bitshares/BaseOperation.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
||||
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/5/16.
|
||||
*/
|
||||
public abstract class BaseOperation implements ByteSerializable, JsonSerializable{
|
||||
|
||||
protected OperationType type;
|
||||
|
||||
public BaseOperation(OperationType type){
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public abstract byte getId();
|
||||
|
||||
public abstract byte[] toBytes();
|
||||
}
|
101
src/main/java/com/luminiasoft/bitshares/BlockData.java
Normal file
101
src/main/java/com/luminiasoft/bitshares/BlockData.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* This class encapsulates all block-related information needed in order to build a valid transaction.
|
||||
*/
|
||||
public class BlockData implements ByteSerializable {
|
||||
private final int REF_BLOCK_NUM_BYTES = 2;
|
||||
private final int REF_BLOCK_PREFIX_BYTES = 4;
|
||||
private final int REF_BLOCK_EXPIRATION_BYTES = 4;
|
||||
|
||||
private int refBlockNum;
|
||||
private long refBlockPrefix;
|
||||
private long relativeExpiration;
|
||||
|
||||
/**
|
||||
* Block data constructor
|
||||
* @param ref_block_num: Least significant 16 bits from the reference block number.
|
||||
* If "relative_expiration" is zero, this field must be zero as well.
|
||||
* @param ref_block_prefix: The first non-block-number 32-bits of the reference block ID.
|
||||
* Recall that block IDs have 32 bits of block number followed by the
|
||||
* actual block hash, so this field should be set using the second 32 bits
|
||||
* in the block_id_type
|
||||
* @param relative_expiration: This field specifies the number of block intervals after the
|
||||
* reference block until this transaction becomes invalid. If this field is
|
||||
* set to zero, the "ref_block_prefix" is interpreted as an absolute timestamp
|
||||
* of the time the transaction becomes invalid.
|
||||
*/
|
||||
public BlockData(int ref_block_num, long ref_block_prefix, long relative_expiration){
|
||||
this.refBlockNum = ref_block_num;
|
||||
this.refBlockPrefix = ref_block_prefix;
|
||||
this.relativeExpiration = relative_expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block data constructor that takes in raw blockchain information.
|
||||
* @param head_block_number: The last block number.
|
||||
* @param head_block_id: The last block apiId.
|
||||
* @param relative_expiration: The relative expiration
|
||||
*/
|
||||
public BlockData(long head_block_number, String head_block_id, long relative_expiration){
|
||||
String hashData = head_block_id.substring(8, 16);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(int i = 0; i < 8; i = i + 2){
|
||||
builder.append(hashData.substring(6 - i, 8 - i));
|
||||
}
|
||||
this.refBlockNum = ((int) head_block_number ) & 0xFFFF;
|
||||
this.refBlockPrefix = Long.parseLong(builder.toString(), 16);
|
||||
this.relativeExpiration = relative_expiration;
|
||||
}
|
||||
|
||||
public int getRefBlockNum() {
|
||||
return refBlockNum;
|
||||
}
|
||||
|
||||
public void setRefBlockNum(int refBlockNum) {
|
||||
this.refBlockNum = refBlockNum;
|
||||
}
|
||||
|
||||
public long getRefBlockPrefix() {
|
||||
return refBlockPrefix;
|
||||
}
|
||||
|
||||
public void setRefBlockPrefix(long refBlockPrefix) {
|
||||
this.refBlockPrefix = refBlockPrefix;
|
||||
}
|
||||
|
||||
public long getRelativeExpiration() {
|
||||
return relativeExpiration;
|
||||
}
|
||||
|
||||
public void setRelativeExpiration(long relativeExpiration) {
|
||||
this.relativeExpiration = relativeExpiration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] toBytes() {
|
||||
// Allocating a fixed length byte array, since we will always need
|
||||
// 2 bytes for the ref_block_num value
|
||||
// 4 bytes for the ref_block_prefix value
|
||||
// 4 bytes for the relative_expiration
|
||||
|
||||
byte[] result = new byte[REF_BLOCK_NUM_BYTES + REF_BLOCK_PREFIX_BYTES + REF_BLOCK_EXPIRATION_BYTES];
|
||||
for(int i = 0; i < result.length; i++){
|
||||
if(i < REF_BLOCK_NUM_BYTES){
|
||||
result[i] = (byte) (this.refBlockNum >> 8 * i);
|
||||
}else if(i >= REF_BLOCK_NUM_BYTES && i < REF_BLOCK_NUM_BYTES + REF_BLOCK_PREFIX_BYTES){
|
||||
result[i] = (byte) (this.refBlockPrefix >> 8 * (i - REF_BLOCK_NUM_BYTES));
|
||||
}else{
|
||||
result[i] = (byte) (this.relativeExpiration >> 8 * (i - REF_BLOCK_NUM_BYTES + REF_BLOCK_PREFIX_BYTES));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
31
src/main/java/com/luminiasoft/bitshares/BrainKey.java
Normal file
31
src/main/java/com/luminiasoft/bitshares/BrainKey.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/19/16.
|
||||
*/
|
||||
public class BrainKey {
|
||||
|
||||
private ECKey mPrivateKey;
|
||||
|
||||
public BrainKey(String words, int sequence){
|
||||
String encoded = String.format("%s %d", words, sequence);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
byte[] bytes = md.digest(encoded.getBytes("UTF-8"));
|
||||
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
|
||||
byte[] result = sha256.digest(bytes);
|
||||
System.out.println("hash: "+Util.bytesToHex(result));
|
||||
//TODO: Transform this final result into a ECKey private key (mPrivateKey)
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
System.out.println("NoSuchAlgotithmException. Msg: "+e.getMessage());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
System.out.println("UnsupportedEncodingException. Msg: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
16
src/main/java/com/luminiasoft/bitshares/Chains.java
Normal file
16
src/main/java/com/luminiasoft/bitshares/Chains.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/8/16.
|
||||
*/
|
||||
public class Chains {
|
||||
public static class BITSHARES {
|
||||
public static final String CHAIN_ID = "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8";
|
||||
}
|
||||
public static class GRAPHENE {
|
||||
public static final String CHAIN_ID = "b8d1603965b3eb1acba27e62ff59f74efa3154d43a4188d381088ac7cdf35539";
|
||||
}
|
||||
public static class TEST {
|
||||
public static final String CHAIN_ID = "39f5e2ede1f8bc1a3a54a7914414e3779e33193f1f5693510e73cb7a87617447";
|
||||
}
|
||||
}
|
8
src/main/java/com/luminiasoft/bitshares/Extension.java
Normal file
8
src/main/java/com/luminiasoft/bitshares/Extension.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/9/16.
|
||||
*/
|
||||
public class Extension {
|
||||
//TODO: Give this class a proper implementation
|
||||
}
|
33
src/main/java/com/luminiasoft/bitshares/GrapheneObject.java
Normal file
33
src/main/java/com/luminiasoft/bitshares/GrapheneObject.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generic class used to represent a graphene object as defined in
|
||||
* <a href="http://docs.bitshares.org/development/blockchain/objects.html"></a>
|
||||
* </p>
|
||||
* Created by nelson on 11/8/16.
|
||||
*/
|
||||
public class GrapheneObject {
|
||||
protected int space;
|
||||
protected int type;
|
||||
protected long instance;
|
||||
|
||||
public GrapheneObject(String id){
|
||||
String[] parts = id.split("\\.");
|
||||
if(parts.length == 3){
|
||||
this.space = Integer.parseInt(parts[0]);
|
||||
this.type = Integer.parseInt(parts[1]);
|
||||
this.instance = Long.parseLong(parts[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return: A String containing the full object apiId in the form {space}.{type}.{instance}
|
||||
*/
|
||||
public String getObjectId(){
|
||||
return String.format("%d.%d.%d", space, type, instance);
|
||||
}
|
||||
}
|
64
src/main/java/com/luminiasoft/bitshares/Main.java
Normal file
64
src/main/java/com/luminiasoft/bitshares/Main.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
// Brain key from Nelson's app referencing the bilthon-83 account
|
||||
public static final String BRAIN_KEY = "PUMPER ISOTOME SERE STAINER CLINGER MOONLIT CHAETA UPBRIM AEDILIC BERTHER NIT SHAP SAID SHADING JUNCOUS CHOUGH";
|
||||
|
||||
// WIF from Nelson's app referencing the bilthon-83 account
|
||||
public static final String WIF = "5J96pne45qWM1WpektoeazN6k9Mt93jQ7LyueRxFfEMTiy6yxjM";
|
||||
|
||||
// WIF from the cli_wallet instance
|
||||
// public static final String WIF = "5KMzB2GqGhnh7ufhgddmz1eKPHS72uTLeL9hHjSvPb1UywWknF5";
|
||||
public static final String EXTERNAL_SIGNATURE = "1f36c41acb774fcbc9c231b5895ec9701d6872729098d8ea56d78dda72a6b54252694db85d7591de5751b7aea06871da15d63a1028758421607ffc143e53ef3306";
|
||||
|
||||
// Static block information used for transaction serialization tests
|
||||
public static int REF_BLOCK_NUM = 56204;
|
||||
public static int REF_BLOCK_PREFIX = 1614747814;
|
||||
public static int RELATIVE_EXPIRATION = 1478385607;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Test test = new Test();
|
||||
// test.testTransactionSerialization();
|
||||
// ECKey.ECDSASignature signature = test.testSigning();
|
||||
|
||||
// try {
|
||||
// test.testWebSocketTransfer();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
// test.testCustomSerializer();
|
||||
|
||||
// test.testTransactionSerialization();
|
||||
|
||||
// test.testLoginSerialization();
|
||||
|
||||
// test.testNetworkBroadcastSerialization();
|
||||
|
||||
// test.testNetworkBroadcastDeserialization();
|
||||
|
||||
// test.testGetDynamicParams();
|
||||
|
||||
// test.testGetRequiredFeesSerialization();
|
||||
|
||||
// test.testRequiredFeesResponse();
|
||||
|
||||
// test.testTransactionBroadcastSequence();
|
||||
|
||||
// test.testAccountLookupDeserialization();
|
||||
|
||||
// test.testPrivateKeyManipulations();
|
||||
|
||||
// test.testGetAccountByName();
|
||||
|
||||
// test.testGetRequiredFees();
|
||||
|
||||
// test.testRandomNumberGeneration();
|
||||
|
||||
test.testBrainKeyOperations();
|
||||
}
|
||||
}
|
15
src/main/java/com/luminiasoft/bitshares/Memo.java
Normal file
15
src/main/java/com/luminiasoft/bitshares/Memo.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/9/16.
|
||||
*/
|
||||
public class Memo implements ByteSerializable {
|
||||
//TODO: Give this class a proper implementation
|
||||
|
||||
@Override
|
||||
public byte[] toBytes() {
|
||||
return new byte[1];
|
||||
}
|
||||
}
|
52
src/main/java/com/luminiasoft/bitshares/OperationType.java
Normal file
52
src/main/java/com/luminiasoft/bitshares/OperationType.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/6/16.
|
||||
*/
|
||||
public enum OperationType {
|
||||
transfer_operation,
|
||||
limit_order_create_operation,
|
||||
limit_order_cancel_operation,
|
||||
call_order_update_operation,
|
||||
fill_order_operation, // VIRTUAL
|
||||
account_create_operation,
|
||||
account_update_operation,
|
||||
account_whitelist_operation,
|
||||
account_upgrade_operation,
|
||||
account_transfer_operation,
|
||||
asset_create_operation,
|
||||
asset_update_operation,
|
||||
asset_update_bitasset_operation,
|
||||
asset_update_feed_producers_operation,
|
||||
asset_issue_operation,
|
||||
asset_reserve_operation,
|
||||
asset_fund_fee_pool_operation,
|
||||
asset_settle_operation,
|
||||
asset_global_settle_operation,
|
||||
asset_publish_feed_operation,
|
||||
witness_create_operation,
|
||||
witness_update_operation,
|
||||
proposal_create_operation,
|
||||
proposal_update_operation,
|
||||
proposal_delete_operation,
|
||||
withdraw_permission_create_operation,
|
||||
withdraw_permission_update_operation,
|
||||
withdraw_permission_claim_operation,
|
||||
withdraw_permission_delete_operation,
|
||||
committee_member_create_operation,
|
||||
committee_member_update_operation,
|
||||
committee_member_update_global_parameters_operation,
|
||||
vesting_balance_create_operation,
|
||||
vesting_balance_withdraw_operation,
|
||||
worker_create_operation,
|
||||
custom_operation,
|
||||
assert_operation,
|
||||
balance_claim_operation,
|
||||
override_transfer_operation,
|
||||
transfer_to_blind_operation,
|
||||
blind_transfer_operation,
|
||||
transfer_from_blind_operation,
|
||||
asset_settle_cancel_operation, // VIRTUAL
|
||||
asset_claim_fees_operation,
|
||||
fba_distribute_operation // VIRTUAL
|
||||
}
|
13
src/main/java/com/luminiasoft/bitshares/RPC.java
Normal file
13
src/main/java/com/luminiasoft/bitshares/RPC.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/16/16.
|
||||
*/
|
||||
public class RPC {
|
||||
public static final String CALL_LOGIN = "login";
|
||||
public static final String CALL_NETWORK_BROADCAST = "network_broadcast";
|
||||
public static final String CALL_GET_ACCOUNT_BY_NAME = "get_account_by_name";
|
||||
public static final String CALL_GET_DYNAMIC_GLOBAL_PROPERTIES = "get_dynamic_global_properties";
|
||||
public static final String CALL_BROADCAST_TRANSACTION = "broadcast_transaction";
|
||||
public static final String CALL_GET_REQUIRED_FEES = "get_required_fees";
|
||||
}
|
509
src/main/java/com/luminiasoft/bitshares/Test.java
Normal file
509
src/main/java/com/luminiasoft/bitshares/Test.java
Normal file
|
@ -0,0 +1,509 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.google.common.primitives.UnsignedLong;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.luminiasoft.bitshares.errors.MalformedTransactionException;
|
||||
import com.luminiasoft.bitshares.interfaces.WitnessResponseListener;
|
||||
import com.luminiasoft.bitshares.models.*;
|
||||
import com.luminiasoft.bitshares.ws.GetAccountByName;
|
||||
import com.luminiasoft.bitshares.ws.GetRequiredFees;
|
||||
import com.luminiasoft.bitshares.ws.TransactionBroadcastSequence;
|
||||
import com.neovisionaries.ws.client.*;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.spongycastle.crypto.Digest;
|
||||
import org.spongycastle.crypto.digests.SHA512Digest;
|
||||
import org.spongycastle.crypto.prng.DigestRandomGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/9/16.
|
||||
*/
|
||||
public class Test {
|
||||
public static final String WITNESS_URL = "ws://api.devling.xyz:8088";
|
||||
private Transaction transaction;
|
||||
|
||||
public Transaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
|
||||
private WitnessResponseListener mListener = new WitnessResponseListener() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(WitnessResponse response) {
|
||||
if(response.result.getClass() == AccountProperties.class){
|
||||
AccountProperties accountProperties = (AccountProperties) response.result;
|
||||
System.out.println("Got account properties");
|
||||
System.out.println("id: "+accountProperties.id);
|
||||
}else if(response.result.getClass() == ArrayList.class){
|
||||
List l = (List) response.result;
|
||||
if(l.size() > 0){
|
||||
if(l.get(0).getClass() == AssetAmount.class){
|
||||
AssetAmount assetAmount = (AssetAmount) l.get(0);
|
||||
System.out.println("Got fee");
|
||||
System.out.println("amount: "+assetAmount.getAmount()+", asset id: "+assetAmount.getAsset().getObjectId());
|
||||
}
|
||||
}else{
|
||||
System.out.println("Got empty list!");
|
||||
}
|
||||
}else{
|
||||
System.out.println("Got other: "+response.result.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(BaseResponse.Error error) {
|
||||
System.out.println("onError. message: "+error.message);
|
||||
}
|
||||
};
|
||||
|
||||
public ECKey.ECDSASignature testSigning() {
|
||||
byte[] serializedTransaction = this.transaction.toBytes();
|
||||
Sha256Hash hash = Sha256Hash.wrap(Sha256Hash.hash(serializedTransaction));
|
||||
byte[] bytesDigest = hash.getBytes();
|
||||
ECKey sk = transaction.getPrivateKey();
|
||||
ECKey.ECDSASignature signature = sk.sign(hash);
|
||||
return signature;
|
||||
}
|
||||
|
||||
public String testSigningMessage() {
|
||||
byte[] serializedTransaction = this.transaction.toBytes();
|
||||
Sha256Hash hash = Sha256Hash.wrap(Sha256Hash.hash(serializedTransaction));
|
||||
ECKey sk = transaction.getPrivateKey();
|
||||
return sk.signMessage(hash.toString());
|
||||
}
|
||||
|
||||
public byte[] signMessage() {
|
||||
byte[] serializedTransaction = this.transaction.toBytes();
|
||||
Sha256Hash hash = Sha256Hash.wrap(Sha256Hash.hash(serializedTransaction));
|
||||
System.out.println(">> digest <<");
|
||||
System.out.println(Util.bytesToHex(hash.getBytes()));
|
||||
ECKey sk = transaction.getPrivateKey();
|
||||
System.out.println("Private key bytes");
|
||||
System.out.println(Util.bytesToHex(sk.getPrivKeyBytes()));
|
||||
boolean isCanonical = false;
|
||||
int recId = -1;
|
||||
ECKey.ECDSASignature sig = null;
|
||||
while (!isCanonical) {
|
||||
sig = sk.sign(hash);
|
||||
if (!sig.isCanonical()) {
|
||||
System.out.println("Signature was not canonical, retrying");
|
||||
continue;
|
||||
} else {
|
||||
System.out.println("Signature is canonical");
|
||||
isCanonical = true;
|
||||
}
|
||||
// Now we have to work backwards to figure out the recId needed to recover the signature.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ECKey k = ECKey.recoverFromSignature(i, sig, hash, sk.isCompressed());
|
||||
if (k != null && k.getPubKeyPoint().equals(sk.getPubKeyPoint())) {
|
||||
recId = i;
|
||||
break;
|
||||
} else {
|
||||
if (k == null) {
|
||||
System.out.println("Recovered key was null");
|
||||
}
|
||||
if (k.getPubKeyPoint().equals(sk.getPubKeyPoint())) {
|
||||
System.out.println("Recovered pub point is not equal to sk pub point");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (recId == -1)
|
||||
throw new RuntimeException("Could not construct a recoverable key. This should never happen.");
|
||||
}
|
||||
int headerByte = recId + 27 + (sk.isCompressed() ? 4 : 0);
|
||||
byte[] sigData = new byte[65]; // 1 header + 32 bytes for R + 32 bytes for S
|
||||
sigData[0] = (byte) headerByte;
|
||||
System.arraycopy(Utils.bigIntegerToBytes(sig.r, 32), 0, sigData, 1, 32);
|
||||
System.arraycopy(Utils.bigIntegerToBytes(sig.s, 32), 0, sigData, 33, 32);
|
||||
System.out.println("recId: " + recId);
|
||||
System.out.println("r: " + Util.bytesToHex(sig.r.toByteArray()));
|
||||
System.out.println("s: " + Util.bytesToHex(sig.s.toByteArray()));
|
||||
return sigData;
|
||||
// return new String(Base64.encode(sigData), Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
public byte[] testTransactionSerialization(long head_block_number, String head_block_id, long relative_expiration) {
|
||||
BlockData blockData = new BlockData(head_block_number, head_block_id, relative_expiration);
|
||||
|
||||
ArrayList<BaseOperation> operations = new ArrayList<BaseOperation>();
|
||||
UserAccount from = new UserAccount("1.2.138632");
|
||||
UserAccount to = new UserAccount("1.2.129848");
|
||||
AssetAmount amount = new AssetAmount(UnsignedLong.valueOf(100), new Asset("1.3.120"));
|
||||
AssetAmount fee = new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0"));
|
||||
operations.add(new Transfer(from, to, amount, fee));
|
||||
this.transaction = new Transaction(Main.WIF, blockData, operations);
|
||||
byte[] serializedTransaction = this.transaction.toBytes();
|
||||
System.out.println("Serialized transaction");
|
||||
System.out.println(Util.bytesToHex(serializedTransaction));
|
||||
return serializedTransaction;
|
||||
}
|
||||
|
||||
public void testWebSocketTransfer() throws IOException {
|
||||
String login = "{\"id\":%d,\"method\":\"call\",\"params\":[1,\"login\",[\"\",\"\"]]}";
|
||||
String getDatabaseId = "{\"method\": \"call\", \"params\": [1, \"database\", []], \"jsonrpc\": \"2.0\", \"id\": %d}";
|
||||
String getHistoryId = "{\"method\": \"call\", \"params\": [1, \"history\", []], \"jsonrpc\": \"2.0\", \"id\": %d}";
|
||||
String getNetworkBroadcastId = "{\"method\": \"call\", \"params\": [1, \"network_broadcast\", []], \"jsonrpc\": \"2.0\", \"id\": %d}";
|
||||
String getDynamicParameters = "{\"method\": \"call\", \"params\": [0, \"get_dynamic_global_properties\", []], \"jsonrpc\": \"2.0\", \"id\": %d}";
|
||||
String rawPayload = "{\"method\": \"call\", \"params\": [%d, \"broadcast_transaction\", [{\"expiration\": \"%s\", \"signatures\": [\"%s\"], \"operations\": [[0, {\"fee\": {\"amount\": 264174, \"asset_id\": \"1.3.0\"}, \"amount\": {\"amount\": 100, \"asset_id\": \"1.3.120\"}, \"to\": \"1.2.129848\", \"extensions\": [], \"from\": \"1.2.138632\"}]], \"ref_block_num\": %d, \"extensions\": [], \"ref_block_prefix\": %d}]], \"jsonrpc\": \"2.0\", \"id\": %d}";
|
||||
|
||||
// String url = "wss://bitshares.openledger.info/ws";
|
||||
String url = "ws://api.devling.xyz:8088";
|
||||
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(5000);
|
||||
|
||||
// Create a WebSocket. The timeout value set above is used.
|
||||
WebSocket ws = factory.createSocket(url);
|
||||
|
||||
ws.addListener(new WebSocketAdapter() {
|
||||
|
||||
private DynamicGlobalProperties dynProperties;
|
||||
private int networkBroadcastApiId;
|
||||
|
||||
@Override
|
||||
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
|
||||
System.out.println("onConnected");
|
||||
String payload = String.format(login, 1);
|
||||
System.out.println(">>");
|
||||
System.out.println(payload);
|
||||
websocket.sendText(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
|
||||
System.out.println("onDisconnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextFrame(WebSocket websocket, WebSocketFrame frame) throws Exception {
|
||||
System.out.println("<<");
|
||||
String response = frame.getPayloadText();
|
||||
System.out.println(response);
|
||||
Gson gson = new Gson();
|
||||
BaseResponse baseResponse = gson.fromJson(response, BaseResponse.class);
|
||||
// if(baseResponse.id.equals("1")){
|
||||
// String payload = String.format(getDatabaseId, 2);
|
||||
// System.out.println(">>");
|
||||
// System.out.println(payload);
|
||||
// websocket.sendText(payload);
|
||||
// }else if(baseResponse.id.equals("2")){
|
||||
// String payload = String.format(getHistoryId, 3);
|
||||
// System.out.println(">>");
|
||||
// System.out.println(payload);
|
||||
// websocket.sendText(payload);
|
||||
// }else if(baseResponse.id.equals("3")){
|
||||
if (baseResponse.id == 1) {
|
||||
String payload = String.format(getNetworkBroadcastId, 2);
|
||||
System.out.println(">>");
|
||||
System.out.println(payload);
|
||||
websocket.sendText(payload);
|
||||
// }else if(baseResponse.id.equals("4")){
|
||||
}
|
||||
if (baseResponse.id == 2) {
|
||||
String payload = String.format(getDynamicParameters, 3);
|
||||
Type ApiIdResponse = new TypeToken<WitnessResponse<Integer>>() {}.getType();
|
||||
WitnessResponse<Integer> witnessResponse = gson.fromJson(response, ApiIdResponse);
|
||||
networkBroadcastApiId = witnessResponse.result.intValue();
|
||||
System.out.println(">>");
|
||||
System.out.println(payload);
|
||||
websocket.sendText(payload);
|
||||
} else if (baseResponse.id == 3) {
|
||||
// Got dynamic properties
|
||||
Type DynamicGlobalPropertiesResponse = new TypeToken<WitnessResponse<DynamicGlobalProperties>>() {
|
||||
}.getType();
|
||||
WitnessResponse<DynamicGlobalProperties> witnessResponse = gson.fromJson(response, DynamicGlobalPropertiesResponse);
|
||||
dynProperties = witnessResponse.result;
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
Date date = dateFormat.parse(dynProperties.time);
|
||||
long expirationTime = (date.getTime() / 1000) + 30;
|
||||
testTransactionSerialization(dynProperties.head_block_number, dynProperties.head_block_id, expirationTime);
|
||||
|
||||
BlockData blockData = new BlockData(dynProperties.head_block_number, dynProperties.head_block_id, expirationTime);
|
||||
byte[] signatureBytes = signMessage();
|
||||
|
||||
String payload = String.format(
|
||||
rawPayload,
|
||||
networkBroadcastApiId,
|
||||
dateFormat.format(new Date(expirationTime * 1000)),
|
||||
Util.bytesToHex(signatureBytes),
|
||||
blockData.getRefBlockNum(),
|
||||
blockData.getRefBlockPrefix(),
|
||||
4);
|
||||
System.out.println(">>");
|
||||
System.out.println(payload);
|
||||
websocket.sendText(payload);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
|
||||
System.out.println("onError");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnexpectedError(WebSocket websocket, WebSocketException cause) throws Exception {
|
||||
System.out.println("onUnexpectedError");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception {
|
||||
System.out.println("handleCallbackError. Msg: " + cause.getMessage());
|
||||
StackTraceElement[] stackTrace = cause.getStackTrace();
|
||||
for (StackTraceElement line : stackTrace) {
|
||||
System.out.println(line.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
// Connect to the server and perform an opening handshake.
|
||||
// This method blocks until the opening handshake is finished.
|
||||
ws.connect();
|
||||
} catch (OpeningHandshakeException e) {
|
||||
// A violation against the WebSocket protocol was detected
|
||||
// during the opening handshake.
|
||||
System.out.println("OpeningHandshakeException");
|
||||
} catch (WebSocketException e) {
|
||||
// Failed to establish a WebSocket connection.
|
||||
System.out.println("WebSocketException. Msg: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCustomSerializer() {
|
||||
AssetAmount amount = new AssetAmount(UnsignedLong.valueOf(100), new Asset("1.3.120"));
|
||||
String jsonAmount = amount.toJsonString();
|
||||
System.out.println("JSON amount");
|
||||
System.out.println(jsonAmount);
|
||||
}
|
||||
|
||||
public void testTransactionSerialization() {
|
||||
try {
|
||||
Transaction transaction = new TransferTransactionBuilder()
|
||||
.setSource(new UserAccount("1.2.138632"))
|
||||
.setDestination(new UserAccount("1.2.129848"))
|
||||
.setAmount(new AssetAmount(UnsignedLong.valueOf(100), new Asset("1.3.120")))
|
||||
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0")))
|
||||
.setBlockData(new BlockData(43408, 1430521623, 1479231969))
|
||||
.setPrivateKey(DumpedPrivateKey.fromBase58(null, Main.WIF).getKey())
|
||||
.build();
|
||||
|
||||
ArrayList<Serializable> transactionList = new ArrayList<>();
|
||||
transactionList.add(transaction);
|
||||
ApiCall call = new ApiCall(4, "call", "broadcast_transaction", transactionList, "2.0", 1);
|
||||
String jsonCall = call.toJsonString();
|
||||
System.out.println("json call");
|
||||
System.out.println(jsonCall);
|
||||
} catch (MalformedTransactionException e) {
|
||||
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testLoginSerialization() {
|
||||
ArrayList<Serializable> loginParams = new ArrayList<>();
|
||||
// loginParams.add("nelson");
|
||||
// loginParams.add("supersecret");
|
||||
loginParams.add(null);
|
||||
loginParams.add(null);
|
||||
ApiCall loginCall = new ApiCall(1, "login", loginParams, "2.0", 1);
|
||||
String jsonLoginCall = loginCall.toJsonString();
|
||||
System.out.println("login call");
|
||||
System.out.println(jsonLoginCall);
|
||||
}
|
||||
|
||||
public void testNetworkBroadcastSerialization() {
|
||||
ArrayList<Serializable> params = new ArrayList<>();
|
||||
ApiCall networkParamsCall = new ApiCall(3, "network_broadcast", params, "2.0", 1);
|
||||
String call = networkParamsCall.toJsonString();
|
||||
System.out.println("network broadcast");
|
||||
System.out.println(call);
|
||||
}
|
||||
|
||||
public void testNetworkBroadcastDeserialization(){
|
||||
String response = "{\"id\":2,\"result\":2}";
|
||||
Gson gson = new Gson();
|
||||
Type ApiIdResponse = new TypeToken<WitnessResponse<Integer>>() {}.getType();
|
||||
WitnessResponse<Integer> witnessResponse = gson.fromJson(response, ApiIdResponse);
|
||||
}
|
||||
|
||||
public void testGetDynamicParams() {
|
||||
ArrayList<Serializable> emptyParams = new ArrayList<>();
|
||||
ApiCall getDynamicParametersCall = new ApiCall(0, "get_dynamic_global_properties", emptyParams, "2.0", 0);
|
||||
System.out.println(getDynamicParametersCall.toJsonString());
|
||||
}
|
||||
|
||||
public void testRequiredFeesResponse() {
|
||||
String response = "{\"id\":1,\"result\":[{\"amount\":264174,\"asset_id\":\"1.3.0\"}]}";
|
||||
Type AccountLookupResponse = new TypeToken<WitnessResponse<List<AssetAmount>>>() {}.getType();
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetDeserializer());
|
||||
WitnessResponse<List<AssetAmount>> witnessResponse = gsonBuilder.create().fromJson(response, AccountLookupResponse);
|
||||
for(AssetAmount assetAmount : witnessResponse.result){
|
||||
System.out.println("asset : "+assetAmount.toJsonString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testTransactionBroadcastSequence(){
|
||||
String url = "ws://api.devling.xyz:8088";
|
||||
WitnessResponseListener listener = new WitnessResponseListener() {
|
||||
@Override
|
||||
public void onSuccess(WitnessResponse response) {
|
||||
System.out.println("onSuccess");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(BaseResponse.Error error) {
|
||||
System.out.println("onError");
|
||||
System.out.println(error.data.message);
|
||||
}
|
||||
};
|
||||
|
||||
try{
|
||||
Transaction transaction = new TransferTransactionBuilder()
|
||||
.setSource(new UserAccount("1.2.138632"))
|
||||
.setDestination(new UserAccount("1.2.129848"))
|
||||
.setAmount(new AssetAmount(UnsignedLong.valueOf(100), new Asset("1.3.120")))
|
||||
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0")))
|
||||
.setBlockData(new BlockData(43408, 1430521623, 1479231969))
|
||||
.setPrivateKey(DumpedPrivateKey.fromBase58(null, Main.WIF).getKey())
|
||||
.build();
|
||||
|
||||
ArrayList<Serializable> transactionList = new ArrayList<>();
|
||||
transactionList.add(transaction);
|
||||
ApiCall call = new ApiCall(4, "call", "broadcast_transaction", transactionList, "2.0", 1);
|
||||
|
||||
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(5000);
|
||||
try {
|
||||
WebSocket mWebSocket = factory.createSocket(url);
|
||||
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, listener));
|
||||
mWebSocket.connect();
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException. Msg: "+e.getMessage());
|
||||
} catch (WebSocketException e) {
|
||||
System.out.println("WebSocketException. Msg: "+e.getMessage());
|
||||
}
|
||||
}catch(MalformedTransactionException e){
|
||||
System.out.println("MalformedTransactionException. Msg: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAccountLookupDeserialization(){
|
||||
String response = "{\"id\":1,\"result\":[[\"ken\",\"1.2.3111\"],[\"ken-1\",\"1.2.101491\"],[\"ken-k\",\"1.2.108646\"]]}";
|
||||
Type AccountLookupResponse = new TypeToken<WitnessResponse<List<List<String>>>>() {}.getType();
|
||||
Gson gson = new Gson();
|
||||
WitnessResponse<List<List<String>>> witnessResponse = gson.fromJson(response, AccountLookupResponse);
|
||||
for(int i = 0; i < witnessResponse.result.size(); i++){
|
||||
System.out.println("suggested name: "+witnessResponse.result.get(i).get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void testPrivateKeyManipulations(){
|
||||
ECKey privateKey = DumpedPrivateKey.fromBase58(null, Main.WIF).getKey();
|
||||
System.out.println("private key..............: "+Util.bytesToHex(privateKey.getSecretBytes()));
|
||||
System.out.println("public key uncompressed..: "+Util.bytesToHex(privateKey.getPubKey()));
|
||||
System.out.println("public key compressed....: "+Util.bytesToHex(privateKey.getPubKeyPoint().getEncoded(true)));
|
||||
System.out.println("base58...................: "+Base58.encode(privateKey.getPubKeyPoint().getEncoded(true)));
|
||||
System.out.println("base58...................: "+Base58.encode(privateKey.getPubKey()));
|
||||
String brainKeyWords = "PUMPER ISOTOME SERE STAINER CLINGER MOONLIT CHAETA UPBRIM AEDILIC BERTHER NIT SHAP SAID SHADING JUNCOUS CHOUGH";
|
||||
BrainKey brainKey = new BrainKey(brainKeyWords, 0);
|
||||
}
|
||||
|
||||
public void testGetAccountByName(){
|
||||
try {
|
||||
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(5000);
|
||||
WebSocket mWebSocket = factory.createSocket(WITNESS_URL);
|
||||
mWebSocket.addListener(new GetAccountByName("bilthon-83", mListener));
|
||||
mWebSocket.connect();
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException. Msg: "+e.getMessage());
|
||||
} catch (WebSocketException e) {
|
||||
System.out.println("WebSocketException. Msg: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetRequiredFees() {
|
||||
ArrayList<Serializable> accountParams = new ArrayList<>();
|
||||
Asset asset = new Asset("1.3.0");
|
||||
UserAccount from = new UserAccount("1.2.138632");
|
||||
UserAccount to = new UserAccount("1.2.129848");
|
||||
AssetAmount amount = new AssetAmount(UnsignedLong.valueOf(100), new Asset("1.3.120"));
|
||||
AssetAmount fee = new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0"));
|
||||
Transfer transfer = new Transfer(from, to, amount, fee);
|
||||
ArrayList<BaseOperation> operations = new ArrayList<>();
|
||||
operations.add(transfer);
|
||||
|
||||
accountParams.add(operations);
|
||||
accountParams.add(asset.getObjectId());
|
||||
|
||||
try {
|
||||
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(5000);
|
||||
WebSocket mWebSocket = factory.createSocket(WITNESS_URL);
|
||||
mWebSocket.addListener(new GetRequiredFees(operations, asset, mListener));
|
||||
mWebSocket.connect();
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException. Msg: "+e.getMessage());
|
||||
} catch (WebSocketException e) {
|
||||
System.out.println("WebSocketException. Msg: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRandomNumberGeneration(){
|
||||
byte[] seed = new byte[] { new Long(System.nanoTime()).byteValue() };
|
||||
doCountTest(new SHA512Digest(), seed);
|
||||
}
|
||||
|
||||
private void doCountTest(Digest digest, byte[] seed)//, byte[] expectedXors)
|
||||
{
|
||||
DigestRandomGenerator generator = new DigestRandomGenerator(digest);
|
||||
byte[] output = new byte[digest.getDigestSize()];
|
||||
int[] averages = new int[digest.getDigestSize()];
|
||||
byte[] ands = new byte[digest.getDigestSize()];
|
||||
byte[] xors = new byte[digest.getDigestSize()];
|
||||
byte[] ors = new byte[digest.getDigestSize()];
|
||||
|
||||
generator.addSeedMaterial(seed);
|
||||
|
||||
for (int i = 0; i != 1000000; i++)
|
||||
{
|
||||
generator.nextBytes(output);
|
||||
for (int j = 0; j != output.length; j++)
|
||||
{
|
||||
averages[j] += output[j] & 0xff;
|
||||
ands[j] &= output[j];
|
||||
xors[j] ^= output[j];
|
||||
ors[j] |= output[j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i != output.length; i++) {
|
||||
if ((averages[i] / 1000000) != 127) {
|
||||
System.out.println("average test failed for " + digest.getAlgorithmName());
|
||||
}
|
||||
System.out.println("averages["+i+"] / 1000000: "+averages[i] / 1000000);
|
||||
if (ands[i |