367 lines
16 KiB
Java
367 lines
16 KiB
Java
package cy.agorise.graphenej;
|
|
|
|
import com.google.common.primitives.UnsignedLong;
|
|
import com.neovisionaries.ws.client.WebSocket;
|
|
import com.neovisionaries.ws.client.WebSocketException;
|
|
import com.neovisionaries.ws.client.WebSocketFactory;
|
|
|
|
import org.bitcoinj.core.ECKey;
|
|
import org.junit.Assert;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
|
|
import java.io.IOException;
|
|
import java.math.BigInteger;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.SecureRandom;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
import javax.net.ssl.SSLContext;
|
|
|
|
import cy.agorise.graphenej.api.GetLimitOrders;
|
|
import cy.agorise.graphenej.api.TransactionBroadcastSequence;
|
|
import cy.agorise.graphenej.interfaces.WitnessResponseListener;
|
|
import cy.agorise.graphenej.models.BaseResponse;
|
|
import cy.agorise.graphenej.models.WitnessResponse;
|
|
import cy.agorise.graphenej.operations.CustomOperation;
|
|
import cy.agorise.graphenej.operations.LimitOrderCancelOperation;
|
|
import cy.agorise.graphenej.operations.LimitOrderCreateOperation;
|
|
import cy.agorise.graphenej.operations.TransferOperation;
|
|
import cy.agorise.graphenej.operations.TransferOperationBuilder;
|
|
import cy.agorise.graphenej.test.NaiveSSLContext;
|
|
|
|
/**
|
|
* Created by nelson on 3/6/17.
|
|
*/
|
|
public class TransactionTest {
|
|
private final String BILTHON_7_BRAIN_KEY = TestAccounts.Bilthon7.BRAINKEY;
|
|
private final String BILTHON_5_BRAIN_KEY = TestAccounts.Bilthon5.BRAINKEY;
|
|
private final String BILTHON_16_BRAIN_KEY = TestAccounts.Bilthon16.BRAINKEY;
|
|
|
|
private final String NODE_URL = "wss://eu.openledger.info/ws";
|
|
|
|
// Transfer operation transaction
|
|
private final Asset CORE_ASSET = new Asset("1.3.0");
|
|
private final UserAccount bilthon_7 = new UserAccount("1.2.140994");
|
|
private final UserAccount bilthon_5 = new UserAccount("1.2.139313");
|
|
private final UserAccount bilthon_16 = new UserAccount("1.2.143569");
|
|
|
|
// Limit order create transaction
|
|
private final Asset BIT_USD = new Asset("1.3.121");
|
|
private UserAccount seller = bilthon_7;
|
|
private AssetAmount amountToSell = new AssetAmount(UnsignedLong.valueOf(100000), CORE_ASSET);
|
|
private AssetAmount minToReceive = new AssetAmount(UnsignedLong.valueOf(520), BIT_USD);
|
|
private long expiration;
|
|
|
|
// Custom operation transaction
|
|
private final AssetAmount fee = new AssetAmount(UnsignedLong.valueOf(100000), CORE_ASSET);
|
|
private final UserAccount payer = bilthon_7;
|
|
private final Integer operationId = 61166;
|
|
private final List<UserAccount> requiredAuths = Collections.singletonList(payer);
|
|
private final String data = "some data";
|
|
|
|
private final long FEE_AMOUNT = 21851;
|
|
|
|
// Lock object
|
|
private static final class Lock { }
|
|
private final Object lockObject = new Lock();
|
|
|
|
// Response
|
|
private BaseResponse baseResponse;
|
|
|
|
/**
|
|
* Generic witness response listener that will just release the lock created in
|
|
* main thread.
|
|
*/
|
|
WitnessResponseListener listener = new WitnessResponseListener() {
|
|
|
|
@Override
|
|
public void onSuccess(WitnessResponse response) {
|
|
System.out.println("onSuccess");
|
|
baseResponse = response;
|
|
synchronized (this){
|
|
this.notifyAll();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onError(BaseResponse.Error error) {
|
|
System.out.println("onError. Msg: "+error.data.message);
|
|
synchronized (this){
|
|
notifyAll();
|
|
}
|
|
}
|
|
};
|
|
|
|
@Before
|
|
public void setup(){
|
|
}
|
|
|
|
/**
|
|
* Receives the elements required for building a transaction, puts them together and broadcasts it.
|
|
* @param privateKey: The private key used to sign the transaction.
|
|
* @param operationList: The list of operations to include
|
|
* @param responseListener: The response listener.
|
|
* @param lockObject: Optional object to use as a lock
|
|
*/
|
|
private void broadcastTransaction(ECKey privateKey, List<BaseOperation> operationList, WitnessResponseListener responseListener, Object lockObject) {
|
|
try{
|
|
Transaction transaction = new Transaction(privateKey, null, operationList);
|
|
|
|
SSLContext context = null;
|
|
context = NaiveSSLContext.getInstance("TLS");
|
|
WebSocketFactory factory = new WebSocketFactory();
|
|
|
|
// Set the custom SSL context.
|
|
factory.setSSLContext(context);
|
|
|
|
WebSocket mWebSocket = factory.createSocket(NODE_URL);
|
|
|
|
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, CORE_ASSET, responseListener));
|
|
mWebSocket.connect();
|
|
|
|
// If a lock object is specified, we use it
|
|
if(lockObject != null){
|
|
synchronized (lockObject){
|
|
lockObject.wait();
|
|
}
|
|
}else{
|
|
// Otherwise we just use this listener as the lock
|
|
synchronized (responseListener){
|
|
responseListener.wait();
|
|
}
|
|
}
|
|
Assert.assertNotNull(baseResponse);
|
|
Assert.assertNull(baseResponse.error);
|
|
}catch(NoSuchAlgorithmException e){
|
|
System.out.println("NoSuchAlgoritmException. Msg: " + e.getMessage());
|
|
} catch (InterruptedException e) {
|
|
System.out.println("InterruptedException. Msg: "+e.getMessage());
|
|
} catch (IOException e) {
|
|
System.out.println("IOException. Msg: " + e.getMessage());
|
|
} catch (WebSocketException e) {
|
|
System.out.println("WebSocketException. Msg: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testTransferTransaction(){
|
|
ECKey sourcePrivateKey = new BrainKey(BILTHON_7_BRAIN_KEY, 0).getPrivateKey();
|
|
PublicKey to1 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(BILTHON_5_BRAIN_KEY, 0).getPublicKey()));
|
|
PublicKey to2 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(BILTHON_16_BRAIN_KEY, 0).getPublicKey()));
|
|
|
|
// Creating memo
|
|
SecureRandom random = new SecureRandom();
|
|
BigInteger nonce = BigInteger.valueOf(random.nextLong());
|
|
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 operation 1
|
|
TransferOperation transferOperation1 = new TransferOperationBuilder()
|
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), CORE_ASSET))
|
|
.setSource(bilthon_7)
|
|
.setDestination(bilthon_5) // bilthon-5
|
|
.setFee(new AssetAmount(UnsignedLong.valueOf(FEE_AMOUNT), CORE_ASSET))
|
|
.setMemo(memo)
|
|
.build();
|
|
|
|
// Creating operation 2
|
|
TransferOperation transferOperation2 = new TransferOperationBuilder()
|
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), CORE_ASSET))
|
|
.setSource(bilthon_7) // bilthon-15
|
|
.setDestination(bilthon_16) // bilthon-16
|
|
.setFee(new AssetAmount(UnsignedLong.valueOf(FEE_AMOUNT), CORE_ASSET))
|
|
.setMemo(memo)
|
|
.build();
|
|
|
|
|
|
// Adding operations to the operation list
|
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
|
operationList.add(transferOperation1);
|
|
operationList.add(transferOperation2);
|
|
|
|
// Broadcasting transaction
|
|
broadcastTransaction(sourcePrivateKey, operationList, listener, null);
|
|
}
|
|
|
|
@Test
|
|
public void testLimitOrderCreateTransaction(){
|
|
ECKey privateKey = new BrainKey(BILTHON_7_BRAIN_KEY, 0).getPrivateKey();
|
|
expiration = (System.currentTimeMillis() / 1000) + 60 * 60;
|
|
|
|
// Creating limit order creation operation
|
|
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, (int) expiration, false);
|
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
|
|
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
|
operationList.add(operation);
|
|
|
|
// Broadcasting transaction
|
|
broadcastTransaction(privateKey, operationList, listener, null);
|
|
}
|
|
|
|
/**
|
|
* Since tests should be independent of each other, in order to be able to test the cancellation of an
|
|
* existing order we must first proceed to create one. And after creating one, we must also retrieve
|
|
* its id in a separate call.
|
|
*
|
|
* All of this just makes this test a bit more complex, since we have 3 clearly defined tasks that require
|
|
* network communication
|
|
*
|
|
* 1- Create order
|
|
* 2- Retrieve order id
|
|
* 3- Send order cancellation tx
|
|
*
|
|
* Only the last one is what we actually want to test
|
|
*
|
|
* @throws NoSuchAlgorithmException
|
|
* @throws IOException
|
|
* @throws WebSocketException
|
|
*/
|
|
@Test
|
|
public void testLimitOrderCancelTransaction() throws NoSuchAlgorithmException, IOException, WebSocketException {
|
|
|
|
// We first must create a limit order for this test
|
|
ECKey privateKey = new BrainKey(BILTHON_7_BRAIN_KEY, 0).getPrivateKey();
|
|
expiration = (System.currentTimeMillis() / 1000) + 60 * 5;
|
|
|
|
// Creating limit order creation operation
|
|
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, (int) expiration, false);
|
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
|
|
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
|
operationList.add(operation);
|
|
|
|
// Broadcasting transaction (Task 1)
|
|
broadcastTransaction(privateKey, operationList, new WitnessResponseListener() {
|
|
|
|
@Override
|
|
public void onSuccess(WitnessResponse response) {
|
|
|
|
System.out.println("onSuccess.0");
|
|
try{
|
|
// Setting up the assets
|
|
Asset base = amountToSell.getAsset();
|
|
Asset quote = minToReceive.getAsset();
|
|
|
|
SSLContext context = NaiveSSLContext.getInstance("TLS");
|
|
WebSocketFactory factory = new WebSocketFactory();
|
|
|
|
// Set the custom SSL context.
|
|
factory.setSSLContext(context);
|
|
WebSocket mWebSocket = factory.createSocket(NODE_URL);
|
|
|
|
// Requesting limit order to cancel (Task 2)
|
|
mWebSocket.addListener(new GetLimitOrders(base.getObjectId(), quote.getObjectId(), 100, new WitnessResponseListener() {
|
|
|
|
@Override
|
|
public void onSuccess(WitnessResponse response) {
|
|
System.out.println("onSuccess.1");
|
|
List<LimitOrder> orders = (List<LimitOrder>) response.result;
|
|
for(LimitOrder order : orders){
|
|
if(order.getSeller().getObjectId().equals(bilthon_7.getObjectId())){
|
|
|
|
// Instantiating a private key for bilthon-15
|
|
ECKey privateKey = new BrainKey(BILTHON_7_BRAIN_KEY, 0).getPrivateKey();
|
|
|
|
// Creating limit order cancellation operation
|
|
LimitOrderCancelOperation operation = new LimitOrderCancelOperation(order, bilthon_7);
|
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
|
operationList.add(operation);
|
|
|
|
// Broadcasting order cancellation tx (Task 3)
|
|
broadcastTransaction(privateKey, operationList, new WitnessResponseListener() {
|
|
|
|
@Override
|
|
public void onSuccess(WitnessResponse response) {
|
|
System.out.println("onSuccess.2");
|
|
baseResponse = response;
|
|
synchronized (this){
|
|
notifyAll();
|
|
}
|
|
synchronized (lockObject){
|
|
lockObject.notifyAll();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onError(BaseResponse.Error error) {
|
|
System.out.println("onError.2");
|
|
synchronized (this){
|
|
notifyAll();
|
|
}
|
|
synchronized (lockObject){
|
|
lockObject.notifyAll();
|
|
}
|
|
}
|
|
}, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onError(BaseResponse.Error error) {
|
|
System.out.println("onError.1");
|
|
System.out.println(error.data.message);
|
|
Assert.assertNull(error);
|
|
synchronized (lockObject){
|
|
lockObject.notifyAll();
|
|
}
|
|
}
|
|
}));
|
|
|
|
mWebSocket.connect();
|
|
|
|
}catch(NoSuchAlgorithmException e){
|
|
System.out.println("NoSuchAlgorithmException. Msg: "+e.getMessage());
|
|
} catch (WebSocketException e) {
|
|
System.out.println("WebSocketException. Msg: "+e.getMessage());
|
|
} catch (IOException e) {
|
|
System.out.println("IOException. Msg: "+e.getMessage());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onError(BaseResponse.Error error) {
|
|
System.out.println("OnError. Msg: "+error.message);
|
|
synchronized (this){
|
|
notifyAll();
|
|
}
|
|
}
|
|
}, lockObject);
|
|
}
|
|
|
|
@Test
|
|
public void testCustomOperationTransaction(){
|
|
ECKey sourcePrivateKey = new BrainKey(BILTHON_7_BRAIN_KEY, 0).getPrivateKey();
|
|
|
|
// Creating custom operation
|
|
CustomOperation customOperation = new CustomOperation(fee, payer, operationId, requiredAuths, data);
|
|
|
|
// Adding operation to the operation list
|
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
|
operationList.add(customOperation);
|
|
|
|
// Broadcasting transaction
|
|
broadcastTransaction(sourcePrivateKey, operationList, listener, null);
|
|
}
|
|
|
|
@Test
|
|
public void testTransactionHash(){
|
|
ArrayList<BaseOperation> operations = new ArrayList<>();
|
|
TransferOperation transferOperation = new TransferOperationBuilder()
|
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf("363"), new Asset("1.3.0")))
|
|
.setFee(new AssetAmount(UnsignedLong.valueOf("10420"), new Asset("1.3.0")))
|
|
.setSource(new UserAccount("1.2.1029856"))
|
|
.setDestination(new UserAccount("1.2.390320"))
|
|
.build();
|
|
BlockData blockData = new BlockData(50885, 2948192884L, 1543548351);
|
|
operations.add(transferOperation);
|
|
Transaction transaction = new Transaction(blockData, operations);
|
|
byte[] testHash = transaction.getHash();
|
|
// Making sure the generated hash matches the one we expect from the block explorer
|
|
Assert.assertArrayEquals(Util.hexToBytes("4fec588ccdd04daaf80666a3646a48b5189df041"), testHash);
|
|
}
|
|
} |