Initial commit

This commit is contained in:
Nelson R. Perez 2016-11-21 12:50:30 -05:00
commit 52c2c9db5e
39 changed files with 2603 additions and 0 deletions

77
.gitignore vendored Normal file
View 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
View 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

Binary file not shown.

View 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
View 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
View 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
View file

@ -0,0 +1,3 @@
rootProject.name = 'fullerene'
include 'application'

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

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

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

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

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

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

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

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

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

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

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

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

View 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