Merge branch 'master' of github.com:Agorise/graphenej
This commit is contained in:
commit
1129a92aa3
159 changed files with 8379 additions and 231 deletions
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
custom: https://www.blockchain.com/btc/payment_request?address=1AFGT5gVj7xhfjgHTuwEoaV56WTCh7Gjf1#BITCOIN_ONLY
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -103,3 +103,4 @@ release.properties
|
|||
graphenej/build
|
||||
|
||||
local.properties
|
||||
|
||||
|
|
20
build.gradle
20
build.gradle
|
@ -3,11 +3,27 @@ subprojects {
|
|||
mavenCentral()
|
||||
}
|
||||
}
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'https://maven.google.com/'
|
||||
name 'Google'
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||
classpath 'com.novoda:bintray-release:0.9.1'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
VERSION_NAME=0.4.6
|
||||
VERSION_CODE=9
|
||||
VERSION_NAME=0.4.7-alpha3
|
||||
VERSION_CODE=12
|
||||
GROUP=com.github.bilthon
|
||||
|
||||
POM_DESCRIPTION=A Java library for mobile app Developers; Graphene/Bitshares blockchain.
|
||||
|
|
0
gradlew
vendored
Normal file → Executable file
0
gradlew
vendored
Normal file → Executable file
|
@ -1,34 +1,54 @@
|
|||
group 'cy.agorise'
|
||||
version '0.4.6'
|
||||
|
||||
apply plugin: 'com.novoda.bintray-release'
|
||||
apply plugin: 'com.android.library'
|
||||
apply from: 'maven-push.gradle'
|
||||
|
||||
|
||||
dependencies {
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
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'
|
||||
compile group: "org.tukaani", name: "xz", version: "1.6"
|
||||
publish {
|
||||
userOrg = 'bilthon'
|
||||
groupId = 'cy.agorise.graphenej'
|
||||
artifactId = 'graphenej'
|
||||
publishVersion = '0.6.0'
|
||||
repoName = 'Graphenej'
|
||||
desc = 'A Java library for mobile app Developers; Graphene/Bitshares blockchain.'
|
||||
website = 'https://github.com/Agorise/graphenej'
|
||||
}
|
||||
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion "25.0.0"
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 24
|
||||
versionCode 9
|
||||
versionName "0.4.6"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 28
|
||||
versionCode 12
|
||||
versionName "0.6.0"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
buildTypes {
|
||||
debug{}
|
||||
preRelease{}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation group: 'junit', name: 'junit', version: '4.12'
|
||||
implementation 'com.neovisionaries:nv-websocket-client:1.30'
|
||||
implementation 'org.bitcoinj:bitcoinj-core:0.14.3'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
implementation 'org.tukaani:xz:1.6'
|
||||
|
||||
androidTestImplementation 'com.android.support:support-annotations:28.0.0'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test:rules:1.0.2'
|
||||
|
||||
// Rx dependencies
|
||||
api 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
api 'io.reactivex.rxjava2:rxjava:2.2.2'
|
||||
api 'com.jakewharton.rxrelay2:rxrelay:2.1.0'
|
||||
api 'com.squareup.okhttp3:okhttp:3.12.2'
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.Log;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import cy.agorise.graphenej.network.FullNode;
|
||||
import cy.agorise.graphenej.network.LatencyNodeProvider;
|
||||
import cy.agorise.graphenej.network.NodeLatencyVerifier;
|
||||
import cy.agorise.graphenej.network.NodeProvider;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NodeLatencyVerifierTest {
|
||||
private final String TAG = this.getClass().getName();
|
||||
|
||||
String[] nodeURLs = new String[]{
|
||||
"wss://bitshares.openledger.info/ws",
|
||||
"wss://us.nodes.bitshares.ws",
|
||||
"wss://eu.nodes.bitshares.ws",
|
||||
"wss://citadel.li/node",
|
||||
"wss://api.bts.mobi/ws"
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testNodeLatencyTest() throws Exception {
|
||||
ArrayList<FullNode> nodeList = new ArrayList<>();
|
||||
nodeList.add(new FullNode(nodeURLs[0]));
|
||||
nodeList.add(new FullNode(nodeURLs[1]));
|
||||
nodeList.add(new FullNode(nodeURLs[2]));
|
||||
final NodeLatencyVerifier nodeLatencyVerifier = new NodeLatencyVerifier(nodeList);
|
||||
PublishSubject subject = nodeLatencyVerifier.start();
|
||||
final NodeProvider nodeProvider = new LatencyNodeProvider();
|
||||
subject.subscribe(new Observer<FullNode>() {
|
||||
int counter = 0;
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {}
|
||||
|
||||
@Override
|
||||
public void onNext(FullNode fullNode) {
|
||||
Log.i(TAG,String.format("Avg latency: %.2f, url: %s", fullNode.getLatencyValue(), fullNode.getUrl()));
|
||||
|
||||
// Updating node provider
|
||||
nodeProvider.updateNode(fullNode);
|
||||
List<FullNode> sortedNodes = nodeProvider.getSortedNodes();
|
||||
for(FullNode node : sortedNodes){
|
||||
Log.d(TAG,String.format("> %.2f, url: %s", node.getLatencyValue(), node.getUrl()));
|
||||
}
|
||||
|
||||
// Finish test after certain amount of rounds
|
||||
if(counter > 3){
|
||||
synchronized (NodeLatencyVerifierTest.this){
|
||||
nodeLatencyVerifier.stop();
|
||||
NodeLatencyVerifierTest.this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG,"onError.Msg: "+e.getMessage());
|
||||
synchronized (NodeLatencyVerifierTest.this){
|
||||
NodeLatencyVerifierTest.this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.d(TAG,"onComplete");
|
||||
}
|
||||
});
|
||||
try {
|
||||
synchronized(this) {
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cy.agorise.graphenej"
|
||||
android:versionCode="9"
|
||||
android:versionName="0.4.6" >
|
||||
<uses-sdk android:minSdkVersion="1" />
|
||||
<application/>
|
||||
package="cy.agorise.graphenej">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name=".api.android.NetworkService"
|
||||
android:enabled="true"
|
||||
android:exported="true"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -33,17 +33,51 @@ public class AccountOptions implements GrapheneSerializable {
|
|||
private Vote[] votes;
|
||||
private Extensions extensions;
|
||||
|
||||
/**
|
||||
* Constructor used to instantiate only the following attributes:
|
||||
* <ul>
|
||||
* <li>voting_account</li>
|
||||
* <li>votes</li>
|
||||
* <li>extensions</li>
|
||||
* </ul>
|
||||
*/
|
||||
public AccountOptions(){
|
||||
voting_account = new UserAccount(UserAccount.PROXY_TO_SELF);
|
||||
this.votes = new Vote[0];
|
||||
this.extensions = new Extensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used to instantiate only the following attributes:
|
||||
* <ul>
|
||||
* <li>voting_account</li>
|
||||
* <li>votes</li>
|
||||
* <li>memo_key</li>
|
||||
* <li>extensions</li>
|
||||
* </ul>
|
||||
*/
|
||||
public AccountOptions(PublicKey memoKey){
|
||||
this();
|
||||
this.memo_key = memoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that can be used to instantiate a version of the AccountOptions object
|
||||
* with a null reference in the 'voting_account' attribute. This can be used to prevent
|
||||
* a circular dependency situation when de-serializing the UserAccount instance.
|
||||
*
|
||||
* @param memoKey Memo public key used by this account
|
||||
* @param includeAccount Whether or not to instantiate an UserAccount
|
||||
*/
|
||||
public AccountOptions(PublicKey memoKey, boolean includeAccount){
|
||||
if(includeAccount){
|
||||
voting_account = new UserAccount(UserAccount.PROXY_TO_SELF);
|
||||
}
|
||||
this.memo_key = memoKey;
|
||||
this.votes = new Vote[0];
|
||||
this.extensions = new Extensions();
|
||||
}
|
||||
|
||||
//TODO: Implement constructor that takes a Vote array.
|
||||
|
||||
public PublicKey getMemoKey() {
|
||||
|
@ -149,13 +183,23 @@ public class AccountOptions implements GrapheneSerializable {
|
|||
*/
|
||||
public static class AccountOptionsDeserializer implements JsonDeserializer<AccountOptions> {
|
||||
|
||||
boolean mIncludeUserAccount;
|
||||
|
||||
public AccountOptionsDeserializer(){
|
||||
this.mIncludeUserAccount = true;
|
||||
}
|
||||
|
||||
public AccountOptionsDeserializer(boolean includeUserAccount){
|
||||
this.mIncludeUserAccount = includeUserAccount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountOptions deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject baseObject = json.getAsJsonObject();
|
||||
AccountOptions options;
|
||||
try {
|
||||
Address address = new Address(baseObject.get(KEY_MEMO_KEY).getAsString());
|
||||
options = new AccountOptions(address.getPublicKey());
|
||||
options = new AccountOptions(address.getPublicKey(), mIncludeUserAccount);
|
||||
} catch (MalformedAddressException e) {
|
||||
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
|
||||
options = new AccountOptions();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import cy.agorise.graphenej.errors.MalformedAddressException;
|
||||
import org.bitcoinj.core.Base58;
|
||||
|
@ -61,4 +62,18 @@ public class Address {
|
|||
ripemd160Digest.doFinal(checksum, 0);
|
||||
return Arrays.copyOfRange(checksum, 0, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Address address = (Address) o;
|
||||
return Objects.equal(publicKey, address.publicKey) &&
|
||||
Objects.equal(prefix, address.prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(publicKey, prefix);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,6 +191,11 @@ public class AssetAmount implements ByteSerializable, JsonSerializable {
|
|||
return jsonAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("(asset=%s, amount=%s)", asset.getObjectId(), amount.toString(10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom serializer used to translate this object into the JSON-formatted entry we need for a transaction.
|
||||
*/
|
||||
|
|
|
@ -9,5 +9,10 @@ package cy.agorise.graphenej;
|
|||
public enum AuthorityType {
|
||||
OWNER,
|
||||
ACTIVE,
|
||||
MEMO
|
||||
MEMO;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%d", this.ordinal());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||
import cy.agorise.graphenej.interfaces.JsonSerializable;
|
||||
import cy.agorise.graphenej.operations.TransferOperation;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/5/16.
|
||||
* Base class that represents a generic operation
|
||||
*/
|
||||
public abstract class BaseOperation implements ByteSerializable, JsonSerializable {
|
||||
|
||||
|
@ -32,4 +39,54 @@ public abstract class BaseOperation implements ByteSerializable, JsonSerializabl
|
|||
array.add(this.getId());
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* De-serializer used to unpack data from a generic operation. The general format used in the
|
||||
* JSON-RPC blockchain API is the following:
|
||||
* </p>
|
||||
*
|
||||
* <code>[OPERATION_ID, OPERATION_OBJECT]</code><br>
|
||||
*
|
||||
* <p>
|
||||
* Where <code>OPERATION_ID</code> is one of the operations defined in {@link cy.agorise.graphenej.OperationType}
|
||||
* and <code>OPERATION_OBJECT</code> is the actual operation serialized in the JSON format.
|
||||
* </p>
|
||||
* Here's an example of this serialized form for a transfer operation:<br><br>
|
||||
*<pre>
|
||||
*[
|
||||
* 0,
|
||||
* {
|
||||
* "fee": {
|
||||
* "amount": 264174,
|
||||
* "asset_id": "1.3.0"
|
||||
* },
|
||||
* "from": "1.2.138632",
|
||||
* "to": "1.2.129848",
|
||||
* "amount": {
|
||||
* "amount": 100,
|
||||
* "asset_id": "1.3.0"
|
||||
* },
|
||||
* "extensions": []
|
||||
* }
|
||||
*]
|
||||
*</pre><br>
|
||||
* If this class is used, this serialized data will be translated to a TransferOperation object instance.<br>
|
||||
*
|
||||
* TODO: Add support for operations other than the 'transfer'
|
||||
*/
|
||||
public static class OperationDeserializer implements JsonDeserializer<BaseOperation> {
|
||||
|
||||
@Override
|
||||
public BaseOperation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
BaseOperation operation = null;
|
||||
if(json.isJsonArray()){
|
||||
JsonArray array = json.getAsJsonArray();
|
||||
if(array.get(0).getAsLong() == OperationType.TRANSFER_OPERATION.ordinal()){
|
||||
operation = context.deserialize(array.get(1), TransferOperation.class);
|
||||
}
|
||||
}
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import org.bitcoinj.core.DumpedPrivateKey;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
|
@ -69,7 +71,15 @@ public class BrainKey {
|
|||
public BrainKey(String words, int sequence) {
|
||||
this.mBrainKey = words;
|
||||
this.sequenceNumber = sequence;
|
||||
String encoded = String.format("%s %d", words, sequence);
|
||||
derivePrivateKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the actual private key from the brainkey + sequence number
|
||||
*/
|
||||
private void derivePrivateKey(){
|
||||
@SuppressLint("DefaultLocale")
|
||||
String encoded = String.format("%s %d", this.mBrainKey, this.sequenceNumber);
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
byte[] bytes = md.digest(encoded.getBytes("UTF-8"));
|
||||
|
@ -120,19 +130,28 @@ public class BrainKey {
|
|||
}
|
||||
|
||||
/**
|
||||
* Brain key words getter
|
||||
* @return: The word sequence that comprises this brain key
|
||||
* Brain key words getter.
|
||||
* @return The word sequence that comprises this brain key
|
||||
*/
|
||||
public String getBrainKey(){
|
||||
return mBrainKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequence number getter
|
||||
* @return: The sequence number used alongside with the brain key words in order
|
||||
* Sequence number getter.
|
||||
* @return The sequence number used alongside with the brain key words in order
|
||||
* to derive the private key
|
||||
*/
|
||||
public int getSequenceNumber(){
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequence number setter.
|
||||
* @param sequenceNumber The sequence number used to generate a specific key from this brainkey
|
||||
*/
|
||||
public void setSequenceNumber(int sequenceNumber) {
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
derivePrivateKey();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||
import cy.agorise.graphenej.interfaces.JsonSerializable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/9/16.
|
||||
*/
|
||||
|
@ -40,4 +45,15 @@ public class Extensions implements JsonSerializable, ByteSerializable {
|
|||
public int size(){
|
||||
return extensions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom de-serializer used to avoid problems when de-serializing an object that contains
|
||||
* an extension array.
|
||||
*/
|
||||
public static class ExtensionsDeserializer implements JsonDeserializer<Extensions> {
|
||||
@Override
|
||||
public Extensions deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package cy.agorise.graphenej;
|
|||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generic class used to represent a graphene object as defined in
|
||||
|
@ -34,15 +36,15 @@ public class GrapheneObject {
|
|||
|
||||
/**
|
||||
*
|
||||
* @return: A String containing the full object apiId in the form {space}.{type}.{instance}
|
||||
* @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);
|
||||
return String.format(Locale.US, "%d.%d.%d", space, type, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this object.
|
||||
* @return: Instance of the ObjectType enum.
|
||||
* @return Instance of the ObjectType enum.
|
||||
*/
|
||||
public ObjectType getObjectType(){
|
||||
switch(space){
|
||||
|
@ -78,6 +80,8 @@ public class GrapheneObject {
|
|||
return ObjectType.WORKER_OBJECT;
|
||||
case 15:
|
||||
return ObjectType.BALANCE_OBJECT;
|
||||
case 16:
|
||||
return ObjectType.HTLC_OBJECT;
|
||||
}
|
||||
case IMPLEMENTATION_SPACE:
|
||||
switch(type){
|
||||
|
|
43
graphenej/src/main/java/cy/agorise/graphenej/Htlc.java
Normal file
43
graphenej/src/main/java/cy/agorise/graphenej/Htlc.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||
import cy.agorise.graphenej.interfaces.JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class used to represent an existing HTLC contract.
|
||||
*/
|
||||
public class Htlc extends GrapheneObject implements ByteSerializable, JsonSerializable {
|
||||
|
||||
public Htlc(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toBytes() {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
DataOutput out = new DataOutputStream(byteArrayOutputStream);
|
||||
try {
|
||||
Varint.writeUnsignedVarLong(this.instance, out);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJsonString() {
|
||||
return this.getObjectId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement toJsonObject() {
|
||||
return null;
|
||||
}
|
||||
}
|
45
graphenej/src/main/java/cy/agorise/graphenej/HtlcHash.java
Normal file
45
graphenej/src/main/java/cy/agorise/graphenej/HtlcHash.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||
import cy.agorise.graphenej.interfaces.JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class used to represent a HTLC hash.
|
||||
*/
|
||||
public class HtlcHash implements ByteSerializable, JsonSerializable {
|
||||
private HtlcHashType hashType;
|
||||
private byte[] hash;
|
||||
|
||||
public HtlcHash(HtlcHashType hashType, byte[] hash) {
|
||||
this.hashType = hashType;
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public HtlcHashType getType(){
|
||||
return this.hashType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toBytes() {
|
||||
byte[] hashTypeBytes = new byte[] { Util.revertInteger(hashType.ordinal())[3] };
|
||||
return Bytes.concat(hashTypeBytes, hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJsonString() {
|
||||
JsonElement element = toJsonObject();
|
||||
return element.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement toJsonObject() {
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(hashType.ordinal());
|
||||
array.add(Util.byteToString(hash));
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package cy.agorise.graphenej;
|
||||
|
||||
/**
|
||||
* Used to enumerate the possible hash algorithms used in HTLCs.
|
||||
* @see <a href="https://github.com/bitshares/bitshares-core/blob/623aea265f2711adade982fc3248e6528dc8ac51/libraries/chain/include/graphene/chain/protocol/htlc.hpp">htlc.hpp</a>
|
||||
*/
|
||||
public enum HtlcHashType {
|
||||
RIPEMD160,
|
||||
SHA1,
|
||||
SHA256
|
||||
}
|
|
@ -1,15 +1,11 @@
|
|||
package cy.agorise.graphenej.objects;
|
||||
package cy.agorise.graphenej;
|
||||
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
import com.google.gson.*;
|
||||
import cy.agorise.graphenej.errors.ChecksumException;
|
||||
import cy.agorise.graphenej.errors.MalformedAddressException;
|
||||
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||
import cy.agorise.graphenej.interfaces.JsonSerializable;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.spongycastle.math.ec.ECPoint;
|
||||
|
||||
|
@ -19,20 +15,11 @@ import java.security.MessageDigest;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import cy.agorise.graphenej.Address;
|
||||
import cy.agorise.graphenej.PublicKey;
|
||||
import cy.agorise.graphenej.Util;
|
||||
import cy.agorise.graphenej.errors.ChecksumException;
|
||||
import cy.agorise.graphenej.errors.MalformedAddressException;
|
||||
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||
import cy.agorise.graphenej.interfaces.JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class used to represent a memo data structure
|
||||
* {@url https://bitshares.org/doxygen/structgraphene_1_1chain_1_1memo__data.html}
|
||||
*/
|
||||
public class Memo implements ByteSerializable, JsonSerializable {
|
||||
public final static String TAG = "Memo";
|
||||
public static final String KEY_FROM = "from";
|
||||
public static final String KEY_TO = "to";
|
||||
public static final String KEY_NONCE = "nonce";
|
||||
|
@ -190,10 +177,6 @@ public class Memo implements ByteSerializable, JsonSerializable {
|
|||
|
||||
byte[] seed = Bytes.concat(nonceBytes, Util.hexlify(Util.bytesToHex(ss)));
|
||||
|
||||
// Calculating checksum
|
||||
byte[] sha256Msg = sha256.digest(message);
|
||||
|
||||
|
||||
// Applying decryption
|
||||
byte[] temp = Util.decryptAES(message, seed);
|
||||
byte[] checksum = Arrays.copyOfRange(temp, 0, 4);
|
||||
|
@ -205,7 +188,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
|
|||
throw new ChecksumException("Invalid checksum found while performing decryption");
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
System.out.println("NoSuchAlgotithmException. Msg:"+ e.getMessage());
|
||||
System.out.println("NoSuchAlgorithmException. Msg:"+ e.getMessage());
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
@ -291,13 +274,15 @@ public class Memo implements ByteSerializable, JsonSerializable {
|
|||
memoObject.addProperty(KEY_FROM, "");
|
||||
memoObject.addProperty(KEY_TO, "");
|
||||
memoObject.addProperty(KEY_NONCE, "");
|
||||
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message));
|
||||
if(this.message != null)
|
||||
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message));
|
||||
return null;
|
||||
}else{
|
||||
memoObject.addProperty(KEY_FROM, this.from.toString());
|
||||
memoObject.addProperty(KEY_TO, this.to.toString());
|
||||
memoObject.addProperty(KEY_NONCE, String.format("%x", this.nonce));
|
||||
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message));
|
||||
memoObject.addProperty(KEY_NONCE, this.nonce.toString());
|
||||
if(this.message != null)
|
||||
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message));
|
||||
}
|
||||
return memoObject;
|
||||
}
|
||||
|
@ -310,8 +295,9 @@ public class Memo implements ByteSerializable, JsonSerializable {
|
|||
*/
|
||||
public JsonElement toJson(boolean decimal){
|
||||
JsonElement jsonElement = toJsonObject();
|
||||
if(decimal){
|
||||
if(decimal && jsonElement != null){
|
||||
JsonObject jsonObject = (JsonObject) jsonElement;
|
||||
// The nonce is interpreted in base 16, but it is going to be written in base 10
|
||||
BigInteger nonce = new BigInteger(jsonObject.get(KEY_NONCE).getAsString(), 16);
|
||||
jsonObject.addProperty(KEY_NONCE, nonce.toString());
|
||||
}
|
|
@ -20,6 +20,7 @@ public enum ObjectType {
|
|||
VESTING_BALANCE_OBJECT,
|
||||
WORKER_OBJECT,
|
||||
BALANCE_OBJECT,
|
||||
HTLC_OBJECT,
|
||||
GLOBAL_PROPERTY_OBJECT,
|
||||
DYNAMIC_GLOBAL_PROPERTY_OBJECT,
|
||||
ASSET_DYNAMIC_DATA,
|
||||
|
@ -53,6 +54,7 @@ public enum ObjectType {
|
|||
case VESTING_BALANCE_OBJECT:
|
||||
case WORKER_OBJECT:
|
||||
case BALANCE_OBJECT:
|
||||
case HTLC_OBJECT:
|
||||
space = 1;
|
||||
break;
|
||||
case GLOBAL_PROPERTY_OBJECT:
|
||||
|
@ -123,6 +125,8 @@ public enum ObjectType {
|
|||
case BALANCE_OBJECT:
|
||||
type = 15;
|
||||
break;
|
||||
case HTLC_OBJECT:
|
||||
type = 16;
|
||||
case GLOBAL_PROPERTY_OBJECT:
|
||||
type = 0;
|
||||
break;
|
||||
|
|
|
@ -51,5 +51,15 @@ public enum OperationType {
|
|||
BLIND_TRANSFER_OPERATION,
|
||||
TRANSFER_FROM_BLIND_OPERATION,
|
||||
ASSET_SETTLE_CANCEL_OPERATION, // VIRTUAL
|
||||
ASSET_CLAIM_FEES_OPERATION
|
||||
ASSET_CLAIM_FEES_OPERATION,
|
||||
FBA_DISTRIBUTE_OPERATION,
|
||||
BID_COLLATERAL_OPERATION,
|
||||
EXECUTE_BID_OPERATION, // VIRTUAL
|
||||
ASSET_CLAIM_POOL_OPERATION,
|
||||
ASSET_UPDATE_ISSUER_OPERATION,
|
||||
HTLC_CREATE_OPERATION,
|
||||
HTLC_REDEEM_OPERATION,
|
||||
HTLC_REDEEMED_OPERATION, // VIRTUAL
|
||||
HTLC_EXTEND_OPERATION,
|
||||
HTLC_REFUND_OPERATION // VIRTUAL
|
||||
}
|
||||
|
|
|
@ -132,4 +132,8 @@ public class OrderBook {
|
|||
}
|
||||
return obtainedBase;
|
||||
}
|
||||
|
||||
public List<LimitOrder> getLimitOrders(){
|
||||
return limitOrders;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,4 +18,13 @@ package cy.agorise.graphenej;
|
|||
public class Price {
|
||||
public AssetAmount base;
|
||||
public AssetAmount quote;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("base:[%s, %s], quote:[%s, %s]",
|
||||
base.getAsset().getObjectId(),
|
||||
base.getAmount().toString(),
|
||||
quote.getAsset().getObjectId(),
|
||||
quote.getAmount().toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,4 +53,9 @@ public class PublicKey implements ByteSerializable, Serializable {
|
|||
PublicKey other = (PublicKey) obj;
|
||||
return this.publicKey.equals(other.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getAddress();
|
||||
}
|
||||
}
|
|
@ -14,15 +14,19 @@ public class RPC {
|
|||
public static final String CALL_CANCEL_ALL_SUBSCRIPTIONS = "cancel_all_subscriptions";
|
||||
public static final String CALL_GET_ACCOUNT_BY_NAME = "get_account_by_name";
|
||||
public static final String CALL_GET_ACCOUNTS = "get_accounts";
|
||||
public static final String CALL_GET_FULL_ACCOUNTS = "get_full_accounts";
|
||||
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";
|
||||
public static final String CALL_GET_KEY_REFERENCES = "get_key_references";
|
||||
public static final String CALL_GET_RELATIVE_ACCOUNT_HISTORY = "get_relative_account_history";
|
||||
public static final String CALL_GET_ACCOUNT_HISTORY = "get_account_history";
|
||||
public static final String CALL_GET_ACCOUNT_HISTORY_BY_OPERATIONS = "get_account_history_by_operations";
|
||||
public static final String CALL_LOOKUP_ACCOUNTS = "lookup_accounts";
|
||||
public static final String CALL_LIST_ASSETS = "list_assets";
|
||||
public static final String GET_OBJECTS = "get_objects";
|
||||
public static final String GET_ACCOUNT_BALANCES = "get_account_balances";
|
||||
public static final String CALL_GET_ASSETS = "get_assets";
|
||||
public static final String CALL_GET_OBJECTS = "get_objects";
|
||||
public static final String CALL_GET_ACCOUNT_BALANCES = "get_account_balances";
|
||||
public static final String CALL_LOOKUP_ASSET_SYMBOLS = "lookup_asset_symbols";
|
||||
public static final String CALL_GET_BLOCK_HEADER = "get_block_header";
|
||||
public static final String CALL_GET_BLOCK = "get_block";
|
||||
|
@ -30,4 +34,5 @@ public class RPC {
|
|||
public static final String CALL_GET_TRADE_HISTORY = "get_trade_history";
|
||||
public static final String CALL_GET_MARKET_HISTORY = "get_market_history";
|
||||
public static final String CALL_GET_ALL_ASSET_HOLDERS = "get_all_asset_holders";
|
||||
public static final String CALL_GET_TRANSACTION = "get_transaction";
|
||||
}
|
|
@ -20,6 +20,7 @@ import java.lang.reflect.Type;
|
|||
import java.text.ParsePosition;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
@ -97,16 +98,25 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
public Transaction(BlockData blockData, List<BaseOperation> operationList){
|
||||
this.blockData = blockData;
|
||||
this.operations = operationList;
|
||||
this.extensions = new Extensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the block data
|
||||
* Block data getter
|
||||
* @param blockData New block data
|
||||
*/
|
||||
public void setBlockData(BlockData blockData){
|
||||
this.blockData = blockData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block data setter
|
||||
* @return BlockData instance
|
||||
*/
|
||||
public BlockData getBlockData(){
|
||||
return this.blockData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the fees for all operations in this transaction.
|
||||
* @param fees: New fees to apply
|
||||
|
@ -229,7 +239,12 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
|
||||
// Getting the signature before anything else,
|
||||
// since this might change the transaction expiration data slightly
|
||||
byte[] signature = getGrapheneSignature();
|
||||
byte[] signature = null;
|
||||
try{
|
||||
signature = getGrapheneSignature();
|
||||
}catch(Exception e){
|
||||
System.out.println("Could not generate signature");
|
||||
}
|
||||
|
||||
// Formatting expiration time
|
||||
Date expirationTime = new Date(blockData.getExpiration() * 1000);
|
||||
|
@ -239,10 +254,12 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
// Adding expiration
|
||||
obj.addProperty(KEY_EXPIRATION, dateFormat.format(expirationTime));
|
||||
|
||||
// Adding signatures
|
||||
JsonArray signatureArray = new JsonArray();
|
||||
signatureArray.add(Util.bytesToHex(signature));
|
||||
obj.add(KEY_SIGNATURES, signatureArray);
|
||||
if(signature != null){
|
||||
// Adding signature
|
||||
JsonArray signatureArray = new JsonArray();
|
||||
signatureArray.add(Util.bytesToHex(signature));
|
||||
obj.add(KEY_SIGNATURES, signatureArray);
|
||||
}
|
||||
|
||||
JsonArray operationsArray = new JsonArray();
|
||||
for(BaseOperation operation : operations){
|
||||
|
@ -259,7 +276,19 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
obj.addProperty(KEY_REF_BLOCK_PREFIX, blockData.getRefBlockPrefix());
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that will return a hash of this transaction's data. The hash covers only the transaction
|
||||
* attributes and not the signature or the chain id.
|
||||
*
|
||||
* @return A hash of the serialized transaction.
|
||||
*/
|
||||
public byte[] getHash(){
|
||||
byte[] txBytes = toBytes();
|
||||
byte[] toHash = Arrays.copyOfRange(txBytes, 32, txBytes.length); //Tx data only, without chain id
|
||||
Sha256Hash hash = Sha256Hash.wrap(Sha256Hash.hash(toHash));
|
||||
return Arrays.copyOfRange(hash.getBytes(), 0, 20); // The hash is only the first 20 bytes
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,7 +320,8 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
SimpleDateFormat dateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
Date expirationDate = dateFormat.parse(expiration, new ParsePosition(0));
|
||||
BlockData blockData = new BlockData(refBlockNum, refBlockPrefix, expirationDate.getTime());
|
||||
long relativeExpiration = expirationDate.getTime() / 1000;
|
||||
BlockData blockData = new BlockData(refBlockNum, refBlockPrefix, relativeExpiration);
|
||||
|
||||
// Parsing operation list
|
||||
BaseOperation operation = null;
|
||||
|
@ -387,6 +417,26 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.ASSET_CLAIM_FEES_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.FBA_DISTRIBUTE_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.BID_COLLATERAL_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.EXECUTE_BID_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.ASSET_CLAIM_POOL_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.ASSET_UPDATE_ISSUER_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.HTLC_CREATE_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.HTLC_REDEEM_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.HTLC_REDEEMED_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.HTLC_EXTEND_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
} else if (operationId == OperationType.HTLC_REFUND_OPERATION.ordinal()) {
|
||||
//TODO: Add operation deserialization support
|
||||
}
|
||||
if (operation != null) operationList.add(operation);
|
||||
operation = null;
|
||||
|
@ -401,4 +451,9 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
|||
return new Transaction(blockData, operationList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.toJsonString();
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
|
|||
public static final String KEY_OWNER_SPECIAL_AUTHORITY = "owner_special_authority";
|
||||
public static final String KEY_ACTIVE_SPECIAL_AUTHORITY = "active_special_authority";
|
||||
public static final String KEY_N_CONTROL_FLAGS = "top_n_control_flags";
|
||||
public static final String LIFETIME_EXPIRATION_DATE = "1969-12-31T23:59:59";
|
||||
|
||||
@Expose
|
||||
private String name;
|
||||
|
@ -84,6 +85,7 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
|
|||
@Expose
|
||||
private long referrerRewardsPercentage;
|
||||
|
||||
private boolean isLifeTime;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -248,6 +250,14 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
|
|||
this.statistics = statistics;
|
||||
}
|
||||
|
||||
public boolean isLifeTime() {
|
||||
return isLifeTime;
|
||||
}
|
||||
|
||||
public void setLifeTime(boolean lifeTime) {
|
||||
isLifeTime = lifeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializer used to build a UserAccount instance from the full JSON-formatted response obtained
|
||||
* by the 'get_objects' API call.
|
||||
|
@ -274,8 +284,10 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
|
|||
// Handling the deserialization and assignation of the membership date, which internally
|
||||
// is stored as a long POSIX time value
|
||||
try{
|
||||
Date date = dateFormat.parse(jsonAccount.get(KEY_MEMBERSHIP_EXPIRATION_DATE).getAsString());
|
||||
String expirationDate = jsonAccount.get(KEY_MEMBERSHIP_EXPIRATION_DATE).getAsString();
|
||||
Date date = dateFormat.parse(expirationDate);
|
||||
userAccount.setMembershipExpirationDate(date.getTime());
|
||||
userAccount.setLifeTime(expirationDate.equals(LIFETIME_EXPIRATION_DATE));
|
||||
} catch (ParseException e) {
|
||||
System.out.println("ParseException. Msg: "+e.getMessage());
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ import com.google.common.primitives.UnsignedLong;
|
|||
|
||||
import org.spongycastle.crypto.DataLengthException;
|
||||
import org.spongycastle.crypto.InvalidCipherTextException;
|
||||
import org.spongycastle.crypto.digests.GeneralDigest;
|
||||
import org.spongycastle.crypto.digests.RIPEMD160Digest;
|
||||
import org.spongycastle.crypto.digests.SHA1Digest;
|
||||
import org.spongycastle.crypto.digests.SHA256Digest;
|
||||
import org.spongycastle.crypto.engines.AESFastEngine;
|
||||
import org.spongycastle.crypto.modes.CBCBlockCipher;
|
||||
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
|
||||
|
@ -320,7 +324,9 @@ public class Util {
|
|||
}
|
||||
|
||||
byte[] temp = new byte[count];
|
||||
System.arraycopy(out, out.length - count, temp, 0, temp.length);
|
||||
int srcPos = out.length - count > 0 ? out.length - count : 0;
|
||||
int length = count < out.length ? count : out.length;
|
||||
System.arraycopy(out, srcPos, temp, 0, length);
|
||||
byte[] temp2 = new byte[count];
|
||||
Arrays.fill(temp2, (byte) count);
|
||||
if (Arrays.equals(temp, temp2)) {
|
||||
|
@ -383,4 +389,36 @@ public class Util {
|
|||
public static long toBase(double value, int precision){
|
||||
return (long) (value * Math.pow(10, precision));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hash for HTLC operations.
|
||||
*
|
||||
* @param preimage The data we want to operate on.
|
||||
* @param hashType The type of hash.
|
||||
* @return The hash.
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static byte[] htlcHash(byte[] preimage, HtlcHashType hashType) throws NoSuchAlgorithmException {
|
||||
byte[] out = null;
|
||||
GeneralDigest digest = null;
|
||||
switch(hashType){
|
||||
case RIPEMD160:
|
||||
digest = new RIPEMD160Digest();
|
||||
out = new byte[20];
|
||||
break;
|
||||
case SHA1:
|
||||
digest = new SHA1Digest();
|
||||
out = new byte[20];
|
||||
break;
|
||||
case SHA256:
|
||||
digest = new SHA256Digest();
|
||||
out = new byte[32];
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Not supported hash function!");
|
||||
}
|
||||
digest.update(preimage, 0, preimage.length);
|
||||
digest.doFinal(out, 0);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package cy.agorise.graphenej.api;
|
||||
|
||||
/**
|
||||
* Class used to list all currently supported API accesses
|
||||
*/
|
||||
|
||||
public class ApiAccess {
|
||||
public static final int API_NONE = 0x00;
|
||||
public static final int API_DATABASE = 0x01;
|
||||
public static final int API_HISTORY = 0x02;
|
||||
public static final int API_NETWORK_BROADCAST = 0x04;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package cy.agorise.graphenej.api;
|
||||
|
||||
/**
|
||||
* Class used to send connection status updates.
|
||||
*
|
||||
* Connection status updates can be any of the following:
|
||||
* - {@link ConnectionStatusUpdate#CONNECTED}
|
||||
* - {@link ConnectionStatusUpdate#AUTHENTICATED}
|
||||
* - {@link ConnectionStatusUpdate#API_UPDATE}
|
||||
* - {@link ConnectionStatusUpdate#DISCONNECTED}
|
||||
*
|
||||
* This is specified by the field calle |