Adding support for multiple operation-tx and applying the factory pattern to every specific operation

master
Nelson R. Perez 2017-03-01 23:26:40 -05:00
parent b51f21bbc5
commit 2bab1fab4f
19 changed files with 250 additions and 409 deletions

View File

@ -21,7 +21,13 @@ public class Main {
public static final String BILTHON_25_PASSWORD = System.getenv("BILTHON_25_PASSWORD");
public static final String BILTHON_11_BRAIN_KEY = System.getenv("BILTHON_11_BRAIN_KEY");
public static final String BILTHON_11_BRAIN_KEY = System.getenv("BILTHON_11_BRAINKEY");
public static final String BILTHON_15_BRAIN_KEY = System.getenv("BILTHON_15_BRAINKEY");
public static final String BILTHON_16_BRAIN_KEY = System.getenv("BILTHON_16_BRAINKEY");
public static final String GENERIC_PASSWORD = System.getenv("GENERIC_PASSWORD");
// Static block information used for transaction serialization tests
public static int REF_BLOCK_NUM = 56204;
@ -48,7 +54,7 @@ public class Main {
// test.testGetDynamicParams();
// test.testGetRequiredFeesSerialization();
// test.testRequiredFeesResponse();
// test.testTransactionBroadcastSequence();
test.testTransactionBroadcastSequence();
// test.testAccountLookupDeserialization();
// test.testPrivateKeyManipulations();
// test.testPublicKeyManipulations();
@ -65,7 +71,7 @@ public class Main {
// test.testAccountUpdateSerialization();
// test.testAccountUpdateOperationBroadcast();
// test.testCreateBinFile();
test.testImportBinFile();
// test.testImportBinFile();
// test.testExportBinFile();
// test.testLzmaCompression();
// test.testLzmaDecompression();

View File

@ -1,6 +1,7 @@
package de.bitsharesmunich.graphenej;
import com.google.common.primitives.Bytes;
import de.bitsharesmunich.graphenej.errors.MalformedOperationException;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.models.*;
import de.bitsharesmunich.graphenej.models.backup.LinkedAccount;
@ -16,6 +17,10 @@ import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.errors.MalformedAddressException;
import de.bitsharesmunich.graphenej.errors.MalformedTransactionException;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.operations.AccountUpdateOperation;
import de.bitsharesmunich.graphenej.operations.AccountUpdateOperationBuilder;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperationBuilder;
import de.bitsharesmunich.graphenej.test.NaiveSSLContext;
import com.neovisionaries.ws.client.*;
import de.bitsharesmunich.graphenej.api.*;
@ -43,8 +48,8 @@ public class Test {
public static final String AMAZON_WITNESS = "ws://54.91.97.99:8090";
public static final String WITNESS_URL = "api://api.devling.xyz:8088";
public static final String OPENLEDGER_WITNESS_URL = "wss://bitshares.openledger.info/api";
public static final String BLOCK_PAY_DE = "wss://de.blockpay.ch:8089";
public static final String BLOCK_PAY_FR = "wss://fr.blockpay.ch:8089";
public static final String BLOCK_PAY_DE = "wss://de.blockpay.ch/node";
public static final String BLOCK_PAY_FR = "wss://fr.blockpay.ch/node";
private Transaction transaction;
@ -220,31 +225,6 @@ public class Test {
System.out.println(Util.bytesToHex(account.toBytes()));
}
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")))
.setPrivateKey(DumpedPrivateKey.fromBase58(null, Main.WIF).getKey())
.setBlockData(new BlockData(Main.REF_BLOCK_NUM, Main.REF_BLOCK_PREFIX, Main.RELATIVE_EXPIRATION))
.build();
ArrayList<Serializable> transactionList = new ArrayList<>();
transactionList.add(transaction);
byte[] signature = transaction.getGrapheneSignature();
System.out.println(Util.bytesToHex(signature));
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");
@ -292,7 +272,6 @@ public class Test {
}
public void testTransactionBroadcastSequence() {
String url = Test.OPENLEDGER_WITNESS_URL;
WitnessResponseListener listener = new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
@ -307,26 +286,38 @@ public class Test {
};
try {
ECKey from = new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey();
PublicKey to = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPublicKey()));
ECKey sourcePrivateKey = new BrainKey(Main.BILTHON_15_BRAIN_KEY, 0).getPrivateKey();
PublicKey to1 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPublicKey()));
PublicKey to2 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_16_BRAIN_KEY, 0).getPublicKey()));
// Creating memo
long nonce = 1;
byte[] encryptedMessage = Memo.encryptMessage(from, to, nonce, "another message");
Memo memo = new Memo(new Address(ECKey.fromPublicOnly(from.getPubKey())), new Address(to.getKey()), nonce, encryptedMessage);
byte[] encryptedMessage = Memo.encryptMessage(sourcePrivateKey, to1, nonce, "another message");
Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), nonce, encryptedMessage);
// Creating transaction
Transaction transaction = new TransferTransactionBuilder()
.setSource(new UserAccount("1.2.138632")) // bilthon-83
// Creating operation 1
TransferOperation transferOperation1 = new TransferOperationBuilder()
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0")))
.setSource(new UserAccount("1.2.143563")) // bilthon-15
.setDestination(new UserAccount("1.2.139313")) // bilthon-5
.setAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0")))
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0")))
.setPrivateKey(new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey())
.setMemo(memo)
.build();
ArrayList<Serializable> transactionList = new ArrayList<>();
transactionList.add(transaction);
// Creating operation 2
TransferOperation transferOperation2 = new TransferOperationBuilder()
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0")))
.setSource(new UserAccount("1.2.143563")) // bilthon-15
.setDestination(new UserAccount("1.2.143569")) // bilthon-16
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0")))
.build();
// Adding operations to the operation list
ArrayList<BaseOperation> operationList = new ArrayList<>();
operationList.add(transferOperation1);
operationList.add(transferOperation2);
Transaction transaction = new Transaction(sourcePrivateKey, null, operationList);
SSLContext context = null;
context = NaiveSSLContext.getInstance("TLS");
@ -340,7 +331,7 @@ public class Test {
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, new Asset("1.3.0"), listener));
mWebSocket.connect();
} catch (MalformedTransactionException e) {
} catch (MalformedOperationException e) {
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
} catch (IOException e) {
System.out.println("IOException. Msg: " + e.getMessage());
@ -363,15 +354,17 @@ public class Test {
}
public void testPrivateKeyManipulations() {
String brainKeyWords = "PUMPER ISOTOME SERE STAINER CLINGER MOONLIT CHAETA UPBRIM AEDILIC BERTHER NIT SHAP SAID SHADING JUNCOUS CHOUGH";
String brainKeyWords = Main.BILTHON_15_BRAIN_KEY;
BrainKey brainKey = new BrainKey(brainKeyWords, 0);
ECKey privateKey = DumpedPrivateKey.fromBase58(null, brainKey.getWalletImportFormat()).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()));
Address address = new Address(ECKey.fromPublicOnly(privateKey.getPubKey()));
System.out.println("Raw private key..........: " + Util.bytesToHex(privateKey.getSecretBytes()));
System.out.println("WIF private key..........: " + brainKey.getWalletImportFormat());
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("Address..................: " + address.toString());
}
public void testPublicKeyManipulations() {
@ -637,9 +630,10 @@ public class Test {
}
public void testImportBinFile() {
String password = Main.GENERIC_PASSWORD;
try {
String current = new File(".").getCanonicalPath();
File file = new File(current + "/src/main/java/de/bitsharesmunich/graphenej/bts_bilthon-25_20170214.bin");
File file = new File(current + "/bts_vinicius_default_20170218_20170219.bin");
Path path = Paths.get(file.getAbsolutePath());
byte[] data = Files.readAllBytes(path);
byte[] publicKey = new byte[FileBin.PUBLIC_KEY_LENGTH];
@ -647,22 +641,27 @@ public class Test {
MessageDigest md = MessageDigest.getInstance("SHA-256");
ECKey randomECKey = ECKey.fromPublicOnly(publicKey);
byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(Main.BILTHON_25_PASSWORD.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded();
byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(password.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded();
System.out.println("final key : "+Util.bytesToHex(finalKey));
Address address = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(finalKey).getPubKey()));
System.out.println("address : "+address.toString());
WalletBackup walletBackup = FileBin.deserializeWalletBackup(data, Main.BILTHON_25_PASSWORD);
System.out.println("Number of wallets: "+walletBackup.getWalletCount());
String brainKeyString = walletBackup.getWallet(0).decryptBrainKey(Main.BILTHON_25_PASSWORD);
WalletBackup walletBackup = FileBin.deserializeWalletBackup(data, password);
String brainKeyString = walletBackup.getWallet(0).decryptBrainKey(password);
System.out.println("Brain key: "+brainKeyString);
BrainKey brainKey = new BrainKey(brainKeyString, 1);
byte[] privateKey = brainKey.getPrivateKey().getPrivKeyBytes();
System.out.println("Brainkey derived private....: " + Util.bytesToHex(privateKey));
byte[] brainKeyDerivedPrivateKey = brainKey.getPrivateKey().getPrivKeyBytes();
System.out.println("Brainkey derived private....: " + Util.bytesToHex(brainKeyDerivedPrivateKey));
byte[] privateKey2 = walletBackup.getPrivateKeyBackup(0).decryptPrivateKey(walletBackup.getWallet(0).getEncryptionKey(Main.BILTHON_25_PASSWORD));
System.out.println("Encrypted private key.......: "+Util.bytesToHex(privateKey2));
byte[] encryptionKey = walletBackup.getWallet(0).getEncryptionKey(password);
byte[] privateKey0 = walletBackup.getPrivateKeyBackup(0).decryptPrivateKey(encryptionKey);
byte[] privateKey1 = walletBackup.getPrivateKeyBackup(1).decryptPrivateKey(encryptionKey);
System.out.println("Encrypted private key 1.....: "+Util.bytesToHex(privateKey0));
System.out.println("Encrypted private key 2.....: "+Util.bytesToHex(privateKey1));
Address addr1 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey).getPubKey()));
Address addr2 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey2).getPubKey()));
Address addr3 = new Address(ECKey.fromPublicOnly(publicKey));
Address addr1 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(brainKeyDerivedPrivateKey).getPubKey()));
Address addr2 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey0).getPubKey()));
Address addr3 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey1).getPubKey()));
System.out.println("Addr1: "+addr1.toString());
System.out.println("Addr2: "+addr2.toString());
System.out.println("Addr3: "+addr3.toString());
@ -674,7 +673,7 @@ public class Test {
}
public void testExportBinFile(){
String password = "123456";
String password = Main.GENERIC_PASSWORD;
BrainKey brainKey = new BrainKey(Main.BILTHON_11_BRAIN_KEY, 0);
Wallet wallet = new Wallet("bilthon-11", brainKey.getBrainKey(), brainKey.getSequenceNumber(), Chains.BITSHARES.CHAIN_ID, password);
byte[] privateKey = brainKey.getPrivateKey().getPrivKeyBytes();
@ -692,7 +691,7 @@ public class Test {
System.out.println("Serialized: "+Util.bytesToHex(serialized));
try {
String current = new File(".").getCanonicalPath();
String fullPath = current + "/scwall_bithon_11.bin";
String fullPath = current + "/scwall_bilthon_11.bin";
System.out.println("Full path: "+fullPath);
File file = new File(fullPath);
FileOutputStream out = new FileOutputStream(file);
@ -787,21 +786,27 @@ public class Test {
Authority authority = new Authority(1, authMap, null);
AccountOptions options = new AccountOptions(address.getPublicKey());
BrainKey brainKey = new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0);
Transaction transaction = new AccountUpdateTransactionBuilder(brainKey.getPrivateKey())
.setAccont(new UserAccount("1.2.140994"))
// .setOwner(authority)
AccountUpdateOperation operation = new AccountUpdateOperationBuilder()
.setAccount(new UserAccount("1.2.140994"))
.setActive(authority)
.setOptions(options)
.setBlockData(new BlockData(Main.REF_BLOCK_NUM, Main.REF_BLOCK_PREFIX, Main.RELATIVE_EXPIRATION))
.build();
ArrayList<BaseOperation> opList = new ArrayList<>();
opList.add(operation);
BlockData blockData = new BlockData(Main.REF_BLOCK_NUM, Main.REF_BLOCK_PREFIX, Main.RELATIVE_EXPIRATION);
ECKey privateKey = brainKey.getPrivateKey();
Transaction transaction = new Transaction(privateKey, blockData, opList);
System.out.println("Json object");
System.out.println(transaction.toJsonString());
System.out.println("Serialized transaction");
System.out.println(Util.bytesToHex(transaction.toBytes()));
} catch (MalformedAddressException e) {
System.out.println("MalformedAddressException. Msg: " + e.getMessage());
} catch (MalformedTransactionException e) {
} catch (MalformedOperationException e) {
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
}
}

View File

@ -1,19 +0,0 @@
package de.bitsharesmunich.graphenej;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Created by nelson on 12/24/16.
*/
public class AssetTest {
@org.junit.Test
public void equals() throws Exception {
Asset bts = new Asset("1.3.0");
Asset bitUSD = new Asset("1.3.121");
assertNotEquals("Different assets should not be equal", bts, bitUSD);
}
}

View File

@ -1,61 +0,0 @@
package de.bitsharesmunich.graphenej;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.InputMismatchException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
/**
* Created by nelson on 12/16/16.
*/
public class AuthorityTest {
private Authority authority;
private Authority sameAuthority;
private Authority differentAuthority;
private Authority keyAuthority1;
private Authority keyAuthority2;
@Before
public void setUp() throws Exception {
authority = new Authority();
sameAuthority = new Authority();
HashMap<UserAccount, Integer> accountAuthorityMap = new HashMap<>();
UserAccount userAccount = new UserAccount("1.2.20000");
accountAuthorityMap.put(userAccount, 1);
differentAuthority = new Authority(1, null, accountAuthorityMap);
Address address1 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
Address address2 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
PublicKey publicKey = address1.getPublicKey();
PublicKey samePublicKey = address2.getPublicKey();
HashMap<PublicKey, Integer> keyMap1 = new HashMap<>();
HashMap<PublicKey, Integer> keyMap2 = new HashMap<>();
keyMap1.put(publicKey, 1);
keyMap2.put(samePublicKey, 1);
keyAuthority1 = new Authority(1, keyMap1, null);
keyAuthority2 = new Authority(1, keyMap2, null);
}
@org.junit.Test
public void toBytes() throws Exception {
}
@Test
public void equals() throws Exception {
assertEquals("Equal authorities", authority, sameAuthority);
assertEquals("Different authorities ", authority, differentAuthority);
assertEquals("Two public keys with the same public key should be equal", keyAuthority1, keyAuthority2);
}
@After
public void tearDown(){
}
}

View File

@ -1,33 +0,0 @@
package de.bitsharesmunich.graphenej;
import org.bitcoinj.core.*;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Created by nelson on 12/16/16.
*/
public class PublicKeyTest {
@Before
public void setUp() throws Exception {
}
@org.junit.Test
public void equals() throws Exception {
Address address1 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
Address address2 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
Address address3 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYp00");
PublicKey pk1 = address1.getPublicKey();
PublicKey pk2 = address2.getPublicKey();
PublicKey pk3 = address3.getPublicKey();
assertEquals("Public keys must be equal", pk1, pk2);
assertNotEquals("Public keys must not be equal", pk1, pk3);
}
@After
public void tearDown() throws Exception {
}
}

View File

@ -1,105 +0,0 @@
package de.bitsharesmunich.graphenej.objects;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import de.bitsharesmunich.graphenej.Address;
import de.bitsharesmunich.graphenej.Util;
import de.bitsharesmunich.graphenej.errors.ChecksumException;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.junit.*;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
/**
* Created by nelson on 12/19/16.
*/
public class MemoTest {
private ECKey sourcePrivate;
private Address sourceAddress;
private ECKey destinationPrivate;
private Address destinationAddress;
private long nonce;
private String shortMessage = "test";
private String longerMessage = "testing now longer string!!";
private byte[] shortEncryptedMessage = Util.hexToBytes("4c81c2db6ebc61e3f9e0ead65c0559dd");
private byte[] longerEncryptedMessage = Util.hexToBytes("1f8a08f1ff53dcefd48eeb052d26fba425f2a917f508ce61fc3d5696b10efa17");
private String decodedMessage;
@Before
public void setUp() throws Exception {
sourcePrivate = DumpedPrivateKey.fromBase58(null, "5J96pne45qWM1WpektoeazN6k9Mt93jQ7LyueRxFfEMTiy6yxjM").getKey();
destinationPrivate = DumpedPrivateKey.fromBase58(null, "5HuGQT8qwHScBgD4XsGbQUmXQF18MrbzxaQDiGGXFNRrCtqgT5Q").getKey();
sourceAddress = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
destinationAddress = new Address("BTS8ADjGaswhfFoxMGxqCdBtzhTBJsrGadCLoc9Ey5AGc8eoVZ5bV");
nonce = 5;
}
@Test
public void shouldMatchPredefinedChiphertext(){
byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage);
assertArrayEquals("Testing with short message and nonce 1", encrypted, shortEncryptedMessage);
byte[] encryptedLong = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, longerMessage);
assertArrayEquals("Testing with longer message and nonce 1", encryptedLong, longerEncryptedMessage);
}
@Test
public void shouldEncryptAndDecryptShortMessage(){
try {
byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, nonce, shortMessage);
String decrypted = decrypted = Memo.decryptMessage(destinationPrivate, sourceAddress, nonce, encrypted);
assertEquals("Decrypted message must be equal to original", decrypted, shortMessage);
} catch (ChecksumException e) {
e.printStackTrace();
}
}
@Test
public void shouldEncryptAndDecryptLongerMessage(){
try{
byte[] longEncrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, nonce, longerMessage);
String longDecrypted = Memo.decryptMessage(destinationPrivate, sourceAddress, nonce, longEncrypted);
assertEquals("The longer message must be equal to the original", longerMessage, longDecrypted);
} catch (ChecksumException e) {
e.printStackTrace();
}
}
@Test(expected = ChecksumException.class)
public void shouldThrowException() throws ChecksumException {
byte[] corrupted = Memo.encryptMessage(sourcePrivate, destinationAddress, nonce, longerMessage);
corrupted[0] = 0;
String longDecrypted = Memo.decryptMessage(destinationPrivate, sourceAddress, nonce, corrupted);
}
@Test
public void shouldBeJsonObjectSerializable(){
byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage);
Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted);
JsonElement jsonObject = memo.toJsonObject();
JsonObject reference = new JsonObject();
reference.addProperty("from", "BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
reference.addProperty("to", "BTS8ADjGaswhfFoxMGxqCdBtzhTBJsrGadCLoc9Ey5AGc8eoVZ5bV");
reference.addProperty("nonce", "1");
reference.addProperty("message", "4c81c2db6ebc61e3f9e0ead65c0559dd");
assertEquals("Memo instance should generate a valid JsonObject",jsonObject, reference);
}
@Test
public void shouldBeByteSerializable(){
String byteReference = "0103d1fb8c7421db64d46fba7e36f428854ca06eff65698b293f37c7ffaa54e2c2b203aece7c31616c02fcc96b50d3397c0e8d33d6384655d477c300d9196c728a5ee20100000000000000104c81c2db6ebc61e3f9e0ead65c0559dd";
byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage);
Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted);
byte[] memoBytes = memo.toBytes();
assertEquals("Memo instance should generate a valid byte array", byteReference, Util.bytesToHex(memoBytes));
}
}

View File

@ -1,6 +1,7 @@
package de.bitsharesmunich.graphenej;
import de.bitsharesmunich.graphenej.errors.MalformedTransactionException;
import de.bitsharesmunich.graphenej.operations.AccountUpdateOperation;
import org.bitcoinj.core.ECKey;
import java.util.ArrayList;

View File

@ -9,9 +9,11 @@ import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
public abstract class BaseOperation implements ByteSerializable, JsonSerializable {
protected OperationType type;
protected Extensions extensions;
public BaseOperation(OperationType type){
this.type = type;
this.extensions = new Extensions();
}
public byte getId() {

View File

@ -5,6 +5,7 @@ import com.google.gson.*;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
@ -37,7 +38,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
private ECKey privateKey;
private BlockData blockData;
private List<BaseOperation> operations;
private List<Extensions> extensions;
private Extensions extensions;
/**
* Transaction constructor.
@ -49,7 +50,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
this.privateKey = privateKey;
this.blockData = blockData;
this.operations = operationList;
this.extensions = new ArrayList<Extensions>();
this.extensions = new Extensions();
}
/**
@ -172,17 +173,8 @@ public class Transaction implements ByteSerializable, JsonSerializable {
byteArray.addAll(Bytes.asList(operation.toBytes()));
}
//Adding the number of extensions
byteArray.add((byte) this.extensions.size());
for(Extensions extensions : this.extensions){
//TODO: Implement the extensions serialization
}
// Adding a last zero byte to match the result obtained by the python-graphenelib code
// I'm not exactly sure what's the meaning of this last zero byte, but for now I'll just
// leave it here and work on signing the transaction.
//TODO: Investigate the origin and meaning of this last byte.
byteArray.add((byte) 0 );
// Adding extensions byte
byteArray.addAll(Bytes.asList(this.extensions.toBytes()));
return Bytes.toArray(byteArray);
}

View File

@ -1,101 +0,0 @@
package de.bitsharesmunich.graphenej;
import de.bitsharesmunich.graphenej.objects.Memo;
import de.bitsharesmunich.graphenej.errors.MalformedTransactionException;
import org.bitcoinj.core.ECKey;
import java.util.ArrayList;
import java.util.List;
/**
* Class used to build a transaction containing a transfer operation.
*/
public class TransferTransactionBuilder extends TransactionBuilder {
private List<BaseOperation> operations;
private UserAccount sourceAccount;
private UserAccount destinationAccount;
private AssetAmount transferAmount;
private AssetAmount feeAmount;
private Memo memo;
public TransferTransactionBuilder(){}
public TransferTransactionBuilder(ECKey privKey) {
super(privKey);
}
public TransferTransactionBuilder setPrivateKey(ECKey key){
this.privateKey = key;
return this;
}
public TransferTransactionBuilder setBlockData(BlockData blockData){
this.blockData = blockData;
return this;
}
public TransferTransactionBuilder setSource(UserAccount source){
this.sourceAccount = source;
return this;
}
public TransferTransactionBuilder setDestination(UserAccount destination){
this.destinationAccount = destination;
return this;
}
public TransferTransactionBuilder setAmount(AssetAmount amount){
this.transferAmount = amount;
return this;
}
public TransferTransactionBuilder setFee(AssetAmount amount){
this.feeAmount = amount;
return this;
}
public TransferTransactionBuilder setMemo(Memo memo){
this.memo = memo;
return this;
}
//TODO: Add support for multiple transfer operations in a single transaction
public TransferTransactionBuilder addOperation(TransferOperation transferOperation){
if(operations == null){
operations = new ArrayList<BaseOperation>();
}
return this;
}
@Override
public Transaction build() throws MalformedTransactionException {
if(privateKey == null){
throw new MalformedTransactionException("Missing private key information");
}else if(operations == null){
// If the operations list has not been set, we might be able to build one with the
// previously provided data. But in order for this to work we have to have all
// source, destination and transfer amount data.
operations = new ArrayList<>();
if(sourceAccount == null){
throw new MalformedTransactionException("Missing source account information");
}
if(destinationAccount == null){
throw new MalformedTransactionException("Missing destination account information");
}
if(transferAmount == null){
throw new MalformedTransactionException("Missing transfer amount information");
}
TransferOperation transferOperation;
if(feeAmount == null){
transferOperation = new TransferOperation(sourceAccount, destinationAccount, transferAmount);
}else{
transferOperation = new TransferOperation(sourceAccount, destinationAccount, transferAmount, feeAmount);
}
if(memo != null){
transferOperation.setMemo(this.memo);
}
operations.add(transferOperation);
}
return new Transaction(privateKey, blockData, operations);
}
}

View File

@ -5,7 +5,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.TransferOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;

View File

@ -10,11 +10,10 @@ import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.TransferOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.SubscriptionResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;

View File

@ -0,0 +1,11 @@
package de.bitsharesmunich.graphenej.errors;
/**
* Created by nelson on 3/1/17.
*/
public class MalformedOperationException extends RuntimeException {
public MalformedOperationException(String msg){
super(msg);
}
}

View File

@ -1,6 +1,6 @@
package de.bitsharesmunich.graphenej.models;
import de.bitsharesmunich.graphenej.TransferOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
/**

View File

@ -1,4 +1,4 @@
package de.bitsharesmunich.graphenej;
package de.bitsharesmunich.graphenej.operations;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedLong;
@ -6,6 +6,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import de.bitsharesmunich.graphenej.*;
/**
* Class used to encapsulate operations related to the ACCOUNT_UPDATE_OPERATION.

View File

@ -0,0 +1,59 @@
package de.bitsharesmunich.graphenej.operations;
import de.bitsharesmunich.graphenej.*;
import de.bitsharesmunich.graphenej.errors.MalformedOperationException;
/**
* Created by nelson on 3/1/17.
*/
public class AccountUpdateOperationBuilder extends BaseOperationBuilder {
private AssetAmount fee;
private UserAccount account;
private Authority owner;
private Authority active;
private AccountOptions new_options;
public AccountUpdateOperationBuilder setFee(AssetAmount fee) {
this.fee = fee;
return this;
}
public AccountUpdateOperationBuilder setAccount(UserAccount account) {
this.account = account;
return this;
}
public AccountUpdateOperationBuilder setOwner(Authority owner) {
this.owner = owner;
return this;
}
public AccountUpdateOperationBuilder setActive(Authority active) {
this.active = active;
return this;
}
public AccountUpdateOperationBuilder setOptions(AccountOptions newOptions) {
this.new_options = newOptions;
return this;
}
@Override
public AccountUpdateOperation build() {
AccountUpdateOperation operation;
if(this.account == null){
throw new MalformedOperationException("This operation requires an account to be set");
}else{
if(owner != null || active != null || new_options != null){
if(fee == null){
operation = new AccountUpdateOperation(account, owner, active, new_options);
}else{
operation = new AccountUpdateOperation(account, owner, active, new_options, fee);
}
}else{
throw new MalformedOperationException("This operation requires at least either an authority or account options change");
}
}
return operation;
}
}

View File

@ -0,0 +1,17 @@
package de.bitsharesmunich.graphenej.operations;
import de.bitsharesmunich.graphenej.BaseOperation;
/**
* Base template for all operation-specific factory classes.
*/
public abstract class BaseOperationBuilder {
/**
* Must be implemented and return the specific operation the
* factory is supposed to build.
*
* @return: A usable instance of a given operation.
*/
public abstract BaseOperation build();
}

View File

@ -1,5 +1,9 @@
package de.bitsharesmunich.graphenej;
package de.bitsharesmunich.graphenej.operations;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.BaseOperation;
import de.bitsharesmunich.graphenej.OperationType;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.objects.Memo;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
@ -22,7 +26,6 @@ public class TransferOperation extends BaseOperation {
private UserAccount from;
private UserAccount to;
private Memo memo;
private String[] extensions;
public TransferOperation(UserAccount from, UserAccount to, AssetAmount transferAmount, AssetAmount fee){
super(OperationType.TRANSFER_OPERATION);
@ -81,7 +84,8 @@ public class TransferOperation extends BaseOperation {
byte[] toBytes = to.toBytes();
byte[] amountBytes = amount.toBytes();
byte[] memoBytes = memo.toBytes();
return Bytes.concat(feeBytes, fromBytes, toBytes, amountBytes, memoBytes);
byte[] extensions = this.extensions.toBytes();
return Bytes.concat(feeBytes, fromBytes, toBytes, amountBytes, memoBytes, extensions);
}
@Override

View File

@ -0,0 +1,63 @@
package de.bitsharesmunich.graphenej.operations;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.errors.MalformedOperationException;
import de.bitsharesmunich.graphenej.objects.Memo;
/**
* Factory class used to build a transfer operation
*/
public class TransferOperationBuilder extends BaseOperationBuilder {
private UserAccount from;
private UserAccount to;
private AssetAmount transferAmount;
private AssetAmount fee;
private Memo memo;
public TransferOperationBuilder setSource(UserAccount from) {
this.from = from;
return this;
}
public TransferOperationBuilder setDestination(UserAccount to) {
this.to = to;
return this;
}
public TransferOperationBuilder setTransferAmount(AssetAmount transferAmount) {
this.transferAmount = transferAmount;
return this;
}
public TransferOperationBuilder setFee(AssetAmount fee) {
this.fee = fee;
return this;
}
public TransferOperationBuilder setMemo(Memo memo) {
this.memo = memo;
return this;
}
@Override
public TransferOperation build(){
TransferOperation transferOperation;
if(from == null ){
throw new MalformedOperationException("Missing source account information");
}else if(to == null){
throw new MalformedOperationException("Missing destination account information");
}else if(transferAmount == null){
throw new MalformedOperationException("Missing transfer amount information");
}
if(fee != null){
transferOperation = new TransferOperation(from, to, transferAmount, fee);
}else{
transferOperation = new TransferOperation(from, to, transferAmount);
}
if(memo != null){
transferOperation.setMemo(this.memo);
}
return transferOperation;
}
}