Introducing the CreateHtlcOperation & supporting classes
- HtlcHashType class enumerates all supported HTLC hash functions. - The HtlcHash class is used to represent all possible HTLC hash results. - The CreateHtlcOperation class itself is used to represent the operation that creates an HTLC - A simple test class was introduced in order to test hash functions and subsequently also test the HTLC operation serialization
This commit is contained in:
parent
d953dae81b
commit
bf346f25bf
4 changed files with 221 additions and 0 deletions
24
graphenej/src/main/java/cy/agorise/graphenej/HtlcHash.java
Normal file
24
graphenej/src/main/java/cy/agorise/graphenej/HtlcHash.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package cy.agorise.graphenej;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
|
||||||
|
import cy.agorise.graphenej.interfaces.ByteSerializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to represent a HTLC hash.
|
||||||
|
*/
|
||||||
|
public class HtlcHash implements ByteSerializable {
|
||||||
|
private HtlcHashType hashType;
|
||||||
|
private byte[] hash;
|
||||||
|
|
||||||
|
public HtlcHash(HtlcHashType hashType, byte[] hash) {
|
||||||
|
this.hashType = hashType;
|
||||||
|
this.hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
byte[] hashTypeBytes = new byte[] { Util.revertInteger(hashType.ordinal())[3] };
|
||||||
|
return Bytes.concat(hashTypeBytes, hash);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package cy.agorise.graphenej;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to enumerate the possible hash algorithms used in HTLCs.
|
||||||
|
* @see <a href="https://github.com/bitshares/bitshares-core/blob/623aea265f2711adade982fc3248e6528dc8ac51/libraries/chain/include/graphene/chain/protocol/htlc.hpp">htlc.hpp</a>
|
||||||
|
*/
|
||||||
|
public enum HtlcHashType {
|
||||||
|
RIPEMD160,
|
||||||
|
SHA1,
|
||||||
|
SHA256
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
package cy.agorise.graphenej.operations;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
|
||||||
|
import cy.agorise.graphenej.AssetAmount;
|
||||||
|
import cy.agorise.graphenej.BaseOperation;
|
||||||
|
import cy.agorise.graphenej.HtlcHash;
|
||||||
|
import cy.agorise.graphenej.OperationType;
|
||||||
|
import cy.agorise.graphenej.UserAccount;
|
||||||
|
import cy.agorise.graphenej.Util;
|
||||||
|
|
||||||
|
public class CreateHtlcOperation extends BaseOperation {
|
||||||
|
private AssetAmount fee;
|
||||||
|
private UserAccount from;
|
||||||
|
private UserAccount to;
|
||||||
|
private AssetAmount amount;
|
||||||
|
private HtlcHash preimageHash;
|
||||||
|
private short preimageSize;
|
||||||
|
private int claimPeriodSeconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public constructor
|
||||||
|
*
|
||||||
|
* @param fee The operation fee.
|
||||||
|
* @param from The source account.
|
||||||
|
* @param to The destination account.
|
||||||
|
* @param amount The amount to be traded.
|
||||||
|
* @param hash The pre-image hash.
|
||||||
|
* @param preimageSize The pre-image size.
|
||||||
|
* @param claimPeriodSeconds The claim period, in seconds.
|
||||||
|
*/
|
||||||
|
public CreateHtlcOperation(AssetAmount fee, UserAccount from, UserAccount to, AssetAmount amount, HtlcHash hash, short preimageSize, int claimPeriodSeconds) {
|
||||||
|
super(OperationType.HTLC_CREATE_OPERATION);
|
||||||
|
this.fee = fee;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.amount = amount;
|
||||||
|
this.preimageHash = hash;
|
||||||
|
this.preimageSize = preimageSize;
|
||||||
|
this.claimPeriodSeconds = claimPeriodSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFee(AssetAmount newFee){
|
||||||
|
this.fee = newFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetAmount getFee() {
|
||||||
|
return fee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrom(UserAccount from) {
|
||||||
|
this.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTo(UserAccount to) {
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetAmount getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(AssetAmount amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HtlcHash getPreimageHash() {
|
||||||
|
return preimageHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreimageHash(HtlcHash preimageHash) {
|
||||||
|
this.preimageHash = preimageHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getPreimageSize() {
|
||||||
|
return preimageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreimageSize(short preimageSize) {
|
||||||
|
this.preimageSize = preimageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClaimPeriodSeconds() {
|
||||||
|
return claimPeriodSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClaimPeriodSeconds(int claimPeriodSeconds) {
|
||||||
|
this.claimPeriodSeconds = claimPeriodSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
byte[] feeBytes = fee.toBytes();
|
||||||
|
byte[] fromBytes = from.toBytes();
|
||||||
|
byte[] toBytes = to.toBytes();
|
||||||
|
byte[] amountBytes = amount.toBytes();
|
||||||
|
byte[] htlcHashBytes = preimageHash.toBytes();
|
||||||
|
byte[] preimageSizeBytes = Util.revertShort(preimageSize);
|
||||||
|
byte[] claimPeriodBytes = Util.revertInteger(claimPeriodSeconds);
|
||||||
|
byte[] extensionsBytes = extensions.toBytes();
|
||||||
|
return Bytes.concat(feeBytes, fromBytes, toBytes, amountBytes, htlcHashBytes, preimageSizeBytes, claimPeriodBytes, extensionsBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJsonString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package cy.agorise.graphenej.operations;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import cy.agorise.graphenej.Asset;
|
||||||
|
import cy.agorise.graphenej.AssetAmount;
|
||||||
|
import cy.agorise.graphenej.HtlcHash;
|
||||||
|
import cy.agorise.graphenej.HtlcHashType;
|
||||||
|
import cy.agorise.graphenej.UserAccount;
|
||||||
|
import cy.agorise.graphenej.Util;
|
||||||
|
|
||||||
|
public class CreateHtlcOperationTest {
|
||||||
|
private final String SERIALIZED_OP = "f68585abf4dce7c8045701310000000000000000007b7c80241100000000000000a06e327ea7388c18e4740e350ed4e60f2e04fc41c80078000000000001";
|
||||||
|
private final String PREIMAGE_HEX = "666f6f626172";
|
||||||
|
private final String HASH_RIPEMD160 = "a06e327ea7388c18e4740e350ed4e60f2e04fc41";
|
||||||
|
private final String HASH_SHA1 = "8843d7f92416211de9ebb963ff4ce28125932878";
|
||||||
|
private final String HASH_SHA256 = "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2";
|
||||||
|
|
||||||
|
private final Asset CORE = new Asset("1.3.0");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRipemd160(){
|
||||||
|
try {
|
||||||
|
byte[] hashRipemd160 = Util.htlcHash(Util.hexToBytes(PREIMAGE_HEX), HtlcHashType.RIPEMD160);
|
||||||
|
String hexHash = Util.bytesToHex(hashRipemd160);
|
||||||
|
Assert.assertEquals(HASH_RIPEMD160, hexHash);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSha1(){
|
||||||
|
try {
|
||||||
|
byte[] hashSha1 = Util.htlcHash(Util.hexToBytes(PREIMAGE_HEX), HtlcHashType.SHA1);
|
||||||
|
String hexHash = Util.bytesToHex(hashSha1);
|
||||||
|
Assert.assertEquals(HASH_SHA1, hexHash);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSha256(){
|
||||||
|
try {
|
||||||
|
byte[] hashSha256 = Util.htlcHash(Util.hexToBytes(PREIMAGE_HEX), HtlcHashType.SHA256);
|
||||||
|
String hexHash = Util.bytesToHex(hashSha256);
|
||||||
|
Assert.assertEquals(HASH_SHA256, hexHash);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Implement operation test
|
||||||
|
public void testOperationSerialization() throws NoSuchAlgorithmException {
|
||||||
|
UserAccount from = new UserAccount("1.2.123");
|
||||||
|
UserAccount to = new UserAccount("1.2.124");
|
||||||
|
AssetAmount fee = new AssetAmount(UnsignedLong.valueOf(0), CORE);
|
||||||
|
AssetAmount amount = new AssetAmount(UnsignedLong.valueOf(1123456), CORE);
|
||||||
|
byte[] hashBytes = Util.htlcHash("foobar".getBytes(), HtlcHashType.RIPEMD160);
|
||||||
|
HtlcHash preimageHash = new HtlcHash(HtlcHashType.RIPEMD160, hashBytes);
|
||||||
|
CreateHtlcOperation operation = new CreateHtlcOperation(fee, from, to, amount, preimageHash, (short) 200, 120);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue