Adding support for multiple operation-tx and applying the factory pattern to every specific operation
This commit is contained in:
parent
b51f21bbc5
commit
2bab1fab4f
19 changed files with 250 additions and 409 deletions
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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(){
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package de.bitsharesmunich.graphenej.models;
|
||||
|
||||
import de.bitsharesmunich.graphenej.TransferOperation;
|
||||
import de.bitsharesmunich.graphenej.operations.TransferOperation;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue