From 3fbcc50503aa68b08301c1b5620c37a1ce7c33ae Mon Sep 17 00:00:00 2001 From: CalDescent Date: Fri, 25 Aug 2023 11:01:48 +0100 Subject: [PATCH] Fixed deserialization issues with CreationRequest, added validation, and made small code tweaks for consistency with other endpoints. --- .../qortal/api/model/AtCreationRequest.java | 102 ++++++++++++++++++ .../org/qortal/api/resource/AtResource.java | 55 +++++----- .../data/transaction/CreationRequest.java | 78 -------------- 3 files changed, 129 insertions(+), 106 deletions(-) create mode 100644 src/main/java/org/qortal/api/model/AtCreationRequest.java delete mode 100644 src/main/java/org/qortal/data/transaction/CreationRequest.java diff --git a/src/main/java/org/qortal/api/model/AtCreationRequest.java b/src/main/java/org/qortal/api/model/AtCreationRequest.java new file mode 100644 index 00000000..14ccdaa2 --- /dev/null +++ b/src/main/java/org/qortal/api/model/AtCreationRequest.java @@ -0,0 +1,102 @@ +package org.qortal.api.model; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlTransient; + +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.DecoderException; + +@XmlAccessorType(XmlAccessType.FIELD) +public class AtCreationRequest { + + @Schema(description = "CIYAM AT version", example = "2") + private short ciyamAtVersion; + + @Schema(description = "base64-encoded code bytes", example = "") + private String codeBytesBase64; + + @Schema(description = "base64-encoded data bytes", example = "") + private String dataBytesBase64; + + private short numCallStackPages; + private short numUserStackPages; + private long minActivationAmount; + + // Default constructor for JSON deserialization + public AtCreationRequest() {} + + // Getters and setters + public short getCiyamAtVersion() { + return ciyamAtVersion; + } + + public void setCiyamAtVersion(short ciyamAtVersion) { + this.ciyamAtVersion = ciyamAtVersion; + } + + + public String getCodeBytesBase64() { + return this.codeBytesBase64; + } + + @XmlTransient + @Schema(hidden = true) + public byte[] getCodeBytes() { + if (this.codeBytesBase64 != null) { + try { + return Base64.decode(this.codeBytesBase64); + } + catch (DecoderException e) { + return null; + } + } + return null; + } + + + public String getDataBytesBase64() { + return this.dataBytesBase64; + } + + @XmlTransient + @Schema(hidden = true) + public byte[] getDataBytes() { + if (this.dataBytesBase64 != null) { + try { + return Base64.decode(this.dataBytesBase64); + } + catch (DecoderException e) { + return null; + } + } + return null; + } + + + public short getNumCallStackPages() { + return numCallStackPages; + } + + public void setNumCallStackPages(short numCallStackPages) { + this.numCallStackPages = numCallStackPages; + } + + public short getNumUserStackPages() { + return numUserStackPages; + } + + public void setNumUserStackPages(short numUserStackPages) { + this.numUserStackPages = numUserStackPages; + } + + public long getMinActivationAmount() { + return minActivationAmount; + } + + public void setMinActivationAmount(long minActivationAmount) { + this.minActivationAmount = minActivationAmount; + } +} diff --git a/src/main/java/org/qortal/api/resource/AtResource.java b/src/main/java/org/qortal/api/resource/AtResource.java index 80a6e299..13bfec83 100644 --- a/src/main/java/org/qortal/api/resource/AtResource.java +++ b/src/main/java/org/qortal/api/resource/AtResource.java @@ -9,7 +9,6 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; -import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -28,7 +27,7 @@ import org.qortal.api.ApiException; import org.qortal.api.ApiExceptionFactory; import org.qortal.data.at.ATData; import org.qortal.data.at.ATStateData; -import org.qortal.data.transaction.CreationRequest; +import org.qortal.api.model.AtCreationRequest; import org.qortal.data.transaction.DeployAtTransactionData; import org.qortal.repository.DataException; import org.qortal.repository.Repository; @@ -39,10 +38,11 @@ import org.qortal.transaction.Transaction.ValidationResult; import org.qortal.transform.TransformationException; import org.qortal.transform.transaction.DeployAtTransactionTransformer; import org.qortal.utils.Base58; -import java.util.Base64; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.ObjectMapper; + + @Path("/at") @Tag(name = "Automated Transactions") public class AtResource { @@ -163,21 +163,21 @@ public class AtResource { } @POST - @Path("/createMachineState") + @Path("/create") @Operation( - summary = "Create MachineState bytes from the provided parameters", + summary = "Create base58-encoded AT creation bytes from the provided parameters", requestBody = @RequestBody( required = true, content = @Content( mediaType = MediaType.APPLICATION_JSON, schema = @Schema( - implementation = CreationRequest.class + implementation = AtCreationRequest.class ) ) ), responses = { @ApiResponse( - description = "MachineState bytes", + description = "AT creation bytes suitable for use in a DEPLOY_AT transaction", content = @Content( mediaType = MediaType.TEXT_PLAIN, schema = @Schema( @@ -187,27 +187,26 @@ public class AtResource { ) } ) - public String createMachineState(String jsonBody) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); - CreationRequest request = objectMapper.readValue(jsonBody, CreationRequest.class); - - logger.info("ciyamAtVersion: {}", request.getCiyamAtVersion()); - logger.info("codeBytes: {}", request.getCodeBytes()); - logger.info("codeBytes: {}", request.getNumUserStackPages()); - logger.info("codeBytes: {}", request.getDataBytes()); - logger.info("codeBytes: {}", request.getNumCallStackPages()); - logger.info("codeBytes: {}", request.getMinActivationAmount()); - byte[] creationBytes = MachineState.toCreationBytes( - request.getCiyamAtVersion(), - request.getCodeBytes(), - request.getDataBytes(), - request.getNumCallStackPages(), - request.getNumUserStackPages(), - request.getMinActivationAmount() - ); - return Base58.encode(creationBytes); - + public String create(AtCreationRequest atCreationRequest) { + if (atCreationRequest.getCiyamAtVersion() < 2) { + throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "ciyamAtVersion must be at least 2"); + } + if (atCreationRequest.getCodeBytes() == null) { + throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Valid codeBytesBase64 must be supplied"); + } + if (atCreationRequest.getDataBytes() == null) { + throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Valid dataBytesBase64 must be supplied"); + } + byte[] creationBytes = MachineState.toCreationBytes( + atCreationRequest.getCiyamAtVersion(), + atCreationRequest.getCodeBytes(), + atCreationRequest.getDataBytes(), + atCreationRequest.getNumCallStackPages(), + atCreationRequest.getNumUserStackPages(), + atCreationRequest.getMinActivationAmount() + ); + return Base58.encode(creationBytes); } @POST @Operation( diff --git a/src/main/java/org/qortal/data/transaction/CreationRequest.java b/src/main/java/org/qortal/data/transaction/CreationRequest.java deleted file mode 100644 index 9d50458c..00000000 --- a/src/main/java/org/qortal/data/transaction/CreationRequest.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.qortal.data.transaction; - -import java.util.Base64; -import com.fasterxml.jackson.annotation.JsonProperty; -public class CreationRequest { - - private short ciyamAtVersion; - @JsonProperty("codeBytesBase64") - private String codeBytesBase64; - private String dataBytesBase64; - private short numCallStackPages; - private short numUserStackPages; - private long minActivationAmount; - - // Default constructor for JSON deserialization - public CreationRequest() {} - - // Getters and setters - public short getCiyamAtVersion() { - return ciyamAtVersion; - } - - public void setCiyamAtVersion(short ciyamAtVersion) { - this.ciyamAtVersion = ciyamAtVersion; - } - - public byte[] getCodeBytes() { - if (this.codeBytesBase64 != null) { - return Base64.getDecoder().decode(this.codeBytesBase64); - } - return new byte[0]; - } - - public void setCodeBytesBase64(String codeBytesBase64) { - this.codeBytesBase64 = codeBytesBase64; - } - public String getCodeBytes2() { - return codeBytesBase64; - - } - - - - public byte[] getDataBytes() { - if (this.dataBytesBase64 != null) { - return Base64.getDecoder().decode(this.dataBytesBase64); - } - return new byte[0]; - } - - public void setDataBytesBase64(String dataBytesBase64) { - this.dataBytesBase64 = dataBytesBase64; - } - - public short getNumCallStackPages() { - return numCallStackPages; - } - - public void setNumCallStackPages(short numCallStackPages) { - this.numCallStackPages = numCallStackPages; - } - - public short getNumUserStackPages() { - return numUserStackPages; - } - - public void setNumUserStackPages(short numUserStackPages) { - this.numUserStackPages = numUserStackPages; - } - - public long getMinActivationAmount() { - return minActivationAmount; - } - - public void setMinActivationAmount(long minActivationAmount) { - this.minActivationAmount = minActivationAmount; - } -}