From 641a6580593b761a007ffa3e2e0eb5d2ebb47350 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 10 Apr 2021 17:49:04 +0100 Subject: [PATCH] Added /blocks/byheight/{height}/mintinginfo API, which returns info on the minter level, key distance, and block timings. --- .../qortal/api/model/BlockMintingInfo.java | 22 +++++++ .../qortal/api/resource/BlocksResource.java | 58 +++++++++++++++++++ src/main/java/org/qortal/block/Block.java | 2 +- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/qortal/api/model/BlockMintingInfo.java diff --git a/src/main/java/org/qortal/api/model/BlockMintingInfo.java b/src/main/java/org/qortal/api/model/BlockMintingInfo.java new file mode 100644 index 00000000..e71c918b --- /dev/null +++ b/src/main/java/org/qortal/api/model/BlockMintingInfo.java @@ -0,0 +1,22 @@ +package org.qortal.api.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.math.BigDecimal; +import java.math.BigInteger; + +@XmlAccessorType(XmlAccessType.FIELD) +public class BlockMintingInfo { + + public byte[] minterPublicKey; + public int minterLevel; + public BigDecimal maxDistance; + public BigInteger keyDistance; + public double keyDistanceRatio; + public long timestamp; + public long timeDelta; + + public BlockMintingInfo() { + } + +} diff --git a/src/main/java/org/qortal/api/resource/BlocksResource.java b/src/main/java/org/qortal/api/resource/BlocksResource.java index 30cc477e..1b160b91 100644 --- a/src/main/java/org/qortal/api/resource/BlocksResource.java +++ b/src/main/java/org/qortal/api/resource/BlocksResource.java @@ -8,6 +8,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; @@ -20,10 +23,13 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import org.qortal.account.Account; import org.qortal.api.ApiError; import org.qortal.api.ApiErrors; import org.qortal.api.ApiExceptionFactory; +import org.qortal.api.model.BlockMintingInfo; import org.qortal.api.model.BlockSignerSummary; +import org.qortal.block.Block; import org.qortal.crypto.Crypto; import org.qortal.data.account.AccountData; import org.qortal.data.block.BlockData; @@ -328,6 +334,58 @@ public class BlocksResource { } } + @GET + @Path("/byheight/{height}/mintinginfo") + @Operation( + summary = "Fetch block minter info using block height", + description = "Returns the minter info for the block with given height", + responses = { + @ApiResponse( + description = "the block", + content = @Content( + schema = @Schema( + implementation = BlockData.class + ) + ) + ) + } + ) + @ApiErrors({ + ApiError.BLOCK_UNKNOWN, ApiError.REPOSITORY_ISSUE + }) + public BlockMintingInfo getBlockMintingInfoByHeight(@PathParam("height") int height) { + try (final Repository repository = RepositoryManager.getRepository()) { + BlockData blockData = repository.getBlockRepository().fromHeight(height); + if (blockData == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCK_UNKNOWN); + + Block block = new Block(repository, blockData); + BlockData parentBlockData = repository.getBlockRepository().fromSignature(blockData.getReference()); + int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockData.getMinterPublicKey()); + if (minterLevel == 0) + // This may be unavailable when requesting a trimmed block + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); + + BigInteger distance = block.calcKeyDistance(parentBlockData.getHeight(), parentBlockData.getSignature(), blockData.getMinterPublicKey(), minterLevel); + double ratio = new BigDecimal(distance).divide(new BigDecimal(block.MAX_DISTANCE), 40, RoundingMode.DOWN).doubleValue(); + long timestamp = block.calcTimestamp(parentBlockData, blockData.getMinterPublicKey(), minterLevel); + long timeDelta = timestamp - parentBlockData.getTimestamp(); + + BlockMintingInfo blockMintingInfo = new BlockMintingInfo(); + blockMintingInfo.minterPublicKey = blockData.getMinterPublicKey(); + blockMintingInfo.minterLevel = minterLevel; + blockMintingInfo.maxDistance = new BigDecimal(block.MAX_DISTANCE); + blockMintingInfo.keyDistance = distance; + blockMintingInfo.keyDistanceRatio = ratio; + blockMintingInfo.timestamp = timestamp; + blockMintingInfo.timeDelta = timeDelta; + + return blockMintingInfo; + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + @GET @Path("/timestamp/{timestamp}") @Operation( diff --git a/src/main/java/org/qortal/block/Block.java b/src/main/java/org/qortal/block/Block.java index 8551e4e7..74fe059c 100644 --- a/src/main/java/org/qortal/block/Block.java +++ b/src/main/java/org/qortal/block/Block.java @@ -225,7 +225,7 @@ public class Block { // Other useful constants - private static final BigInteger MAX_DISTANCE; + public static final BigInteger MAX_DISTANCE; static { byte[] maxValue = new byte[Transformer.PUBLIC_KEY_LENGTH]; Arrays.fill(maxValue, (byte) 0xFF);