From b2bbce8c44ddf12967512b5e4d41e0afec4fe3a6 Mon Sep 17 00:00:00 2001 From: i-mills Date: Tue, 21 Jun 2022 13:03:21 +0100 Subject: [PATCH 1/6] issues/99 - In progress, correcting invalid CLMap byte conversion code --- .../types/AbstractByteSerializer.java | 16 ++- .../com/casper/sdk/how_to/HowToUseMaps.java | 114 ++++++++++++++++++ .../types/CLValueByteSerializerTest.java | 14 ++- 3 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/casper/sdk/how_to/HowToUseMaps.java diff --git a/src/main/java/com/casper/sdk/service/serialization/types/AbstractByteSerializer.java b/src/main/java/com/casper/sdk/service/serialization/types/AbstractByteSerializer.java index 04a33a7d1..96ba033f9 100644 --- a/src/main/java/com/casper/sdk/service/serialization/types/AbstractByteSerializer.java +++ b/src/main/java/com/casper/sdk/service/serialization/types/AbstractByteSerializer.java @@ -3,10 +3,7 @@ import com.casper.sdk.service.serialization.cltypes.TypesFactory; import com.casper.sdk.service.serialization.cltypes.TypesSerializer; import com.casper.sdk.service.serialization.util.ByteArrayBuilder; -import com.casper.sdk.types.CLByteArrayInfo; -import com.casper.sdk.types.CLOptionTypeInfo; -import com.casper.sdk.types.CLType; -import com.casper.sdk.types.CLTypeInfo; +import com.casper.sdk.types.*; abstract class AbstractByteSerializer implements ByteSerializer { @@ -40,11 +37,22 @@ byte[] toBytesForCLTypeInfo(final CLTypeInfo typeInfo) { case OPTION: return getOptionType(typeInfo); + case MAP: + return getMapType((CLMapTypeInfo) typeInfo); + default: throw new IllegalArgumentException("Wrong type " + typeInfo.getType()); } } + private byte[] getMapType(final CLMapTypeInfo typeInfo) { + return new ByteArrayBuilder() + .append(getTypeBytes(typeInfo)) + .append(getTypeBytes(typeInfo.getKeyType())) + .append(getTypeBytes(typeInfo.getValueType())) + .toByteArray(); + } + public TypesSerializer getU32Serializer() { return u32Serializer; } diff --git a/src/test/java/com/casper/sdk/how_to/HowToUseMaps.java b/src/test/java/com/casper/sdk/how_to/HowToUseMaps.java new file mode 100644 index 000000000..46dbf6b16 --- /dev/null +++ b/src/test/java/com/casper/sdk/how_to/HowToUseMaps.java @@ -0,0 +1,114 @@ +package com.casper.sdk.how_to; + +import com.casper.sdk.CasperSdk; +import com.casper.sdk.KeyPairStreams; +import com.casper.sdk.service.serialization.cltypes.CLValueBuilder; +import com.casper.sdk.service.serialization.util.CollectionUtils; +import com.casper.sdk.types.*; +import org.junit.jupiter.api.Test; + +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.time.Instant; +import java.util.Map; + +import static com.casper.sdk.how_to.HowToUtils.getFaucetKeyPair; +import static com.casper.sdk.how_to.HowToUtils.getWasmIn; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; + +public class HowToUseMaps { + + /** Create new instance of the SDK with default NCTL url and port */ + final CasperSdk casperSdk = new CasperSdk("http://localhost", 11101); + + + @Test + void clMapUsage() throws Exception { + + final KeyPairStreams faucetKeyPair = getFaucetKeyPair(); + final KeyPair operatorKeyPair = casperSdk.loadKeyPair(faucetKeyPair.getPublicKeyIn(), faucetKeyPair.getPrivateKeyIn()); + + + final Digest contractHash = installContract(); + + assertThat(contractHash, is(notNullValue())); + + /* CLValue key1 = CLValueBuilder.byteArray(contractHash); + CLValue value1 = CLValueBuilder.u256(50000); + + CLMap clMap = new CLMap((String) null, new CLMapTypeInfo(key1.getCLTypeInfo(), value1.getCLTypeInfo()), null); + clMap.put(key1, value1); +*/ + final Map clMap = CollectionUtils.Map.of(CLValueBuilder.byteArray(contractHash), CLValueBuilder.u256(50000)); + + final Deploy deploy = casperSdk.makeDeploy( + new DeployParams( + // platformKeyPair.getPublic(), + operatorKeyPair.getPublic(), + "integration-test", + 1, + Instant.now().toEpochMilli(), + DeployParams.DEFAULT_TTL, + null), + new StoredContractByHash( + new ContractHash(contractHash.getHash()), + "set_state", + new DeployNamedArgBuilder() + .add("token_id", CLValueBuilder.string("A-TOKEN-ID")) + .add("instrument_id", CLValueBuilder.string("A-CONTRACT-ID")) + .add("asset_decimals", CLValueBuilder.u256(10)) + .add("asset_units", CLValueBuilder.u256(50000)) + .add("asset_holders", CLValueBuilder.map(clMap)) + .add("liability_decimals", CLValueBuilder.u256(10)) + .add("liability_units", CLValueBuilder.u256(40000)) + .add("liability_holders", CLValueBuilder.map(clMap)) + .build()), + casperSdk.standardPayment(new BigInteger("10000000000")) + ); + } + + + public Digest installContract() throws FileNotFoundException { + + final InputStream erc20wasmIn = getWasmIn("/com/casper/sdk/how_to/erc20.wasm"); + final String chainName = "casper-net-1"; + final Number payment = 50e9; + final int tokenDecimals = 11; + final String tokenName = "Acme Token"; + final Number tokenTotalSupply = 1e15; + final String tokenSymbol = "ACME"; + + // Get contract operator. + final KeyPairStreams faucetKeyPair = getFaucetKeyPair(); + final KeyPair operatorKeyPair = casperSdk.loadKeyPair(faucetKeyPair.getPublicKeyIn(), faucetKeyPair.getPrivateKeyIn()); + + // Set deploy. + final Deploy deploy = casperSdk.makeInstallContract( + new DeployParams( + operatorKeyPair.getPublic(), + chainName, + null, + null, + null, + null + ), + payment, + erc20wasmIn, + tokenDecimals, + tokenName, + tokenSymbol, + tokenTotalSupply + ); + + // Approve deploy. + casperSdk.signDeploy(deploy, operatorKeyPair); + + // Dispatch deploy to a node. + return casperSdk.putDeploy(deploy); + + } +} diff --git a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java index 9c34f3b42..679b60863 100644 --- a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java +++ b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java @@ -2,10 +2,10 @@ import com.casper.sdk.service.serialization.cltypes.CLValueBuilder; import com.casper.sdk.service.serialization.cltypes.TypesFactory; +import com.casper.sdk.service.serialization.util.CollectionUtils; import com.casper.sdk.types.*; import org.junit.jupiter.api.Test; -import java.util.LinkedHashMap; import java.util.Map; import static com.casper.sdk.service.serialization.util.ByteUtils.concat; @@ -118,4 +118,16 @@ void keyValueToBytes() { assertThat(byteSerializer.toBytes(clKeyValue), is(expected)); } + + + @Test + void clMapTypeBytesTest() { + + final Digest contractHash = new Digest("8c7b947748f9715c3f24d83fbe60ab03b9602976ebcfe29535143c3dc19eca01"); + final Map clMap = CollectionUtils.Map.of(CLValueBuilder.byteArray(contractHash), CLValueBuilder.u256(50000)); + + byte[] bytes = byteSerializer.toBytes(CLValueBuilder.map(clMap)); + + assertThat(bytes[0], is(CLType.MAP.getClType())); + } } From d964f871430a4bfdfdaab9cc3179fc7e36878231 Mon Sep 17 00:00:00 2001 From: i-mills Date: Tue, 21 Jun 2022 13:04:42 +0100 Subject: [PATCH 2/6] issues/99 - In progress, correcting invalid CLMap byte conversion code --- .../serialization/types/CLValueByteSerializerTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java index 679b60863..26f3684a1 100644 --- a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java +++ b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java @@ -128,6 +128,10 @@ void clMapTypeBytesTest() { byte[] bytes = byteSerializer.toBytes(CLValueBuilder.map(clMap)); - assertThat(bytes[0], is(CLType.MAP.getClType())); + assertThat(bytes[4], is(CLType.MAP.getClType())); + assertThat(bytes[5], is(CLType.BYTE_ARRAY.getClType())); + assertThat(bytes[6], is(CLType.U256.getClType())); + + // TODO test values are converted } } From 4e6c71cf7b62913f82c518fbb3a5877edea9b1d4 Mon Sep 17 00:00:00 2001 From: i-mills Date: Tue, 21 Jun 2022 18:07:40 +0100 Subject: [PATCH 3/6] issues/99 - In progress, correcting invalid CLMap byte conversion code --- .../serialization/cltypes/CLValueBuilder.java | 5 +++- .../serialization/cltypes/MapSerializer.java | 23 +++++++++++++------ .../types/CLValueByteSerializerTest.java | 21 +++++++++-------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/casper/sdk/service/serialization/cltypes/CLValueBuilder.java b/src/main/java/com/casper/sdk/service/serialization/cltypes/CLValueBuilder.java index a5c44b960..9d1a7be74 100644 --- a/src/main/java/com/casper/sdk/service/serialization/cltypes/CLValueBuilder.java +++ b/src/main/java/com/casper/sdk/service/serialization/cltypes/CLValueBuilder.java @@ -89,7 +89,10 @@ public static CLMap map(final Map map) { throw new ValueNotFoundException("Maps must contain at least one key pair"); } - return new CLMap(TYPES_FACTORY.getInstance(CLType.MAP).serialize(map), + final byte[] bytes = TYPES_FACTORY.getInstance(CLType.MAP).serialize(map); + + return new CLMap( + bytes, new CLMapTypeInfo( map.keySet().iterator().next().getCLTypeInfo(), map.values().iterator().next().getCLTypeInfo() diff --git a/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java b/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java index 0be2c95ef..112d394e6 100644 --- a/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java +++ b/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java @@ -23,24 +23,33 @@ public MapSerializer(final TypesFactory typesFactory) { public byte[] serialize(final Object toSerialize) { if (toSerialize instanceof CLMap) { - if (((CLMap) toSerialize).isModified() || ((CLMap) toSerialize).getBytes() == null) { + if (((CLMap) toSerialize).isModified() || ((CLMap) toSerialize).getBytes() == null) { ((CLMap) toSerialize).setModified(false); - return ByteUtils.concat( - typesFactory.getInstance(CLType.U32).serialize(((CLMap) toSerialize).size()), - buildMapBytes((CLMap)toSerialize) - ); + //noinspection unchecked + return serializeMap((Map) toSerialize); } else { - // The map has not been modified so write as is + // The map in not new and has not been modified so write as is return ((CLMap) toSerialize).getBytes(); } + } else if (toSerialize instanceof Map) { + //noinspection unchecked + return serializeMap((Map) toSerialize); } else { return new byte[0]; } } - private byte[] buildMapBytes(final CLMap clMap) { + private byte[] serializeMap(final Map toSerialize) { + return ByteUtils.concat( + typesFactory.getInstance(CLType.U32).serialize(toSerialize.size()), + buildKeyValueBytes(toSerialize) + ); + } + + private byte[] buildKeyValueBytes(final Map clMap) { + final ByteArrayBuilder builder = new ByteArrayBuilder(); for (Map.Entry entry : clMap.entrySet()) { diff --git a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java index 26f3684a1..21049fdcc 100644 --- a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java +++ b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java @@ -6,8 +6,6 @@ import com.casper.sdk.types.*; import org.junit.jupiter.api.Test; -import java.util.Map; - import static com.casper.sdk.service.serialization.util.ByteUtils.concat; import static com.casper.sdk.service.serialization.util.ByteUtils.decodeHex; import static org.hamcrest.MatcherAssert.assertThat; @@ -40,7 +38,6 @@ void u64toBytes() { @Test void u512ValueToBytes() { - final CLValue source = new CLValue( decodeHex("0500e40b5402"), CLType.U512, @@ -123,15 +120,19 @@ void keyValueToBytes() { @Test void clMapTypeBytesTest() { - final Digest contractHash = new Digest("8c7b947748f9715c3f24d83fbe60ab03b9602976ebcfe29535143c3dc19eca01"); - final Map clMap = CollectionUtils.Map.of(CLValueBuilder.byteArray(contractHash), CLValueBuilder.u256(50000)); + final CLValue key = CLValueBuilder.string("ABC"); + final CLValue value = CLValueBuilder.i32(10); + final byte[] expectedBytes = {1, 0, 0, 0, 3, 0, 0, 0, 65, 66, 67, 10, 0, 0, 0}; + + // Assert the value builder can generate the bytes + final CLMap clMap = CLValueBuilder.map(CollectionUtils.Map.of(key, value)); + assertThat(clMap.getBytes(), is(expectedBytes)); - byte[] bytes = byteSerializer.toBytes(CLValueBuilder.map(clMap)); + final byte[] expectedWithTypeBytes = {15, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 65, 66, 67, 10, 0, 0, 0, 17, 10, 1}; - assertThat(bytes[4], is(CLType.MAP.getClType())); - assertThat(bytes[5], is(CLType.BYTE_ARRAY.getClType())); - assertThat(bytes[6], is(CLType.U256.getClType())); + // Obtain the value with its type info + final byte[] bytes = byteSerializer.toBytes(clMap); + assertThat(bytes, is(expectedWithTypeBytes)); - // TODO test values are converted } } From 126da375a656abeb59ab7154a8d397acd70fc36c Mon Sep 17 00:00:00 2001 From: i-mills Date: Tue, 21 Jun 2022 18:12:40 +0100 Subject: [PATCH 4/6] issues/99 - Fixed issued with byte conversion of CLMap values --- .../com/casper/sdk/how_to/HowToUseMaps.java | 114 ------------------ .../types/CLValueByteSerializerTest.java | 2 - 2 files changed, 116 deletions(-) delete mode 100644 src/test/java/com/casper/sdk/how_to/HowToUseMaps.java diff --git a/src/test/java/com/casper/sdk/how_to/HowToUseMaps.java b/src/test/java/com/casper/sdk/how_to/HowToUseMaps.java deleted file mode 100644 index 46dbf6b16..000000000 --- a/src/test/java/com/casper/sdk/how_to/HowToUseMaps.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.casper.sdk.how_to; - -import com.casper.sdk.CasperSdk; -import com.casper.sdk.KeyPairStreams; -import com.casper.sdk.service.serialization.cltypes.CLValueBuilder; -import com.casper.sdk.service.serialization.util.CollectionUtils; -import com.casper.sdk.types.*; -import org.junit.jupiter.api.Test; - -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.KeyPair; -import java.time.Instant; -import java.util.Map; - -import static com.casper.sdk.how_to.HowToUtils.getFaucetKeyPair; -import static com.casper.sdk.how_to.HowToUtils.getWasmIn; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsNull.notNullValue; - -public class HowToUseMaps { - - /** Create new instance of the SDK with default NCTL url and port */ - final CasperSdk casperSdk = new CasperSdk("http://localhost", 11101); - - - @Test - void clMapUsage() throws Exception { - - final KeyPairStreams faucetKeyPair = getFaucetKeyPair(); - final KeyPair operatorKeyPair = casperSdk.loadKeyPair(faucetKeyPair.getPublicKeyIn(), faucetKeyPair.getPrivateKeyIn()); - - - final Digest contractHash = installContract(); - - assertThat(contractHash, is(notNullValue())); - - /* CLValue key1 = CLValueBuilder.byteArray(contractHash); - CLValue value1 = CLValueBuilder.u256(50000); - - CLMap clMap = new CLMap((String) null, new CLMapTypeInfo(key1.getCLTypeInfo(), value1.getCLTypeInfo()), null); - clMap.put(key1, value1); -*/ - final Map clMap = CollectionUtils.Map.of(CLValueBuilder.byteArray(contractHash), CLValueBuilder.u256(50000)); - - final Deploy deploy = casperSdk.makeDeploy( - new DeployParams( - // platformKeyPair.getPublic(), - operatorKeyPair.getPublic(), - "integration-test", - 1, - Instant.now().toEpochMilli(), - DeployParams.DEFAULT_TTL, - null), - new StoredContractByHash( - new ContractHash(contractHash.getHash()), - "set_state", - new DeployNamedArgBuilder() - .add("token_id", CLValueBuilder.string("A-TOKEN-ID")) - .add("instrument_id", CLValueBuilder.string("A-CONTRACT-ID")) - .add("asset_decimals", CLValueBuilder.u256(10)) - .add("asset_units", CLValueBuilder.u256(50000)) - .add("asset_holders", CLValueBuilder.map(clMap)) - .add("liability_decimals", CLValueBuilder.u256(10)) - .add("liability_units", CLValueBuilder.u256(40000)) - .add("liability_holders", CLValueBuilder.map(clMap)) - .build()), - casperSdk.standardPayment(new BigInteger("10000000000")) - ); - } - - - public Digest installContract() throws FileNotFoundException { - - final InputStream erc20wasmIn = getWasmIn("/com/casper/sdk/how_to/erc20.wasm"); - final String chainName = "casper-net-1"; - final Number payment = 50e9; - final int tokenDecimals = 11; - final String tokenName = "Acme Token"; - final Number tokenTotalSupply = 1e15; - final String tokenSymbol = "ACME"; - - // Get contract operator. - final KeyPairStreams faucetKeyPair = getFaucetKeyPair(); - final KeyPair operatorKeyPair = casperSdk.loadKeyPair(faucetKeyPair.getPublicKeyIn(), faucetKeyPair.getPrivateKeyIn()); - - // Set deploy. - final Deploy deploy = casperSdk.makeInstallContract( - new DeployParams( - operatorKeyPair.getPublic(), - chainName, - null, - null, - null, - null - ), - payment, - erc20wasmIn, - tokenDecimals, - tokenName, - tokenSymbol, - tokenTotalSupply - ); - - // Approve deploy. - casperSdk.signDeploy(deploy, operatorKeyPair); - - // Dispatch deploy to a node. - return casperSdk.putDeploy(deploy); - - } -} diff --git a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java index 21049fdcc..512bca93e 100644 --- a/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java +++ b/src/test/java/com/casper/sdk/service/serialization/types/CLValueByteSerializerTest.java @@ -92,7 +92,6 @@ void byteOptionArrayKeyValue() { assertThat(byteSerializer.toBytes(optionValue), is(expected)); } - @Test void keyValueToBytes() { @@ -133,6 +132,5 @@ void clMapTypeBytesTest() { // Obtain the value with its type info final byte[] bytes = byteSerializer.toBytes(clMap); assertThat(bytes, is(expectedWithTypeBytes)); - } } From a6e7925027026e8606014bdb16409bcfbedb2ad2 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Tue, 21 Jun 2022 18:15:12 +0100 Subject: [PATCH 5/6] Update MapSerializer.java --- .../casper/sdk/service/serialization/cltypes/MapSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java b/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java index 112d394e6..908603ac5 100644 --- a/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java +++ b/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java @@ -30,7 +30,7 @@ public byte[] serialize(final Object toSerialize) { return serializeMap((Map) toSerialize); } else { - // The map in not new and has not been modified so write as is + // The map is not new and has not been modified so write as is return ((CLMap) toSerialize).getBytes(); } } else if (toSerialize instanceof Map) { From 1ddf32f0c6ef1e500dd1ff2d82c92b5f663f389b Mon Sep 17 00:00:00 2001 From: i-mills Date: Wed, 22 Jun 2022 11:11:44 +0100 Subject: [PATCH 6/6] issues/99 - Changes for code review and increase version number --- pom.xml | 2 +- .../sdk/service/serialization/cltypes/MapSerializer.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6079d103f..db79d1774 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 network.casper casper-java-sdk - 0.3.5 + 0.3.6 Casper Java SDK Casper Java SDK https://casperlabs.io/ diff --git a/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java b/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java index 112d394e6..85b9b5e18 100644 --- a/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java +++ b/src/main/java/com/casper/sdk/service/serialization/cltypes/MapSerializer.java @@ -24,7 +24,8 @@ public byte[] serialize(final Object toSerialize) { if (toSerialize instanceof CLMap) { - if (((CLMap) toSerialize).isModified() || ((CLMap) toSerialize).getBytes() == null) { + // The map is mutable to the bytes need to be reserialized if modified or not yet created + if (isModifiedOrNotYetSerialized((CLMap) toSerialize)) { ((CLMap) toSerialize).setModified(false); //noinspection unchecked return serializeMap((Map) toSerialize); @@ -41,6 +42,10 @@ public byte[] serialize(final Object toSerialize) { } } + private boolean isModifiedOrNotYetSerialized(final CLMap toSerialize) { + return toSerialize.isModified() || toSerialize.getBytes() == null; + } + private byte[] serializeMap(final Map toSerialize) { return ByteUtils.concat( typesFactory.getInstance(CLType.U32).serialize(toSerialize.size()),