From 8667a5703c6bebe94b95e4a42daa5f50a9d01883 Mon Sep 17 00:00:00 2001 From: Joshua Primero Date: Thu, 22 Jul 2021 15:54:43 -0500 Subject: [PATCH] Fix getNextEpochValidatorSet archive endpoint --- .../api/data/ValidatorInfoDetails.java | 16 -- .../api/handler/ArchiveValidationHandler.java | 2 +- .../api/handler/ValidationHandler.java | 51 ++-- .../api/service/AccountInfoService.java | 95 +------ .../radixdlt/api/service/MetricsService.java | 10 +- .../service/ValidatorArchiveInfoService.java | 85 ++++--- .../api/service/ValidatorInfoService.java | 189 ++++++++++++++ .../service/reducer/NextEpochValidators.java | 233 ------------------ .../BerkeleyValidatorUptimeArchiveStore.java | 25 ++ .../statecomputer/ValidatorDetails.java | 153 ------------ .../handler/ArchiveValidationHandlerTest.java | 40 --- 11 files changed, 295 insertions(+), 604 deletions(-) create mode 100644 radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorInfoService.java delete mode 100644 radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/reducer/NextEpochValidators.java delete mode 100644 radixdlt-core/radixdlt/src/main/java/com/radixdlt/statecomputer/ValidatorDetails.java diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/data/ValidatorInfoDetails.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/data/ValidatorInfoDetails.java index 15357ed0cd..b98b0863a7 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/data/ValidatorInfoDetails.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/data/ValidatorInfoDetails.java @@ -70,7 +70,6 @@ import com.radixdlt.crypto.ECPublicKey; import com.radixdlt.identifiers.REAddr; import com.radixdlt.networks.Addressing; -import com.radixdlt.statecomputer.ValidatorDetails; import com.radixdlt.utils.UInt256; import static com.radixdlt.api.JsonRpcUtil.jsonObject; @@ -137,21 +136,6 @@ public static ValidatorInfoDetails create( ); } - public static ValidatorInfoDetails create(ValidatorDetails details) { - return create( - details.getKey(), - details.getOwner(), - details.getName(), - details.getUrl(), - details.getStake(), - details.getOwnerStake(), - details.allowsDelegation(), - details.registered(), - details.getPercentage(), - details.getUptime() - ); - } - public String getValidatorAddress(Addressing addressing) { return addressing.forValidators().of(validator); } diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ArchiveValidationHandler.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ArchiveValidationHandler.java index 936be135b3..656ce68159 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ArchiveValidationHandler.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ArchiveValidationHandler.java @@ -118,7 +118,7 @@ public JSONObject handleValidatorsLookupValidator(JSONObject request) { request, "validatorAddress", address -> addressing.forValidators().fromString(address) - .flatMap(validatorInfoService::getValidator) + .map(validatorInfoService::getNextEpochValidator) .map(d -> d.asJson(addressing)) ); } diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ValidationHandler.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ValidationHandler.java index 01148ca258..9626ee5f7a 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ValidationHandler.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/handler/ValidationHandler.java @@ -64,6 +64,7 @@ package com.radixdlt.api.handler; +import com.radixdlt.api.service.ValidatorInfoService; import com.radixdlt.api.store.ValidatorUptime; import com.radixdlt.application.system.state.ValidatorBFTData; import com.radixdlt.application.system.state.ValidatorStakeData; @@ -77,36 +78,40 @@ import org.json.JSONObject; import com.google.inject.Inject; -import com.radixdlt.api.service.AccountInfoService; import static com.radixdlt.api.JsonRpcUtil.*; import static com.radixdlt.application.validators.scrypt.ValidatorUpdateRakeConstraintScrypt.RAKE_PERCENTAGE_GRANULARITY; public final class ValidationHandler { - private final AccountInfoService accountService; + private final ValidatorInfoService validatorInfoService; private final Addressing addressing; private final ECPublicKey self; private final RadixEngine radixEngine; @Inject public ValidationHandler( - AccountInfoService accountService, + ValidatorInfoService validatorInfoService, RadixEngine radixEngine, @Self ECPublicKey self, Addressing addressing ) { - this.accountService = accountService; + this.validatorInfoService = validatorInfoService; this.radixEngine = radixEngine; this.self = self; this.addressing = addressing; } private JSONObject getValidatorInfo() { - var metadata = accountService.getMyValidatorMetadata(); - var stakeData = accountService.getStakeData(); - var validatorData = stakeData.getFirst(); - var allowDelegationFlag = accountService.getMyValidatorDelegationFlag(); - var uptime = accountService.getMyValidatorUptime(); + var metadata = validatorInfoService.getMetadata(self); + var validatorData = validatorInfoService.getValidatorStakeData(self); + var individualStakes = validatorInfoService.getEstimatedIndividualStakes(validatorData); + var stakesJson = jsonArray(); + individualStakes.forEach((addr, amt) -> stakesJson.put(jsonObject() + .put("delegator", addressing.forAccounts().of(addr)) + .put("amount", amt) + )); + var allowDelegationFlag = validatorInfoService.getAllowDelegationFlag(self); + var uptime = validatorInfoService.getUptime(self); var validatorAddress = addressing.forValidators().of(self); var data = jsonObject() @@ -119,26 +124,26 @@ private JSONObject getValidatorInfo() { .put("registered", validatorData.isRegistered()) .put("owner", addressing.forAccounts().of(validatorData.getOwnerAddr())) .put("validatorFee", (double) validatorData.getRakePercentage() / (double) RAKE_PERCENTAGE_GRANULARITY + "") - .put("stakes", stakeData.getSecond()) + .put("stakes", stakesJson) .put("totalStake", validatorData.getTotalStake()) .put("proposalsCompleted", uptime.getProposalsCompleted()) .put("proposalsMissed", uptime.getProposalsMissed()) .put("uptimePercentage", uptime.toPercentageString()); var updates = jsonObject(); - var validatorRakeCopy = accountService.getMyNextValidatorFee(); + var validatorRakeCopy = validatorInfoService.getNextValidatorFee(self); if (validatorRakeCopy.getRakePercentage() != validatorData.getRakePercentage()) { updates.put("validatorFee", (double) validatorRakeCopy.getRakePercentage() / (double) RAKE_PERCENTAGE_GRANULARITY + ""); } - var nextEpochRegisteredFlag = accountService.getMyNextEpochRegisteredFlag().isRegistered(); + var nextEpochRegisteredFlag = validatorInfoService.getNextEpochRegisteredFlag(self).isRegistered(); if (nextEpochRegisteredFlag != validatorData.isRegistered()) { updates.put("registered", nextEpochRegisteredFlag); } - var nextEpochOwner = accountService.getMyNextEpochValidatorOwner().getOwner(); + var nextEpochOwner = validatorInfoService.getNextEpochValidatorOwner(self).getOwner(); if (!nextEpochOwner.equals(validatorData.getOwnerAddr())) { updates.put("owner", addressing.forAccounts().of(nextEpochOwner)); } - var preparedStakes = accountService.getPreparedStakesToMyValidator(); + var preparedStakes = validatorInfoService.getPreparedStakes(self); if (!preparedStakes.isEmpty()) { var preparedStakesJson = jsonArray(); preparedStakes.forEach((addr, amount) -> preparedStakesJson.put( @@ -148,20 +153,14 @@ private JSONObject getValidatorInfo() { )); updates.put("stakes", preparedStakesJson); } - var preparedUnstakes = accountService.getPreparedUnstakesFromMyValidator(); + var preparedUnstakes = validatorInfoService.getEstimatedPreparedUnstakes(validatorData); if (!preparedUnstakes.isEmpty()) { - var curStake = validatorData.getTotalStake(); - var curOwnership = validatorData.getTotalOwnership(); var preparedUnstakesJson = jsonArray(); - for (var e : preparedUnstakes.entrySet()) { - var unstakeValueEstimate = e.getValue().multiply(curStake).divide(curOwnership).getLow(); - preparedUnstakesJson.put(jsonObject() - .put("amount", unstakeValueEstimate) - .put("delegator", addressing.forAccounts().of(e.getKey())) - ); - curOwnership = curOwnership.subtract(e.getValue().getLow()); - curStake = curStake.subtract(unstakeValueEstimate); - } + preparedUnstakes.forEach((addr, amount) -> preparedUnstakesJson.put( + jsonObject() + .put("amount", amount) + .put("delegator", addressing.forAccounts().of(addr)) + )); updates.put("unstakes", preparedUnstakesJson); } diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/AccountInfoService.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/AccountInfoService.java index fbbbd362d4..ba8edf2c3c 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/AccountInfoService.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/AccountInfoService.java @@ -64,26 +64,16 @@ package com.radixdlt.api.service; -import com.radixdlt.api.store.ValidatorUptime; import com.radixdlt.application.system.state.StakeOwnership; -import com.radixdlt.application.system.state.ValidatorBFTData; import com.radixdlt.application.system.state.ValidatorStakeData; import com.radixdlt.application.tokens.state.PreparedStake; -import com.radixdlt.application.tokens.state.PreparedUnstakeOwnership; import com.radixdlt.application.tokens.state.TokenResourceMetadata; import com.radixdlt.application.tokens.state.TokensInAccount; -import com.radixdlt.application.validators.state.AllowDelegationFlag; -import com.radixdlt.application.validators.state.ValidatorMetaData; -import com.radixdlt.application.validators.state.ValidatorOwnerCopy; -import com.radixdlt.application.validators.state.ValidatorFeeCopy; -import com.radixdlt.application.validators.state.ValidatorRegisteredCopy; import com.radixdlt.atom.SubstateTypeId; import com.radixdlt.constraintmachine.SubstateIndex; import com.radixdlt.constraintmachine.SystemMapKey; import com.radixdlt.engine.RadixEngine; -import com.radixdlt.utils.Pair; import org.bouncycastle.util.Arrays; -import org.json.JSONArray; import org.json.JSONObject; import com.google.inject.Inject; @@ -92,7 +82,6 @@ import com.radixdlt.identifiers.REAddr; import com.radixdlt.networks.Addressing; import com.radixdlt.statecomputer.LedgerAndBFTProof; -import com.radixdlt.utils.UInt256; import com.radixdlt.utils.UInt384; import java.util.HashMap; @@ -123,89 +112,7 @@ public JSONObject getAccountInfo() { .put("balance", getOwnBalance()); } - public ValidatorUptime getMyValidatorUptime() { - var validatorUptimeKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_BFT_DATA.id(), bftKey.getCompressedBytes()); - return radixEngine.get(validatorUptimeKey) - .map(ValidatorBFTData.class::cast) - .map(d -> ValidatorUptime.create(d.proposalsCompleted(), d.proposalsMissed())) - .orElse(ValidatorUptime.empty()); - } - - public AllowDelegationFlag getMyValidatorDelegationFlag() { - var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_ALLOW_DELEGATION_FLAG.id(), bftKey.getCompressedBytes()); - return (AllowDelegationFlag) radixEngine.get(validatorDataKey).orElse(AllowDelegationFlag.createVirtual(bftKey)); - } - - public ValidatorRegisteredCopy getMyNextEpochRegisteredFlag() { - var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_REGISTERED_FLAG_COPY.id(), bftKey.getCompressedBytes()); - return (ValidatorRegisteredCopy) radixEngine.get(validatorDataKey).orElse(ValidatorRegisteredCopy.createVirtual(bftKey)); - } - - public ValidatorFeeCopy getMyNextValidatorFee() { - var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_RAKE_COPY.id(), bftKey.getCompressedBytes()); - return (ValidatorFeeCopy) radixEngine.get(validatorDataKey).orElse(ValidatorFeeCopy.createVirtual(bftKey)); - } - - public ValidatorOwnerCopy getMyNextEpochValidatorOwner() { - var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_OWNER_COPY.id(), bftKey.getCompressedBytes()); - return (ValidatorOwnerCopy) radixEngine.get(validatorDataKey).orElse(ValidatorOwnerCopy.createVirtual(bftKey)); - } - - public ValidatorMetaData getMyValidatorMetadata() { - var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_META_DATA.id(), bftKey.getCompressedBytes()); - return (ValidatorMetaData) radixEngine.get(validatorDataKey).orElse(ValidatorMetaData.createVirtual(bftKey)); - } - - public UInt256 getTotalStake() { - return getMyValidator().getTotalStake(); - } - - public ValidatorStakeData getMyValidator() { - var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_STAKE_DATA.id(), bftKey.getCompressedBytes()); - return (ValidatorStakeData) radixEngine.get(validatorDataKey).orElse(ValidatorStakeData.createVirtual(bftKey)); - } - - public Map getPreparedStakesToMyValidator() { - var index = SubstateIndex.create( - Arrays.concatenate(new byte[] {SubstateTypeId.PREPARED_STAKE.id(), 0}, bftKey.getCompressedBytes()), - PreparedStake.class - ); - return radixEngine.reduceResources(index, PreparedStake::getOwner); - } - - public Map getPreparedUnstakesFromMyValidator() { - var index = SubstateIndex.create( - Arrays.concatenate(new byte[] {SubstateTypeId.PREPARED_UNSTAKE.id(), 0}, bftKey.getCompressedBytes()), - PreparedUnstakeOwnership.class - ); - return radixEngine.reduceResources(index, PreparedUnstakeOwnership::getOwner); - } - - public Pair getStakeData() { - var myValidator = getMyValidator(); - var index = SubstateIndex.create( - Arrays.concatenate(new byte[] {SubstateTypeId.STAKE_OWNERSHIP.id(), 0}, bftKey.getCompressedBytes()), - StakeOwnership.class - ); - var stakeReceived = radixEngine.reduceResources(index, StakeOwnership::getOwner); - var unstakingOwnership = SubstateIndex.create( - Arrays.concatenate(new byte[] {SubstateTypeId.PREPARED_UNSTAKE.id(), 0}, bftKey.getCompressedBytes()), - PreparedUnstakeOwnership.class - ); - radixEngine.reduceResources(unstakingOwnership, PreparedUnstakeOwnership::getOwner, stakeReceived); - - var stakeFrom = jsonArray(); - stakeReceived.forEach((address, amt) -> { - stakeFrom.put( - jsonObject() - .put("delegator", addressing.forAccounts().of(address)) - .put("amount", amt.multiply(myValidator.getTotalStake()).divide(myValidator.getTotalOwnership())) - ); - }); - return Pair.of(myValidator, stakeFrom); - } - - public String getOwnAddress() { + private String getOwnAddress() { return addressing.forAccounts().of(REAddr.ofPubKeyAccount(bftKey)); } diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/MetricsService.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/MetricsService.java index c9aa81bc00..b86c953760 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/MetricsService.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/MetricsService.java @@ -206,6 +206,7 @@ public class MetricsService { private final InfoSupplier infoSupplier; private final SystemConfigService systemConfigService; private final AccountInfoService accountInfoService; + private final ValidatorInfoService validatorInfoService; private final NetworkInfoService networkInfoService; private final Addressing addressing; private final InMemorySystemInfo inMemorySystemInfo; @@ -217,6 +218,7 @@ public MetricsService( InfoSupplier infoSupplier, SystemConfigService systemConfigService, AccountInfoService accountInfoService, + ValidatorInfoService validatorInfoService, NetworkInfoService networkInfoService, InMemorySystemInfo inMemorySystemInfo, @Self BFTNode self, @@ -226,6 +228,7 @@ public MetricsService( this.infoSupplier = infoSupplier; this.systemConfigService = systemConfigService; this.accountInfoService = accountInfoService; + this.validatorInfoService = validatorInfoService; this.networkInfoService = networkInfoService; this.inMemorySystemInfo = inMemorySystemInfo; this.self = self; @@ -266,7 +269,8 @@ private void exportSystemInfo(StringBuilder builder) { } private UInt384 getTotalStake() { - return UInt384.from(accountInfoService.getTotalStake()); + var stakeData = validatorInfoService.getValidatorStakeData(self.getKey()); + return UInt384.from(stakeData.getTotalStake()); } private UInt384 getXrdBalance() { @@ -294,7 +298,7 @@ private String prepareNodeInfo() { addEndpontStatuses(builder); appendField(builder, "owner_address", addressing.forAccounts().of(REAddr.ofPubKeyAccount(self.getKey()))); - appendField(builder, "validator_registered", accountInfoService.getMyNextEpochRegisteredFlag()); + appendField(builder, "validator_registered", validatorInfoService.getNextEpochRegisteredFlag(self.getKey())); addBranchAndCommit(builder); addValidatorAddress(builder); addAccumulatorState(builder); @@ -338,7 +342,7 @@ private void appendField(StringBuilder builder, String name, Object value) { private void exportCounters(StringBuilder builder) { EXPORT_LIST.forEach(counterType -> generateCounterEntry(counterType, builder)); - var uptime = accountInfoService.getMyValidatorUptime(); + var uptime = validatorInfoService.getUptime(self.getKey()); appendCounter(builder, COUNTER_PREFIX + "radix_engine_cur_epoch_completed_proposals", uptime.getProposalsCompleted()); appendCounter(builder, COUNTER_PREFIX + "radix_engine_cur_epoch_missed_proposals", uptime.getProposalsMissed()); } diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorArchiveInfoService.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorArchiveInfoService.java index 7d87f1075d..e2982a7702 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorArchiveInfoService.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorArchiveInfoService.java @@ -66,33 +66,30 @@ import com.google.inject.Inject; import com.radixdlt.api.data.ValidatorInfoDetails; -import com.radixdlt.api.service.reducer.NextEpochValidators; import com.radixdlt.api.store.berkeley.BerkeleyValidatorUptimeArchiveStore; -import com.radixdlt.application.system.state.ValidatorStakeData; -import com.radixdlt.application.tokens.state.PreparedStake; -import com.radixdlt.application.validators.state.AllowDelegationFlag; -import com.radixdlt.application.validators.state.ValidatorMetaData; -import com.radixdlt.application.validators.state.ValidatorOwnerCopy; -import com.radixdlt.application.validators.state.ValidatorFeeCopy; +import com.radixdlt.application.validators.state.ValidatorRegisteredCopy; import com.radixdlt.crypto.ECPublicKey; import com.radixdlt.engine.RadixEngine; import com.radixdlt.networks.Addressing; import com.radixdlt.statecomputer.LedgerAndBFTProof; +import com.radixdlt.utils.UInt256; +import com.radixdlt.utils.UInt384; import com.radixdlt.utils.functional.FunctionalUtils; import com.radixdlt.utils.functional.Result; import com.radixdlt.utils.functional.Result.Mapper2; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import static com.radixdlt.api.data.ApiErrors.UNKNOWN_VALIDATOR; import static com.radixdlt.utils.functional.FunctionalUtils.skipUntil; import static com.radixdlt.utils.functional.Tuple.tuple; public class ValidatorArchiveInfoService { private final RadixEngine radixEngine; + private final ValidatorInfoService validatorInfoService; private final BerkeleyValidatorUptimeArchiveStore uptimeStore; private final Addressing addressing; @@ -100,10 +97,12 @@ public class ValidatorArchiveInfoService { public ValidatorArchiveInfoService( RadixEngine radixEngine, BerkeleyValidatorUptimeArchiveStore uptimeStore, + ValidatorInfoService validatorInfoService, Addressing addressing ) { this.radixEngine = radixEngine; this.uptimeStore = uptimeStore; + this.validatorInfoService = validatorInfoService; this.addressing = addressing; } @@ -119,39 +118,49 @@ public Mapper2, List> getValidators( return () -> Result.ok(tuple(newCursor, list)); } - // TODO: Don't retrieve all validators - public Result getValidator(ECPublicKey validatorPublicKey) { - return getAllValidators() - .stream() - .filter(validatorInfoDetails -> validatorInfoDetails.getValidatorKey().equals(validatorPublicKey)) - .findFirst() - .map(Result::ok) - .orElseGet(() -> UNKNOWN_VALIDATOR.with(addressing.forValidators().of(validatorPublicKey)).result()); + public ValidatorInfoDetails getNextEpochValidator(ECPublicKey k) { + var metadata = validatorInfoService.getMetadata(k); + var curData = validatorInfoService.getValidatorStakeData(k); + var owner = validatorInfoService.getNextEpochValidatorOwner(k).getOwner(); + var individualStakes = validatorInfoService.getEstimatedIndividualStakes(curData); + var preparedStakes = validatorInfoService.getPreparedStakes(k); + var totalPreparedStakes = preparedStakes.values().stream().reduce(UInt384::add).orElse(UInt384.ZERO).getLow(); + var preparedUnstakes = validatorInfoService.getEstimatedPreparedUnstakes(curData); + var totalPreparedUnstakes = preparedUnstakes.values().stream().reduce(UInt256::add).orElse(UInt256.ZERO); + var totalStake = curData.getTotalStake().add(totalPreparedStakes).subtract(totalPreparedUnstakes); + var ownerStake = individualStakes.getOrDefault(owner, UInt256.ZERO) + .add(preparedStakes.getOrDefault(owner, UInt384.ZERO).getLow()) + .subtract(preparedUnstakes.getOrDefault(owner, UInt256.ZERO)); + var allowsDelegation = validatorInfoService.getAllowDelegationFlag(k).allowsDelegation(); + var isRegistered = validatorInfoService.getNextEpochRegisteredFlag(k).isRegistered(); + var percentage = validatorInfoService.getNextValidatorFee(k).getRakePercentage(); + var uptime = uptimeStore.getUptimeTwoWeeks(k); + return ValidatorInfoDetails.create( + k, + owner, + metadata.getName(), + metadata.getUrl(), + totalStake, + ownerStake, + allowsDelegation, + isRegistered, + percentage, + uptime + ); } public List getAllValidators() { - // TODO: Use NextEpoch action to compute all of this - var indices = List.of( - ValidatorStakeData.class, - PreparedStake.class, - ValidatorOwnerCopy.class, - AllowDelegationFlag.class, - ValidatorMetaData.class, - ValidatorFeeCopy.class - ); - var nextEpochValidators = NextEpochValidators.create(); - for (var index : indices) { - radixEngine.reduce(index, nextEpochValidators, (u, t) -> { - u.process(t); - return u; - }); - } + var registered = radixEngine.reduce(ValidatorRegisteredCopy.class, new HashSet(), (u, t) -> { + if (t.isRegistered()) { + u.add(t.getValidatorKey()); + } + return u; + }); - var uptime = uptimeStore.getUptimeTwoWeeks(); - nextEpochValidators.process(uptime); - - var result = nextEpochValidators.map(ValidatorInfoDetails::create); - result.sort(Comparator.comparing(ValidatorInfoDetails::getTotalStake).reversed()); - return result; + // TODO: Use NextEpoch action to compute all of this + return registered.stream() + .map(this::getNextEpochValidator) + .sorted(Comparator.comparing(ValidatorInfoDetails::getTotalStake).reversed()) + .collect(Collectors.toList()); } } diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorInfoService.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorInfoService.java new file mode 100644 index 0000000000..0ad96885e3 --- /dev/null +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/ValidatorInfoService.java @@ -0,0 +1,189 @@ +/* + * Copyright 2021 Radix DLT Ltd incorporated in England. + * * + * * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * * file except in compliance with the License. You may obtain a copy of the License at: + * * + * * radixfoundation.org/licenses/LICENSE-v1 + * * + * * The Licensor hereby grants permission for the Canonical version of the Work to be + * * published, distributed and used under or by reference to the Licensor’s trademark + * * Radix ® and use of any unregistered trade names, logos or get-up. + * * + * * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * * + * * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * * a distributed ledger it is your responsibility to test and validate the code, together + * * with all logic and performance of that code under all foreseeable scenarios. + * * + * * The Licensor does not make or purport to make and hereby excludes liability for all + * * and any representation, warranty or undertaking in any form whatsoever, whether express + * * or implied, to any entity or person, including any representation, warranty or + * * undertaking, as to the functionality security use, value or other characteristics of + * * any distributed ledger nor in respect the functioning or value of any tokens which may + * * be created stored or transferred using the Work. The Licensor does not warrant that the + * * Work or any use of the Work complies with any law or regulation in any territory where + * * it may be implemented or used or that it will be appropriate for any specific purpose. + * * + * * Neither the licensor nor any current or former employees, officers, directors, partners, + * * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * * shall be liable for any direct or indirect, special, incidental, consequential or other + * * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * * out of or in connection with (without limitation of any use, misuse, of any ledger system + * * or use made or its functionality or any performance or operation of any code or protocol + * * caused by bugs or programming or logic errors or otherwise); + * * + * * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * * interaction with the Work; + * * + * * B. any failure in a transmission or loss of any token or assets keys or other digital + * * artefacts due to errors in transmission; + * * + * * C. bugs, hacks, logic errors or faults in the Work or any communication; + * * + * * D. system software or apparatus including but not limited to losses caused by errors + * * in holding or transmitting tokens by any third-party; + * * + * * E. breaches or failure of security including hacker attacks, loss or disclosure of + * * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * * + * * F. any losses including loss of anticipated savings or other benefits resulting from + * * use of the Work or any changes to the Work (however implemented). + * * + * * You are solely responsible for; testing, validating and evaluation of all operation + * * logic, functionality, security and appropriateness of using the Work for any commercial + * * or non-commercial purpose and for any reproduction or redistribution by You of the + * * Work. You assume all risks associated with Your use of the Work and the exercise of + * * permissions under this License. + * + */ + +package com.radixdlt.api.service; + +import com.google.inject.Inject; +import com.radixdlt.api.store.ValidatorUptime; +import com.radixdlt.application.system.state.StakeOwnership; +import com.radixdlt.application.system.state.ValidatorBFTData; +import com.radixdlt.application.system.state.ValidatorStakeData; +import com.radixdlt.application.tokens.state.PreparedStake; +import com.radixdlt.application.tokens.state.PreparedUnstakeOwnership; +import com.radixdlt.application.validators.state.AllowDelegationFlag; +import com.radixdlt.application.validators.state.ValidatorFeeCopy; +import com.radixdlt.application.validators.state.ValidatorMetaData; +import com.radixdlt.application.validators.state.ValidatorOwnerCopy; +import com.radixdlt.application.validators.state.ValidatorRegisteredCopy; +import com.radixdlt.atom.SubstateTypeId; +import com.radixdlt.constraintmachine.SubstateIndex; +import com.radixdlt.constraintmachine.SystemMapKey; +import com.radixdlt.crypto.ECPublicKey; +import com.radixdlt.engine.RadixEngine; +import com.radixdlt.identifiers.REAddr; +import com.radixdlt.statecomputer.LedgerAndBFTProof; +import com.radixdlt.utils.UInt256; +import com.radixdlt.utils.UInt384; +import org.bouncycastle.util.Arrays; + +import java.util.HashMap; +import java.util.Map; + +public final class ValidatorInfoService { + private final RadixEngine radixEngine; + + @Inject + public ValidatorInfoService(RadixEngine radixEngine) { + this.radixEngine = radixEngine; + } + + public ValidatorMetaData getMetadata(ECPublicKey validatorKey) { + var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_META_DATA.id(), validatorKey.getCompressedBytes()); + return (ValidatorMetaData) radixEngine.get(validatorDataKey).orElse(ValidatorMetaData.createVirtual(validatorKey)); + } + + public AllowDelegationFlag getAllowDelegationFlag(ECPublicKey validatorKey) { + var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_ALLOW_DELEGATION_FLAG.id(), validatorKey.getCompressedBytes()); + return (AllowDelegationFlag) radixEngine.get(validatorDataKey).orElse(AllowDelegationFlag.createVirtual(validatorKey)); + } + + public ValidatorUptime getUptime(ECPublicKey validatorKey) { + var validatorUptimeKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_BFT_DATA.id(), validatorKey.getCompressedBytes()); + return radixEngine.get(validatorUptimeKey) + .map(ValidatorBFTData.class::cast) + .map(d -> ValidatorUptime.create(d.proposalsCompleted(), d.proposalsMissed())) + .orElse(ValidatorUptime.empty()); + } + + + public ValidatorRegisteredCopy getNextEpochRegisteredFlag(ECPublicKey validatorKey) { + var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_REGISTERED_FLAG_COPY.id(), validatorKey.getCompressedBytes()); + return (ValidatorRegisteredCopy) radixEngine.get(validatorDataKey).orElse(ValidatorRegisteredCopy.createVirtual(validatorKey)); + } + + public ValidatorFeeCopy getNextValidatorFee(ECPublicKey validatorKey) { + var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_RAKE_COPY.id(), validatorKey.getCompressedBytes()); + return (ValidatorFeeCopy) radixEngine.get(validatorDataKey).orElse(ValidatorFeeCopy.createVirtual(validatorKey)); + } + + public ValidatorOwnerCopy getNextEpochValidatorOwner(ECPublicKey validatorKey) { + var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_OWNER_COPY.id(), validatorKey.getCompressedBytes()); + return (ValidatorOwnerCopy) radixEngine.get(validatorDataKey).orElse(ValidatorOwnerCopy.createVirtual(validatorKey)); + } + + + public Map getPreparedStakes(ECPublicKey validatorKey) { + var index = SubstateIndex.create( + Arrays.concatenate(new byte[] {SubstateTypeId.PREPARED_STAKE.id(), 0}, validatorKey.getCompressedBytes()), + PreparedStake.class + ); + return radixEngine.reduceResources(index, PreparedStake::getOwner); + } + + public Map getPreparedOwnershipUnstakes(ECPublicKey validatorKey) { + var index = SubstateIndex.create( + Arrays.concatenate(new byte[] {SubstateTypeId.PREPARED_UNSTAKE.id(), 0}, validatorKey.getCompressedBytes()), + PreparedUnstakeOwnership.class + ); + return radixEngine.reduceResources(index, PreparedUnstakeOwnership::getOwner); + } + + public Map getEstimatedPreparedUnstakes(ValidatorStakeData curData) { + var validatorKey = curData.getValidatorKey(); + var ownershipUnstakes = getPreparedOwnershipUnstakes(validatorKey); + + var curStake = curData.getTotalStake(); + var curOwnership = curData.getTotalOwnership(); + var unstakes = new HashMap(); + for (var e : ownershipUnstakes.entrySet()) { + var unstakeValueEstimate = e.getValue().multiply(curStake).divide(curOwnership).getLow(); + unstakes.put(e.getKey(), unstakeValueEstimate); + curOwnership = curOwnership.subtract(e.getValue().getLow()); + curStake = curStake.subtract(unstakeValueEstimate); + } + return unstakes; + } + + + public Map getEstimatedIndividualStakes(ValidatorStakeData curData) { + var validatorKey = curData.getValidatorKey(); + var index = SubstateIndex.create( + Arrays.concatenate(new byte[] {SubstateTypeId.STAKE_OWNERSHIP.id(), 0}, validatorKey.getCompressedBytes()), + StakeOwnership.class + ); + var stakeReceived = radixEngine.reduceResources(index, StakeOwnership::getOwner); + var stakes = new HashMap(); + stakeReceived.forEach((address, amt) -> stakes.put( + address, amt.multiply(curData.getTotalStake()).divide(curData.getTotalOwnership()).getLow()) + ); + return stakes; + } + + public ValidatorStakeData getValidatorStakeData(ECPublicKey validatorKey) { + var validatorDataKey = SystemMapKey.ofSystem(SubstateTypeId.VALIDATOR_STAKE_DATA.id(), validatorKey.getCompressedBytes()); + return (ValidatorStakeData) radixEngine.get(validatorDataKey).orElse(ValidatorStakeData.createVirtual(validatorKey)); + } +} diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/reducer/NextEpochValidators.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/reducer/NextEpochValidators.java deleted file mode 100644 index fcb2e56cc1..0000000000 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/service/reducer/NextEpochValidators.java +++ /dev/null @@ -1,233 +0,0 @@ -/* Copyright 2021 Radix DLT Ltd incorporated in England. - * - * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at: - * - * radixfoundation.org/licenses/LICENSE-v1 - * - * The Licensor hereby grants permission for the Canonical version of the Work to be - * published, distributed and used under or by reference to the Licensor’s trademark - * Radix ® and use of any unregistered trade names, logos or get-up. - * - * The Licensor provides the Work (and each Contributor provides its Contributions) on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, - * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. - * - * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create - * a distributed ledger it is your responsibility to test and validate the code, together - * with all logic and performance of that code under all foreseeable scenarios. - * - * The Licensor does not make or purport to make and hereby excludes liability for all - * and any representation, warranty or undertaking in any form whatsoever, whether express - * or implied, to any entity or person, including any representation, warranty or - * undertaking, as to the functionality security use, value or other characteristics of - * any distributed ledger nor in respect the functioning or value of any tokens which may - * be created stored or transferred using the Work. The Licensor does not warrant that the - * Work or any use of the Work complies with any law or regulation in any territory where - * it may be implemented or used or that it will be appropriate for any specific purpose. - * - * Neither the licensor nor any current or former employees, officers, directors, partners, - * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor - * shall be liable for any direct or indirect, special, incidental, consequential or other - * losses of any kind, in tort, contract or otherwise (including but not limited to loss - * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss - * of any economic or other opportunity of whatsoever nature or howsoever arising), arising - * out of or in connection with (without limitation of any use, misuse, of any ledger system - * or use made or its functionality or any performance or operation of any code or protocol - * caused by bugs or programming or logic errors or otherwise); - * - * A. any offer, purchase, holding, use, sale, exchange or transmission of any - * cryptographic keys, tokens or assets created, exchanged, stored or arising from any - * interaction with the Work; - * - * B. any failure in a transmission or loss of any token or assets keys or other digital - * artefacts due to errors in transmission; - * - * C. bugs, hacks, logic errors or faults in the Work or any communication; - * - * D. system software or apparatus including but not limited to losses caused by errors - * in holding or transmitting tokens by any third-party; - * - * E. breaches or failure of security including hacker attacks, loss or disclosure of - * password, loss of private key, unauthorised use or misuse of such passwords or keys; - * - * F. any losses including loss of anticipated savings or other benefits resulting from - * use of the Work or any changes to the Work (however implemented). - * - * You are solely responsible for; testing, validating and evaluation of all operation - * logic, functionality, security and appropriateness of using the Work for any commercial - * or non-commercial purpose and for any reproduction or redistribution by You of the - * Work. You assume all risks associated with Your use of the Work and the exercise of - * permissions under this License. - */ - -package com.radixdlt.api.service.reducer; - -import com.radixdlt.api.store.ValidatorUptime; -import com.radixdlt.application.system.state.ValidatorStakeData; -import com.radixdlt.application.tokens.state.PreparedStake; -import com.radixdlt.application.tokens.state.PreparedUnstakeOwnership; -import com.radixdlt.application.validators.state.AllowDelegationFlag; -import com.radixdlt.application.validators.state.ValidatorMetaData; -import com.radixdlt.application.validators.state.ValidatorOwnerCopy; -import com.radixdlt.application.validators.state.ValidatorFeeCopy; -import com.radixdlt.application.validators.state.ValidatorRegisteredCopy; -import com.radixdlt.constraintmachine.Particle; -import com.radixdlt.crypto.ECPublicKey; -import com.radixdlt.identifiers.REAddr; -import com.radixdlt.statecomputer.ValidatorDetails; -import com.radixdlt.utils.UInt256; -import com.radixdlt.utils.UInt384; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static com.radixdlt.utils.functional.FunctionalUtils.mergeAll; - -import static java.util.Optional.ofNullable; - -/** - * Wrapper class for registered validators - */ -public final class NextEpochValidators { - private final Map metadataMap; - private final Map stakeMap; - private final Map stakeOwnershipMap; - private final Map ownersMap; - private final Map delegationFlagsMap; - private final Map feesMap; - private final Set registered; - private Map uptime; - - private NextEpochValidators() { - this.registered = new HashSet<>(); - this.stakeMap = new HashMap<>(); - this.stakeOwnershipMap = new HashMap<>(); - this.ownersMap = new HashMap<>(); - this.delegationFlagsMap = new HashMap<>(); - this.metadataMap = new HashMap<>(); - this.feesMap = new HashMap<>(); - } - - public static NextEpochValidators create() { - return new NextEpochValidators(); - } - - public void process(Map uptime) { - this.uptime = uptime; - } - - public void process(Particle p) { - if (p instanceof ValidatorRegisteredCopy) { - var v = (ValidatorRegisteredCopy) p; - if (!v.isRegistered()) { - registered.remove(v.getValidatorKey()); - } else { - registered.add(v.getValidatorKey()); - } - } else if (p instanceof ValidatorMetaData) { - var s = (ValidatorMetaData) p; - metadataMap.put(s.getValidatorKey(), s); - } else if (p instanceof PreparedStake) { - var s = (PreparedStake) p; - stakeMap.merge(s.getDelegateKey(), s.getAmount(), UInt256::add); - } else if (p instanceof PreparedUnstakeOwnership) { - var s = (PreparedUnstakeOwnership) p; - var totalOwnership = stakeOwnershipMap.get(s.getDelegateKey()); - var totalStake = UInt384.from(stakeMap.get(s.getDelegateKey())); - var stakeRemoved = totalStake.multiply(s.getAmount()).divide(totalOwnership); - stakeMap.put(s.getDelegateKey(), totalStake.subtract(stakeRemoved).getLow()); - stakeOwnershipMap.put(s.getDelegateKey(), totalOwnership.subtract(s.getAmount())); - } else if (p instanceof ValidatorOwnerCopy) { - var s = (ValidatorOwnerCopy) p; - ownersMap.put(s.getValidatorKey(), s.getOwner()); - } else if (p instanceof AllowDelegationFlag) { - var s = (AllowDelegationFlag) p; - delegationFlagsMap.put(s.getValidatorKey(), s.allowsDelegation()); - } else if (p instanceof ValidatorFeeCopy) { - var s = (ValidatorFeeCopy) p; - feesMap.put(s.getValidatorKey(), s.getRakePercentage()); - } else { - var s = (ValidatorStakeData) p; - ownersMap.put(s.getValidatorKey(), s.getOwnerAddr()); - stakeOwnershipMap.put(s.getValidatorKey(), s.getTotalOwnership()); - stakeMap.put(s.getValidatorKey(), s.getAmount()); - if (!s.isRegistered()) { - registered.remove(s.getValidatorKey()); - } else { - registered.add(s.getValidatorKey()); - } - } - } - - public ValidatorMetaData getMetadata(ECPublicKey validatorKey) { - return ofNullable(metadataMap.get(validatorKey)).orElse(ValidatorMetaData.createVirtual(validatorKey)); - } - - public REAddr getOwner(ECPublicKey validatorKey) { - return ofNullable(ownersMap.get(validatorKey)) - .orElse(REAddr.ofPubKeyAccount(validatorKey)); - } - - public UInt256 getStake(ECPublicKey validatorKey) { - return ofNullable(stakeMap.get(validatorKey)) - .orElse(UInt256.ZERO); - } - - public Boolean allowsDelegation(ECPublicKey validatorKey) { - return ofNullable(delegationFlagsMap.get(validatorKey)) - .orElse(Boolean.FALSE); - } - - public UInt256 getOwnerStake(ECPublicKey key) { - return getOwner(key) - .publicKey() - .map(this::getStake) - .orElse(UInt256.ZERO); - } - - public ValidatorUptime getUptime(ECPublicKey key) { - return ofNullable(uptime.get(key)).orElse(ValidatorUptime.empty()); - } - - private int getRake(ECPublicKey validatorKey) { - return ofNullable(feesMap.get(validatorKey)).orElse(0); - } - - public List map(Function mapper) { - return mergeAll( - registered, - metadataMap.keySet(), - stakeMap.keySet(), - ownersMap.keySet(), - delegationFlagsMap.keySet(), - feesMap.keySet() - ).stream() - .map(this::fillDetails) - .map(mapper) - .collect(Collectors.toList()); - } - - public long count() { - return registered.size(); - } - - private ValidatorDetails fillDetails(ECPublicKey validatorKey) { - return ValidatorDetails.fromParticle( - getMetadata(validatorKey), - getOwner(validatorKey), - getStake(validatorKey), - getOwnerStake(validatorKey), - allowsDelegation(validatorKey), - registered.contains(validatorKey), - getRake(validatorKey), - getUptime(validatorKey) - ); - } -} diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/store/berkeley/BerkeleyValidatorUptimeArchiveStore.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/store/berkeley/BerkeleyValidatorUptimeArchiveStore.java index 06ab2b3ead..49d6e2bc2c 100644 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/store/berkeley/BerkeleyValidatorUptimeArchiveStore.java +++ b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/api/store/berkeley/BerkeleyValidatorUptimeArchiveStore.java @@ -118,6 +118,31 @@ private void store(Transaction dbTxn, ValidatorBFTData validatorBFTData) { validatorUptime.put(dbTxn, key, value); } + public ValidatorUptime getUptimeTwoWeeks(ECPublicKey validatorKey) { + var lastEpoch = curEpoch.get(); + long epochStart = Math.max(curEpoch.get() - EPOCH_WINDOW_LENGTH, 0); + + var uptime = ValidatorUptime.empty(); + for (var epoch = epochStart; epoch <= lastEpoch; epoch++) { + var buf = ByteBuffer.allocate(Long.BYTES + ECPublicKey.COMPRESSED_BYTES); + buf.putLong(epoch); + buf.put(validatorKey.getCompressedBytes()); + var key = new DatabaseEntry(buf.array()); + var value = new DatabaseEntry(); + + var status = validatorUptime.get(null, key, value, null); + if (status == OperationStatus.SUCCESS) { + var valueBuf = ByteBuffer.wrap(value.getData()); + var proposalsCompleted = valueBuf.getLong(); + var proposalsMissed = valueBuf.getLong(); + var nextUptime = ValidatorUptime.create(proposalsCompleted, proposalsMissed); + uptime = uptime.merge(nextUptime); + } + } + + return uptime; + } + public Map getUptimeTwoWeeks() { var map = new HashMap(); long epochStart = Math.max(curEpoch.get() - EPOCH_WINDOW_LENGTH, 0); diff --git a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/statecomputer/ValidatorDetails.java b/radixdlt-core/radixdlt/src/main/java/com/radixdlt/statecomputer/ValidatorDetails.java deleted file mode 100644 index b3d70247cf..0000000000 --- a/radixdlt-core/radixdlt/src/main/java/com/radixdlt/statecomputer/ValidatorDetails.java +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright 2021 Radix DLT Ltd incorporated in England. - * - * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at: - * - * radixfoundation.org/licenses/LICENSE-v1 - * - * The Licensor hereby grants permission for the Canonical version of the Work to be - * published, distributed and used under or by reference to the Licensor’s trademark - * Radix ® and use of any unregistered trade names, logos or get-up. - * - * The Licensor provides the Work (and each Contributor provides its Contributions) on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, - * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. - * - * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create - * a distributed ledger it is your responsibility to test and validate the code, together - * with all logic and performance of that code under all foreseeable scenarios. - * - * The Licensor does not make or purport to make and hereby excludes liability for all - * and any representation, warranty or undertaking in any form whatsoever, whether express - * or implied, to any entity or person, including any representation, warranty or - * undertaking, as to the functionality security use, value or other characteristics of - * any distributed ledger nor in respect the functioning or value of any tokens which may - * be created stored or transferred using the Work. The Licensor does not warrant that the - * Work or any use of the Work complies with any law or regulation in any territory where - * it may be implemented or used or that it will be appropriate for any specific purpose. - * - * Neither the licensor nor any current or former employees, officers, directors, partners, - * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor - * shall be liable for any direct or indirect, special, incidental, consequential or other - * losses of any kind, in tort, contract or otherwise (including but not limited to loss - * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss - * of any economic or other opportunity of whatsoever nature or howsoever arising), arising - * out of or in connection with (without limitation of any use, misuse, of any ledger system - * or use made or its functionality or any performance or operation of any code or protocol - * caused by bugs or programming or logic errors or otherwise); - * - * A. any offer, purchase, holding, use, sale, exchange or transmission of any - * cryptographic keys, tokens or assets created, exchanged, stored or arising from any - * interaction with the Work; - * - * B. any failure in a transmission or loss of any token or assets keys or other digital - * artefacts due to errors in transmission; - * - * C. bugs, hacks, logic errors or faults in the Work or any communication; - * - * D. system software or apparatus including but not limited to losses caused by errors - * in holding or transmitting tokens by any third-party; - * - * E. breaches or failure of security including hacker attacks, loss or disclosure of - * password, loss of private key, unauthorised use or misuse of such passwords or keys; - * - * F. any losses including loss of anticipated savings or other benefits resulting from - * use of the Work or any changes to the Work (however implemented). - * - * You are solely responsible for; testing, validating and evaluation of all operation - * logic, functionality, security and appropriateness of using the Work for any commercial - * or non-commercial purpose and for any reproduction or redistribution by You of the - * Work. You assume all risks associated with Your use of the Work and the exercise of - * permissions under this License. - */ - -package com.radixdlt.statecomputer; - -import com.radixdlt.api.store.ValidatorUptime; -import com.radixdlt.application.validators.state.ValidatorMetaData; -import com.radixdlt.crypto.ECPublicKey; -import com.radixdlt.identifiers.REAddr; -import com.radixdlt.utils.UInt256; - -public final class ValidatorDetails { - private final ECPublicKey key; - private final REAddr owner; - private final String name; - private final String url; - private final UInt256 stake; - private final UInt256 ownerStake; - private final boolean allowDelegation; - private final boolean registered; - private final int percentage; - private final ValidatorUptime uptime; - - private ValidatorDetails( - ECPublicKey key, REAddr owner, String name, String url, UInt256 stake, - UInt256 ownerStake, boolean allowDelegation, boolean registered, int percentage, - ValidatorUptime uptime - ) { - this.key = key; - this.name = name; - this.owner = owner; - this.url = url; - this.stake = stake; - this.ownerStake = ownerStake; - this.allowDelegation = allowDelegation; - this.registered = registered; - this.percentage = percentage; - this.uptime = uptime; - } - - public static ValidatorDetails fromParticle( - ValidatorMetaData metaData, REAddr owner, UInt256 stake, - UInt256 ownerStake, boolean allowDelegation, boolean registered, int percentage, - ValidatorUptime uptime - ) { - return new ValidatorDetails( - metaData.getValidatorKey(), owner, metaData.getName(), metaData.getUrl(), - stake, ownerStake, allowDelegation, registered, percentage, - uptime - ); - } - - public REAddr getOwner() { - return owner; - } - - public ECPublicKey getKey() { - return key; - } - - public String getName() { - return name; - } - - public String getUrl() { - return url; - } - - public UInt256 getStake() { - return stake; - } - - public UInt256 getOwnerStake() { - return ownerStake; - } - - public boolean allowsDelegation() { - return allowDelegation; - } - - public int getPercentage() { - return percentage; - } - - public boolean registered() { - return registered; - } - - public ValidatorUptime getUptime() { - return uptime; - } -} diff --git a/radixdlt-core/radixdlt/src/test/java/com/radixdlt/api/handler/ArchiveValidationHandlerTest.java b/radixdlt-core/radixdlt/src/test/java/com/radixdlt/api/handler/ArchiveValidationHandlerTest.java index 2def3bb772..40cebec7ce 100644 --- a/radixdlt-core/radixdlt/src/test/java/com/radixdlt/api/handler/ArchiveValidationHandlerTest.java +++ b/radixdlt-core/radixdlt/src/test/java/com/radixdlt/api/handler/ArchiveValidationHandlerTest.java @@ -181,46 +181,6 @@ public void testValidatorsNamed() { assertEquals("v3", list.getJSONObject(2).get("name")); } - @Test - public void testLookupValidatorPositional() { - when(validatorInfoService.getValidator(eq(V1))) - .thenReturn(Result.ok(createValidator(V1, "v1", UInt256.FIVE))); - - var params = jsonArray().put(addressing.forValidators().of(V1)); - var response = handler.handleValidatorsLookupValidator(requestWith(params)); - - assertNotNull(response); - assertTrue(response.has("result")); - - var result = response.getJSONObject("result"); - - assertNotNull(result); - - assertEquals(UInt256.FIVE, result.get("totalDelegatedStake")); - assertEquals("http://v1.com", result.get("infoURL")); - assertEquals("v1", result.get("name")); - } - - @Test - public void testLookupValidatorNamed() { - when(validatorInfoService.getValidator(eq(V1))) - .thenReturn(Result.ok(createValidator(V1, "v1", UInt256.FIVE))); - - var params = jsonObject().put("validatorAddress", addressing.forValidators().of(V1)); - var response = handler.handleValidatorsLookupValidator(requestWith(params)); - - assertNotNull(response); - assertTrue(response.has("result")); - - var result = response.getJSONObject("result"); - - assertNotNull(result); - - assertEquals(UInt256.FIVE, result.get("totalDelegatedStake")); - assertEquals("http://v1.com", result.get("infoURL")); - assertEquals("v1", result.get("name")); - } - private ValidatorInfoDetails createValidator(ECPublicKey v1, String name, UInt256 stake) { return ValidatorInfoDetails.create( v1, REAddr.ofPubKeyAccount(v1),