limit_order_create_operation-bearing tx is successfully being created and accepted by the network

master
Nelson R. Perez 2017-03-20 19:21:04 -05:00
parent 5ee4ef77f2
commit a9a550491b
6 changed files with 212 additions and 20 deletions

View File

@ -50,7 +50,7 @@ public class Main {
// e.printStackTrace();
// }
// test.testCustomSerializer();
test.testUserAccountSerialization();
// test.testUserAccountSerialization();
// test.testTransactionSerialization();
// test.testLoginSerialization();
// test.testNetworkBroadcastSerialization();
@ -89,7 +89,7 @@ public class Main {
// test.testGetObjects();
// test.testGetBlockHeader();
// test.testGetLimitOrders();
// test.testGetTradeHistory();
test.testGetTradeHistory();
// test.testAssetSerialization();
// test.testGetMarketHistory();
// test.testGetAccountBalances();

View File

@ -276,12 +276,14 @@ public class Test {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
System.out.println("Callback.Thread. name: "+Thread.currentThread().getName()+", id: "+Thread.currentThread().getId());
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
System.out.println(error.data.message);
System.out.println("Callback.Thread. name: "+Thread.currentThread().getName()+", id: "+Thread.currentThread().getId());
}
};
@ -330,7 +332,7 @@ public class Test {
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, new Asset("1.3.0"), listener));
mWebSocket.connect();
System.out.println("Main.Thread. name: "+Thread.currentThread().getName()+", id: "+Thread.currentThread().getId());
} catch (MalformedOperationException e) {
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
} catch (IOException e) {
@ -1189,7 +1191,7 @@ public class Test {
Calendar to = Calendar.getInstance();
to.roll(Calendar.DAY_OF_MONTH, false);
mWebSocket.addListener(new GetTradeHistory("BTS", "EUR", "20161215T0130000", "20161212T233000",100, new WitnessResponseListener() {
mWebSocket.addListener(new GetTradeHistory("BTS", "EUR", "20170309T0130000", "20161212T233000",100, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
List<MarketTrade> orders = (List<MarketTrade>) response.result;

View File

@ -133,7 +133,7 @@ public class TransactionBroadcastSequence extends WebSocketAdapter {
websocket.sendText(call.toJsonString());
}else if(baseResponse.id >= BROADCAST_TRANSACTION){
Type WitnessResponseType = new TypeToken<WitnessResponse<String>>(){}.getType();
WitnessResponse<WitnessResponse<String>> witnessResponse = gson.fromJson(response, WitnessResponseType);
WitnessResponse<String> witnessResponse = gson.fromJson(response, WitnessResponseType);
mListener.onSuccess(witnessResponse);
websocket.disconnect();
}

View File

@ -9,9 +9,19 @@ import de.bitsharesmunich.graphenej.*;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
* Operation used to denote the creation of a limit order on the blockchain.
*
* The blockchain will atempt to sell amount_to_sell.asset_id for as much min_to_receive.asset_id as possible.
* The fee will be paid by the seller's account. Market fees will apply as specified by the issuer of both the
* selling asset and the receiving asset as a percentage of the amount exchanged.
*
* If either the selling asset or the receiving asset is white list restricted, the order will only be created
* if the seller is on the white list of the restricted asset type.
*
* Market orders are matched in the order they are included in the block chain.
*/
public class LimitOrderCreateOperation extends BaseOperation {
// Number of bytes used for the expiration field.
@ -27,15 +37,22 @@ public class LimitOrderCreateOperation extends BaseOperation {
// Inner fields of a limit order
private AssetAmount fee;
private UserAccount seller;
private AssetAmount toSell;
private AssetAmount amountToSell;
private AssetAmount minToReceive;
private int expiration;
private boolean fillOrKill;
/**
* @param seller: Id of the seller
* @param toSell: Id of the asset to sell
* @param minToReceive: The minimum amount of the asset to receive
* @param expiration: Expiration in seconds
* @param fillOrKill: If this flag is set the entire order must be filled or the operation is rejected.
*/
public LimitOrderCreateOperation(UserAccount seller, AssetAmount toSell, AssetAmount minToReceive, int expiration, boolean fillOrKill){
super(OperationType.LIMIT_ORDER_CREATE_OPERATION);
this.seller = seller;
this.toSell = toSell;
this.amountToSell = toSell;
this.minToReceive = minToReceive;
this.expiration = expiration;
this.fillOrKill = fillOrKill;
@ -54,11 +71,14 @@ public class LimitOrderCreateOperation extends BaseOperation {
if(fee != null)
jsonObject.add(KEY_FEE, fee.toJsonObject());
jsonObject.addProperty(KEY_SELLER, seller.toJsonString());
jsonObject.add(KEY_AMOUNT_TO_SELL, toSell.toJsonObject());
jsonObject.add(KEY_AMOUNT_TO_SELL, amountToSell.toJsonObject());
jsonObject.add(KEY_MIN_TO_RECEIVE, minToReceive.toJsonObject());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
jsonObject.addProperty(KEY_EXPIRATION, simpleDateFormat.format(new Date(expiration)));
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
jsonObject.addProperty(KEY_EXPIRATION, simpleDateFormat.format(new Date(((long) expiration) * 1000)));
jsonObject.addProperty(KEY_FILL_OR_KILL, this.fillOrKill ? "true" : "false");
jsonObject.add(KEY_EXTENSIONS, new JsonArray());
array.add(jsonObject);
return array;
@ -73,7 +93,7 @@ public class LimitOrderCreateOperation extends BaseOperation {
public byte[] toBytes() {
byte[] feeBytes = this.fee.toBytes();
byte[] sellerBytes = this.seller.toBytes();
byte[] amountBytes = this.toSell.toBytes();
byte[] amountBytes = this.amountToSell.toBytes();
byte[] minAmountBytes = this.minToReceive.toBytes();
ByteBuffer buffer = ByteBuffer.allocate(EXPIRATION_BYTE_LENGTH);
@ -81,6 +101,8 @@ public class LimitOrderCreateOperation extends BaseOperation {
byte[] expirationBytes = Util.revertBytes(buffer.array());
byte[] fillOrKill = this.fillOrKill ? new byte[]{ 0x1 } : new byte[]{ 0x0 };
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill);
byte[] extensions = this.extensions.toBytes();
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill, extensions);
}
}

View File

@ -0,0 +1,168 @@
package de.bitsharesmunich.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 de.bitsharesmunich.graphenej.api.TransactionBroadcastSequence;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import de.bitsharesmunich.graphenej.objects.Memo;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperationTest;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperationBuilder;
import de.bitsharesmunich.graphenej.test.NaiveSSLContext;
import org.bitcoinj.core.ECKey;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by nelson on 3/6/17.
*/
public class TransactionTest {
private final String BILTHON_15_BRAIN_KEY = System.getenv("BILTHON_15_BRAINKEY");
private final String BILTHON_5_BRAIN_KEY = System.getenv("BILTHON_5_BRAINKEY");
private final String BILTHON_16_BRAIN_KEY = System.getenv("BILTHON_16_BRAINKEY");
private final String BLOCK_PAY_DE = System.getenv("BLOCKPAY_DE");
private final String BLOCK_PAY_FR = System.getenv("BLOCKPAY_FR");
// Transfer operation transaction
private final Asset CORE_ASSET = new Asset("1.3.0");
private final UserAccount bilthon_15 = new UserAccount("1.2.143563");
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_15;
private AssetAmount amountToSell = new AssetAmount(UnsignedLong.valueOf(100000), CORE_ASSET);
private AssetAmount minToReceive = new AssetAmount(UnsignedLong.valueOf(520), BIT_USD);
private long expiration;
WitnessResponseListener listener = new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
WitnessResponse<String> witnessResponse = response;
Assert.assertNull(witnessResponse.result);
synchronized (this){
notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
System.out.println(error.data.message);
Assert.assertNull(error);
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.
*/
private void broadcastTransaction(ECKey privateKey, List<BaseOperation> operationList, WitnessResponseListener responseListener) {
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(BLOCK_PAY_DE);
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, CORE_ASSET, listener));
mWebSocket.connect();
synchronized (responseListener){
responseListener.wait();
System.out.println("Wait released");
}
}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_15_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
long nonce = 1;
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_15)
.setDestination(bilthon_5) // bilthon-5
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), CORE_ASSET))
.build();
// Creating operation 2
TransferOperation transferOperation2 = new TransferOperationBuilder()
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), CORE_ASSET))
.setSource(bilthon_15) // bilthon-15
.setDestination(bilthon_16) // bilthon-16
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), CORE_ASSET))
.build();
// Adding operations to the operation list
ArrayList<BaseOperation> operationList = new ArrayList<>();
operationList.add(transferOperation1);
operationList.add(transferOperation2);
// Broadcasting transaction
broadcastTransaction(sourcePrivateKey, operationList, listener);
}
@Test
public void testLimitOrderCreateTransaction(){
ECKey privateKey = new BrainKey(BILTHON_15_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);
}
}

View File

@ -17,11 +17,11 @@ import static org.junit.Assert.*;
* Created by nelson on 3/6/17.
*/
public class LimitOrderCreateOperationTest {
private final int AMOUNT_TO_SELL = 25000000;
private final int MIN_TO_RECEIVE = 1;
private final Asset CORE_ASSET = new Asset("1.3.0");
private final Asset BIT_USD = new Asset("1.3.121");
private final int DEFAULT_EXPIRATION = 1488831620; // 2017-03-06T20:20:20
private static final int AMOUNT_TO_SELL = 25000000;
private static final int MIN_TO_RECEIVE = 1;
private static final Asset CORE_ASSET = new Asset("1.3.0");
private static final Asset BIT_USD = new Asset("1.3.121");
private static final int DEFAULT_EXPIRATION = 1488831620; // 2017-03-06T20:20:20
private UserAccount seller;
private AssetAmount amountToSell;
@ -43,14 +43,14 @@ public class LimitOrderCreateOperationTest {
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, expiration, true);
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
byte[] serialized = operation.toBytes();
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5801"));
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5800")));
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580100"));
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580000")));
// Testing serialization of operation with fillOrKill parameter == false
operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, expiration, false);
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
serialized = operation.toBytes();
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5800"));
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5801")));
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580000"));
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580100")));
}
}