diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/ConstitutionQuery.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/ConstitutionQuery.java new file mode 100644 index 00000000..378718af --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/ConstitutionQuery.java @@ -0,0 +1,50 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries; + +import co.nstant.in.cbor.model.Array; +import co.nstant.in.cbor.model.DataItem; +import co.nstant.in.cbor.model.UnsignedInteger; +import com.bloxbean.cardano.yaci.core.model.governance.Anchor; +import com.bloxbean.cardano.yaci.core.model.serializers.governance.AnchorSerializer; +import com.bloxbean.cardano.yaci.core.protocol.handshake.messages.AcceptVersion; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.Era; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.EraQuery; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; +import lombok.ToString; + +import java.util.List; + +@Getter +@AllArgsConstructor +@ToString +// ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Query.hs +public class ConstitutionQuery implements EraQuery { + @NonNull + private Era era; + + public ConstitutionQuery() { + this.era = Era.Conway; + } + + @Override + public DataItem serialize(AcceptVersion protocolVersion) { + Array queryArray = new Array(); + queryArray.add(new UnsignedInteger(23)); + + return wrapWithOuterArray(queryArray); + } + + @Override + public ConstitutionResult deserializeResult(AcceptVersion protocolVersion, DataItem[] di) { + List dataItemList = ((Array)di[0]).getDataItems(); + + int type = ((UnsignedInteger)dataItemList.get(0)).getValue().intValue(); //4 + + List resultDIList = ((Array)dataItemList.get(1)).getDataItems(); + var items = (Array)resultDIList.get(0); + + Anchor anchor = AnchorSerializer.INSTANCE.deserializeDI(items.getDataItems().get(0)); + return new ConstitutionResult(anchor); + } +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/ConstitutionResult.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/ConstitutionResult.java new file mode 100644 index 00000000..812f592d --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/ConstitutionResult.java @@ -0,0 +1,14 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries; + +import com.bloxbean.cardano.yaci.core.model.governance.Anchor; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.QueryResult; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +@Getter +@AllArgsConstructor +@ToString +public class ConstitutionResult implements QueryResult { + private Anchor anchor; +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/DRepStateQuery.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/DRepStateQuery.java new file mode 100644 index 00000000..2b8ac432 --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/DRepStateQuery.java @@ -0,0 +1,88 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries; + + +import co.nstant.in.cbor.model.Array; +import co.nstant.in.cbor.model.DataItem; +import co.nstant.in.cbor.model.Map; +import co.nstant.in.cbor.model.UnsignedInteger; +import com.bloxbean.cardano.yaci.core.model.Credential; +import com.bloxbean.cardano.yaci.core.model.governance.Anchor; +import com.bloxbean.cardano.yaci.core.model.serializers.governance.AnchorSerializer; +import com.bloxbean.cardano.yaci.core.protocol.handshake.messages.AcceptVersion; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.Era; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.EraQuery; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.DRepState; +import com.bloxbean.cardano.yaci.core.util.CborSerializationUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +@Getter +@AllArgsConstructor +public class DRepStateQuery implements EraQuery { + private Era era; + private List dRepCreds; + + public DRepStateQuery(List dRepCreds) { + this(Era.Conway, dRepCreds); + } + + @Override + public DataItem serialize(AcceptVersion protocolVersion) { + Array array = new Array(); + array.add(new UnsignedInteger(25)); + + Array dRepCredArray = new Array(); + + dRepCreds.forEach(dRepCred -> dRepCredArray.add(dRepCred.serialize())); + + dRepCredArray.setTag(258); + + array.add(dRepCredArray); + + return wrapWithOuterArray(array); + } + + @Override + public DRepStateQueryResult deserializeResult(AcceptVersion protocolVersion, DataItem[] di) { + DRepStateQueryResult result = new DRepStateQueryResult(); + var array = (Array) di[0]; + var drepStateArray = (Array) array.getDataItems().get(1); + + for (var dataItem : drepStateArray.getDataItems()) { + var map = (Map)dataItem; + var keys = (List)map.getKeys(); + + if (keys.isEmpty()) { + continue; + } + for (var key : keys) { + var itemDI = (Array)key; + String dRepHash = CborSerializationUtil.toHex(itemDI.getDataItems().get(1)); + var value = (Array) map.get(itemDI); + Integer expiry = CborSerializationUtil.toInt(value.getDataItems().get(0)); + + Anchor anchor = null; + if (((Array) value.getDataItems().get(1)).getDataItems().size() > 0) { + anchor = AnchorSerializer.INSTANCE.deserializeDI(((Array)value.getDataItems().get(1)).getDataItems().get(0)); + } + + BigInteger deposit = CborSerializationUtil.toBigInteger(value.getDataItems().get(2)); + + var dRepState = DRepState.builder() + .dRepHash(dRepHash) + .anchor(anchor) + .deposit(deposit) + .expiry(expiry) + .build(); + + result.addDRepState(dRepState); + } + } + + return result; + } +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/DRepStateQueryResult.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/DRepStateQueryResult.java new file mode 100644 index 00000000..fd63e5ea --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/DRepStateQueryResult.java @@ -0,0 +1,23 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries; + +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.QueryResult; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.DRepState; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Setter +@Getter +public class DRepStateQueryResult implements QueryResult { + List dRepStates; + + public DRepStateQueryResult() { + this.dRepStates = new ArrayList<>(); + } + + public void addDRepState(DRepState dRepState) { + dRepStates.add(dRepState); + } +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/GovStateQuery.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/GovStateQuery.java new file mode 100644 index 00000000..d09bfdc5 --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/GovStateQuery.java @@ -0,0 +1,591 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries; + +import co.nstant.in.cbor.model.*; +import com.bloxbean.cardano.client.util.Tuple; +import com.bloxbean.cardano.yaci.core.model.Credential; +import com.bloxbean.cardano.yaci.core.model.DrepVoteThresholds; +import com.bloxbean.cardano.yaci.core.model.PoolVotingThresholds; +import com.bloxbean.cardano.yaci.core.model.ProtocolParamUpdate; +import com.bloxbean.cardano.yaci.core.model.certs.StakeCredType; +import com.bloxbean.cardano.yaci.core.model.certs.StakePoolId; +import com.bloxbean.cardano.yaci.core.model.governance.*; +import com.bloxbean.cardano.yaci.core.model.serializers.governance.AnchorSerializer; +import com.bloxbean.cardano.yaci.core.protocol.handshake.messages.AcceptVersion; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.Era; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.EraQuery; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.EnactState; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.Proposal; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.ProposalType; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.RatifyState; +import com.bloxbean.cardano.yaci.core.util.CborSerializationUtil; +import com.bloxbean.cardano.yaci.core.util.HexUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; + +import static com.bloxbean.cardano.yaci.core.util.CborSerializationUtil.*; + +@Getter +@AllArgsConstructor +@ToString +public class GovStateQuery implements EraQuery { + private Era era; + + public GovStateQuery() { + this.era = Era.Conway; + } + + @Override + public DataItem serialize(AcceptVersion protocolVersion) { + Array queryArray = new Array(); + queryArray.add(new UnsignedInteger(24)); + + return wrapWithOuterArray(queryArray); + } + + @Override + public GovStateResult deserializeResult(AcceptVersion protocolVersion, DataItem[] di) { + GovStateResult govStateResult = new GovStateResult(); + Array array = (Array) di[0]; + Array resultArray = (Array) ((Array) array.getDataItems().get(1)).getDataItems().get(0); + + // committee + Array committeeResult = (Array) resultArray.getDataItems().get(1); + Array committeeDI = (Array) committeeResult.getDataItems().get(0); + Committee committee = deserializeCommitteeResult(committeeDI.getDataItems()); + govStateResult.setCommittee(committee); + + // constitution + Array constitutionArr = (Array) resultArray.getDataItems().get(2); + var constitutionDI = constitutionArr.getDataItems().get(0); + + Constitution constitution = deserializeConstitutionResult(constitutionDI); + govStateResult.setConstitution(constitution); + + // current protocol params + Array currentPParams = (Array) resultArray.getDataItems().get(3); + List paramsDIList = currentPParams.getDataItems(); + + ProtocolParamUpdate currentProtocolParam = deserializePPResult(paramsDIList); + + govStateResult.setCurrentPParams(currentProtocolParam); + + Array futurePParams = (Array) resultArray.getDataItems().get(5); + if (!futurePParams.getDataItems().isEmpty() && futurePParams.getDataItems().size() > 1) { + List futureParamsDIList = ((Array)futurePParams.getDataItems().get(1)).getDataItems(); + ProtocolParamUpdate futureProtocolParam = deserializePPResult(futureParamsDIList); + govStateResult.setFuturePParams(futureProtocolParam); + } + + // next ratify state + Array nextRatifyStateDI = (Array) ((Array)resultArray.getDataItems().get(6)).getDataItems().get(1); + + // next ratify state - enacted gov actions + List enactedProposals = new ArrayList<>(); + Array enactedProposalArr = (Array) nextRatifyStateDI.getDataItems().get(1); + for (var proposalDI : enactedProposalArr.getDataItems()) { + Proposal enactedProposal = deserializeProposalResult(proposalDI); + enactedProposals.add(enactedProposal); + } + + // next ratify state - expired gov actions + List expiredGovActions = deserializeGovActionIdListResult(nextRatifyStateDI.getDataItems().get(2)); + + // next ratify state - next enact state + var nextEnactStateDI = (Array)nextRatifyStateDI.getDataItems().get(0); + + // next enact state - committee + var nextEnactStateCommitteeArr = (Array) nextEnactStateDI.getDataItems().get(0); + Committee nextEnactStateCommittee = deserializeCommitteeResult( + ((Array)nextEnactStateCommitteeArr.getDataItems().get(0)).getDataItems()); + + // next enact state - constitution + var nextEnactStateConstitutionArr = (Array)nextEnactStateDI.getDataItems().get(1); + Constitution nextEnactStateConstitution = deserializeConstitutionResult(nextEnactStateConstitutionArr.getDataItems().get(0)); + + // next enact state - current protocol params + ProtocolParamUpdate nextEnactStateCurrentPParams = deserializePPResult( + ((Array)nextEnactStateDI.getDataItems().get(2)).getDataItems()); + // next enact state - prev protocol params + ProtocolParamUpdate nextEnactStatePrevPParams = deserializePPResult( + ((Array)nextEnactStateDI.getDataItems().get(3)).getDataItems()); + // next enact state - Prev govActionIds + java.util.Map prevGovActionIds = new HashMap<>(); + Array nextEnactStatePrevGovActionIds = (Array) nextEnactStateDI.getDataItems().get(6); + + prevGovActionIds.put(ProposalType.COMMITTEE, + deserializeGovActionIdListResult(nextEnactStatePrevGovActionIds.getDataItems().get(0)) + .stream() + .findFirst() + .orElse(null)); + + prevGovActionIds.put(ProposalType.HARD_FORK, + deserializeGovActionIdListResult(nextEnactStatePrevGovActionIds.getDataItems().get(1)) + .stream() + .findFirst() + .orElse(null)); + + prevGovActionIds.put(ProposalType.CONSTITUTION, + deserializeGovActionIdListResult(nextEnactStatePrevGovActionIds.getDataItems().get(1)) + .stream() + .findFirst() + .orElse(null)); + + prevGovActionIds.put(ProposalType.P_PARAM_UPDATE, + deserializeGovActionIdListResult(nextEnactStatePrevGovActionIds.getDataItems().get(1)) + .stream() + .findFirst() + .orElse(null)); + + // next ratify state - ratificationDelayed + var ratificationDelayedDI = nextRatifyStateDI.getDataItems().get(3); + Boolean ratificationDelayed = ratificationDelayedDI != null ? + (((SimpleValue) ratificationDelayedDI).getValue() == SimpleValueType.FALSE.getValue() ? Boolean.FALSE : Boolean.TRUE) + : null; + + RatifyState nextRatifyState = RatifyState.builder() + .ratificationDelayed(ratificationDelayed) + .nextEnactState(EnactState.builder() + .committee(nextEnactStateCommittee) + .constitution(nextEnactStateConstitution) + .currentPParams(nextEnactStateCurrentPParams) + .prevGovActionIds(prevGovActionIds) + .prevPParams(nextEnactStatePrevPParams) + .build()) + .enactedGovActions(enactedProposals) + .expiredGovActions(expiredGovActions) + .build(); + + govStateResult.setNextRatifyState(nextRatifyState); + + // previous protocol params + Array prevPParams = (Array) resultArray.getDataItems().get(4); + paramsDIList = prevPParams.getDataItems(); + ProtocolParamUpdate prevProtocolParam = deserializePPResult(paramsDIList); + + govStateResult.setPreviousPParams(prevProtocolParam); + + // proposals + Array proposalArr = (Array)((Array) resultArray.getDataItems().get(0)).getDataItems().get(1); + + List proposals = new ArrayList<>(); + for (DataItem item : proposalArr.getDataItems()) { + if (item == SimpleValue.BREAK) { + continue; + } + Proposal proposal = deserializeProposalResult(item); + proposals.add(proposal); + } + + govStateResult.setProposals(proposals); + + return govStateResult; + } + + public ProtocolParamUpdate deserializePPResult(List paramsDIList) { + if (paramsDIList.isEmpty()) { + return null; + } + + DataItem itemDI = paramsDIList.get(0); + Integer minFeeA = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(1); + Integer minFeeB = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(2); + Integer maxBlockSize = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(3); + Integer maxTxSize = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(4); + Integer maxBlockHeaderSize = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(5); + BigInteger keyDeposit = itemDI != null ? toBigInteger(itemDI) : null; + + itemDI = paramsDIList.get(6); + BigInteger poolDeposit = itemDI != null ? toBigInteger(itemDI) : null; + + itemDI = paramsDIList.get(7); + Integer maxEpoch = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(8); + Integer nOpt = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(9); + BigDecimal poolPledgeInfluence = itemDI != null ? toRationalNumber(itemDI) : null; + + itemDI = paramsDIList.get(10); + BigDecimal expansionRate = itemDI != null ? toRationalNumber(itemDI) : null; + + itemDI = paramsDIList.get(11); + BigDecimal treasuryGrowthRate = itemDI != null ? toRationalNumber(itemDI) : null; + + Integer protocolMajorVersion = null; + Integer protocolMinorVersion = null; + itemDI = paramsDIList.get(12); + if (itemDI != null) { + List protocolVersions = ((Array) itemDI).getDataItems(); + protocolMajorVersion = toInt(protocolVersions.get(0)); + protocolMinorVersion = toInt(protocolVersions.get(1)); + } + + itemDI = paramsDIList.get(13); + BigInteger minPoolCost = itemDI != null ? toBigInteger(itemDI) : null; + + itemDI = paramsDIList.get(14); + BigInteger adaPerUtxoBytes = itemDI != null ? toBigInteger(itemDI) : null; + + //CostModels + java.util.Map costModelMap = null; + itemDI = paramsDIList.get(15); + if (itemDI != null) { + costModelMap = new LinkedHashMap<>(); + Map itemDIMap = (Map) itemDI; + for (DataItem key : itemDIMap.getKeys()) { + Integer version = toInt(key); + String costModel = HexUtil.encodeHexString(CborSerializationUtil.serialize(itemDIMap.get(key))); + costModelMap.put(version, costModel); + } + } + + //exUnits prices + BigDecimal priceMem = null; + BigDecimal priceSteps = null; + itemDI = paramsDIList.get(16); + if (itemDI != null) { + List exUnitPriceList = ((Array) itemDI).getDataItems(); + Tuple tuple = getExUnitPrices(exUnitPriceList); + priceMem = tuple._1; + priceSteps = tuple._2; + } + + //max tx exunits + BigInteger maxTxExMem = null; + BigInteger maxTxExSteps = null; + itemDI = paramsDIList.get(17); + if (itemDI != null) { + List exUnits = ((Array) itemDI).getDataItems(); + Tuple tuple = getExUnits(exUnits); + maxTxExMem = tuple._1; + maxTxExSteps = tuple._2; + } + + //max block exunits + BigInteger maxBlockExMem = null; + BigInteger maxBlockExSteps = null; + itemDI = paramsDIList.get(18); + if (itemDI != null) { + List exUnits = ((Array) itemDI).getDataItems(); + Tuple tuple = getExUnits(exUnits); + maxBlockExMem = tuple._1; + maxBlockExSteps = tuple._2; + } + + itemDI = paramsDIList.get(19); + Long maxValueSize = itemDI != null ? toLong(itemDI) : null; + + itemDI = paramsDIList.get(20); + Integer collateralPercent = itemDI != null ? toInt(itemDI) : null; + + Integer maxCollateralInputs = null; + itemDI = paramsDIList.get(21); + maxCollateralInputs = itemDI != null ? toInt(itemDI) : null; + + //Pool Voting Threshold + itemDI = paramsDIList.get(22); + BigDecimal motionNoConfidence = null; + BigDecimal committeeNormal = null; + BigDecimal committeeNoConfidence = null; + BigDecimal hardForkInitiation = null; + BigDecimal ppSecurityGroup = null; + if (itemDI != null) { + List poolVotingThresholdList = ((Array) itemDI).getDataItems(); + if (poolVotingThresholdList.size() != 5) + throw new IllegalStateException("Invalid pool voting threshold list"); + + var pvtMotionNoConfidenceDI = (RationalNumber) poolVotingThresholdList.get(0); + var pvtCommitteeNormalDI = (RationalNumber) poolVotingThresholdList.get(1); + var pvtCommitteeNoConfidenceDI = (RationalNumber) poolVotingThresholdList.get(2); + var pvtHardForkInitiationDI = (RationalNumber) poolVotingThresholdList.get(3); + var pvtPPSecurityGroupDI = (RationalNumber) poolVotingThresholdList.get(4); + + motionNoConfidence = toRationalNumber(pvtMotionNoConfidenceDI); + committeeNormal = toRationalNumber(pvtCommitteeNormalDI); + committeeNoConfidence = toRationalNumber(pvtCommitteeNoConfidenceDI); + hardForkInitiation = toRationalNumber(pvtHardForkInitiationDI); + ppSecurityGroup = toRationalNumber(pvtPPSecurityGroupDI); + } + + //DRep voting thresholds + itemDI = paramsDIList.get(23); + BigDecimal dvtMotionNoConfidence = null; + BigDecimal dvtCommitteeNormal = null; + BigDecimal dvtCommitteeNoConfidence = null; + BigDecimal dvtUpdateToConstitution = null; + BigDecimal dvtHardForkInitiation = null; + BigDecimal dvtPPNetworkGroup = null; + BigDecimal dvtPPEconomicGroup = null; + BigDecimal dvtPPTechnicalGroup = null; + BigDecimal dvtPPGovGroup = null; + BigDecimal dvtTreasuryWithdrawal = null; + + if (itemDI != null) { + List dRepVotingThresholdList = ((Array) itemDI).getDataItems(); + if (dRepVotingThresholdList.size() != 10) + throw new IllegalStateException("Invalid dRep voting threshold list"); + + var dvtMotionNoConfidenceDI = (RationalNumber) dRepVotingThresholdList.get(0); + var dvtCommitteeNormalDI = (RationalNumber) dRepVotingThresholdList.get(1); + var dvtCommitteeNoConfidenceDI = (RationalNumber) dRepVotingThresholdList.get(2); + var dvtUpdateToConstitutionDI = (RationalNumber) dRepVotingThresholdList.get(3); + var dvtHardForkInitiationDI = (RationalNumber) dRepVotingThresholdList.get(4); + var dvtPPNetworkGroupDI = (RationalNumber) dRepVotingThresholdList.get(5); + var dvtPPEconomicGroupDI = (RationalNumber) dRepVotingThresholdList.get(6); + var dvtPPTechnicalGroupDI = (RationalNumber) dRepVotingThresholdList.get(7); + var dvtPPGovGroupDI = (RationalNumber) dRepVotingThresholdList.get(8); + var dvtTreasuryWithdrawalDI = (RationalNumber) dRepVotingThresholdList.get(9); + + dvtMotionNoConfidence = toRationalNumber(dvtMotionNoConfidenceDI); + dvtCommitteeNormal = toRationalNumber(dvtCommitteeNormalDI); + dvtCommitteeNoConfidence = toRationalNumber(dvtCommitteeNoConfidenceDI); + dvtUpdateToConstitution = toRationalNumber(dvtUpdateToConstitutionDI); + dvtHardForkInitiation = toRationalNumber(dvtHardForkInitiationDI); + dvtPPNetworkGroup = toRationalNumber(dvtPPNetworkGroupDI); + dvtPPEconomicGroup = toRationalNumber(dvtPPEconomicGroupDI); + dvtPPTechnicalGroup = toRationalNumber(dvtPPTechnicalGroupDI); + dvtPPGovGroup = toRationalNumber(dvtPPGovGroupDI); + dvtTreasuryWithdrawal = toRationalNumber(dvtTreasuryWithdrawalDI); + } + + itemDI = paramsDIList.get(24); + Integer minCommitteeSize = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(25); + Integer committeeTermLimit = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(26); + Integer governanceActionValidityPeriod = itemDI != null ? toInt(itemDI) : null; + + itemDI = paramsDIList.get(27); + BigInteger governanceActionDeposit = itemDI != null ? toBigInteger(itemDI) : null; + + itemDI = paramsDIList.get(28); + BigInteger drepDeposit = itemDI != null ? toBigInteger(itemDI) : null; + + itemDI = paramsDIList.get(29); + Integer drepInactivityPeriod = itemDI != null ? toInt(itemDI) : null; + + BigDecimal minFeeRefScriptCostPerByte = null; //TODO -- Remove if condition once this is available in the node release + if (paramsDIList.size() > 30) { + itemDI = paramsDIList.get(30); + minFeeRefScriptCostPerByte = itemDI != null ? toRationalNumber(itemDI) : null; + } + + return ProtocolParamUpdate.builder() + .minFeeA(minFeeA) + .minFeeB(minFeeB) + .maxBlockSize(maxBlockSize) + .maxTxSize(maxTxSize) + .maxBlockHeaderSize(maxBlockHeaderSize) + .keyDeposit(keyDeposit) + .poolDeposit(poolDeposit) + .maxEpoch(maxEpoch) + .nOpt(nOpt) + .poolPledgeInfluence(poolPledgeInfluence) + .expansionRate(expansionRate) + .treasuryGrowthRate(treasuryGrowthRate) + .protocolMajorVer(protocolMajorVersion) + .protocolMinorVer(protocolMinorVersion) + .minPoolCost(minPoolCost) + .adaPerUtxoByte(adaPerUtxoBytes) + .costModels(costModelMap) + .priceMem(priceMem) + .priceStep(priceSteps) + .maxTxExMem(maxTxExMem) + .maxTxExSteps(maxTxExSteps) + .maxBlockExMem(maxBlockExMem) + .maxBlockExSteps(maxBlockExSteps) + .maxValSize(maxValueSize) + .collateralPercent(collateralPercent) + .maxCollateralInputs(maxCollateralInputs) + .poolVotingThresholds(PoolVotingThresholds.builder() + .pvtMotionNoConfidence(motionNoConfidence) + .pvtCommitteeNormal(committeeNormal) + .pvtCommitteeNoConfidence(committeeNoConfidence) + .pvtHardForkInitiation(hardForkInitiation) + .pvtPPSecurityGroup(ppSecurityGroup) + .build()) + .drepVotingThresholds(DrepVoteThresholds.builder() + .dvtMotionNoConfidence(dvtMotionNoConfidence) + .dvtCommitteeNormal(dvtCommitteeNormal) + .dvtCommitteeNoConfidence(dvtCommitteeNoConfidence) + .dvtUpdateToConstitution(dvtUpdateToConstitution) + .dvtHardForkInitiation(dvtHardForkInitiation) + .dvtPPNetworkGroup(dvtPPNetworkGroup) + .dvtPPEconomicGroup(dvtPPEconomicGroup) + .dvtPPTechnicalGroup(dvtPPTechnicalGroup) + .dvtPPGovGroup(dvtPPGovGroup) + .dvtTreasuryWithdrawal(dvtTreasuryWithdrawal) + .build()) + .committeeMinSize(minCommitteeSize) + .committeeMaxTermLength(committeeTermLimit) + .govActionLifetime(governanceActionValidityPeriod) + .govActionDeposit(governanceActionDeposit) + .drepDeposit(drepDeposit) + .drepActivity(drepInactivityPeriod) + .minFeeRefScriptCostPerByte(minFeeRefScriptCostPerByte) + .build(); + } + + private Tuple getExUnits(List exunits) { + BigInteger mem = toBigInteger(exunits.get(0)); + + BigInteger steps = null; + if (exunits.size() > 1) + steps = toBigInteger(exunits.get(1)); + + return new Tuple<>(mem, steps); + } + + private Tuple getExUnitPrices(List exunits) { + RationalNumber memPriceRN = (RationalNumber) exunits.get(0); + RationalNumber stepPriceRN = (RationalNumber) exunits.get(1); + + BigDecimal memPrice = toRationalNumber(memPriceRN); + BigDecimal stepPrice = toRationalNumber(stepPriceRN); + + return new Tuple<>(memPrice, stepPrice); + } + + public Committee deserializeCommitteeResult(List committeeDIList) { + var committeeMapDI = (Map) committeeDIList.get(0); + java.util.Map committeeColdCredentialEpoch = new LinkedHashMap<>(); + + for (DataItem di : committeeMapDI.getKeys()) { + var key = (Array) di; + int credType = toInt(key.getDataItems().get(0)); + String credentialHash = HexUtil.encodeHexString(((ByteString)key.getDataItems().get(1)).getBytes()); + Credential credential = Credential.builder() + .type(credType == 1 ? StakeCredType.SCRIPTHASH: StakeCredType.ADDR_KEYHASH) + .hash(credentialHash) + .build(); + var expiredEpochDI = committeeMapDI.get(key); + committeeColdCredentialEpoch.put(credential, toLong(expiredEpochDI)); + } + + var committeeThresholdDI = (RationalNumber) committeeDIList.get(1); + BigDecimal committeeThreshold = toRationalNumber(committeeThresholdDI); + + return Committee.builder() + .committeeColdCredentialEpoch(committeeColdCredentialEpoch) + .threshold(committeeThreshold) + .build(); + } + + public List deserializeGovActionIdListResult(DataItem govActionsDI) { + List govActionIds = new ArrayList<>(); + + Array govActionsArray = (Array) govActionsDI; + for (DataItem item : govActionsArray.getDataItems()) { + govActionIds.add(deserializeGovActionIdResult(item)); + } + + return govActionIds; + } + + public GovActionId deserializeGovActionIdResult(DataItem govActionId) { + Array govActionIdDI = (Array) govActionId; + + if (govActionIdDI.getDataItems().isEmpty()) { + return null; + } + + return GovActionId.builder() + .transactionId(HexUtil.encodeHexString(((ByteString) govActionIdDI.getDataItems().get(0)).getBytes())) + .gov_action_index(toInt(govActionIdDI.getDataItems().get(1))) + .build(); + } + + public Constitution deserializeConstitutionResult(DataItem constitutionDI) { + Anchor anchor = AnchorSerializer.INSTANCE.deserializeDI(constitutionDI); + return Constitution.builder().anchor(anchor).build(); + } + + public Proposal deserializeProposalResult(DataItem proposalDI) { + Array proposalArray = (Array) proposalDI; + GovActionId govActionId = deserializeGovActionIdResult(proposalArray.getDataItems().get(0)); + + var proposalProcedureDI = (Array) proposalArray.getDataItems().get(4); + + ProposalProcedure proposalProcedure = ProposalProcedure.builder() + .anchor(AnchorSerializer.INSTANCE.deserializeDI(proposalProcedureDI.getDataItems().get(3))) + .rewardAccount(HexUtil.encodeHexString(((ByteString) proposalProcedureDI.getDataItems().get(1)).getBytes())) + // TODO: 'govAction' field + .deposit(toBigInteger(proposalProcedureDI.getDataItems().get(0))) + .build(); + + // committee votes + java.util.Map committeeVotes = new HashMap<>(); + var committeeVotesDI = (Map) proposalArray.getDataItems().get(1); + + for (DataItem key : committeeVotesDI.getKeys()) { + var credentialDI = (Array) key; + int credType = toInt(credentialDI.getDataItems().get(0)); + String credHash = HexUtil.encodeHexString(((ByteString) credentialDI.getDataItems().get(1)).getBytes()); + var voteDI = committeeVotesDI.get(credentialDI); + Vote vote = Vote.values()[toInt(voteDI)]; + committeeVotes.put(Credential.builder() + .type(credType == 0 ? StakeCredType.ADDR_KEYHASH : StakeCredType.SCRIPTHASH) + .hash(credHash) + .build(), vote); + } + + // dRep votes + java.util.Map dRepVotes = new HashMap<>(); + var dRepVotesDI = (Map) proposalArray.getDataItems().get(2); + + for (DataItem key : dRepVotesDI.getKeys()) { + var credentialDI = (Array) key; + int credType = toInt(credentialDI.getDataItems().get(0)); + String credHash = HexUtil.encodeHexString(((ByteString)credentialDI.getDataItems().get(1)).getBytes()); + var voteDI = dRepVotesDI.get(credentialDI); + Vote vote = Vote.values()[toInt(voteDI)]; + dRepVotes.put(credType == 0 ? Drep.addrKeyHash(credHash) : Drep.scriptHash(credHash), vote); + } + + // stake pool votes + java.util.Map stakePoolVotes = new HashMap<>(); + var stakePoolVotesDI = (Map) proposalArray.getDataItems().get(3); + for (DataItem key : stakePoolVotesDI.getKeys()) { + String poolHash = HexUtil.encodeHexString(((ByteString)key).getBytes()); + var voteDI = stakePoolVotesDI.get(key); + Vote vote = Vote.values()[toInt(voteDI)]; + stakePoolVotes.put(StakePoolId.builder().poolKeyHash(poolHash).build(), vote); + } + + // expiredAfter + Integer expiredAfter = toInt(proposalArray.getDataItems().get(6)); + // proposedIn + Integer proposedIn = toInt(proposalArray.getDataItems().get(5)); + + return Proposal.builder() + .govActionId(govActionId) + .dRepVotes(dRepVotes) + .stakePoolVotes(stakePoolVotes) + .proposalProcedure(proposalProcedure) + .expiredAfter(expiredAfter) + .proposedIn(proposedIn) + .build(); + } + +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/GovStateResult.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/GovStateResult.java new file mode 100644 index 00000000..4b8fb29d --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/GovStateResult.java @@ -0,0 +1,24 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries; + +import com.bloxbean.cardano.yaci.core.model.ProtocolParamUpdate; +import com.bloxbean.cardano.yaci.core.model.governance.Committee; +import com.bloxbean.cardano.yaci.core.model.governance.Constitution; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.QueryResult; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.Proposal; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model.RatifyState; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class GovStateResult implements QueryResult { + private Committee committee; + private Constitution constitution; + private ProtocolParamUpdate currentPParams; + private ProtocolParamUpdate futurePParams; + private ProtocolParamUpdate previousPParams; + private RatifyState nextRatifyState; + private List proposals; +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/DRepState.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/DRepState.java new file mode 100644 index 00000000..9a9d5b24 --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/DRepState.java @@ -0,0 +1,18 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model; + +import com.bloxbean.cardano.yaci.core.model.governance.Anchor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.math.BigInteger; + +@Getter +@Setter +@Builder +public class DRepState { + private String dRepHash; + private Anchor anchor; + private BigInteger deposit; + private Integer expiry; +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/EnactState.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/EnactState.java new file mode 100644 index 00000000..ceb1f75a --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/EnactState.java @@ -0,0 +1,22 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model; + +import com.bloxbean.cardano.yaci.core.model.ProtocolParamUpdate; +import com.bloxbean.cardano.yaci.core.model.governance.Committee; +import com.bloxbean.cardano.yaci.core.model.governance.Constitution; +import com.bloxbean.cardano.yaci.core.model.governance.GovActionId; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.Map; + +@Getter +@Setter +@Builder +public class EnactState { + private Committee committee; + private Constitution constitution; + private ProtocolParamUpdate currentPParams; + private ProtocolParamUpdate prevPParams; + private Map prevGovActionIds; +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/Proposal.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/Proposal.java new file mode 100644 index 00000000..f69d679a --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/Proposal.java @@ -0,0 +1,26 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model; + +import com.bloxbean.cardano.yaci.core.model.Credential; +import com.bloxbean.cardano.yaci.core.model.certs.StakePoolId; +import com.bloxbean.cardano.yaci.core.model.governance.Drep; +import com.bloxbean.cardano.yaci.core.model.governance.GovActionId; +import com.bloxbean.cardano.yaci.core.model.governance.ProposalProcedure; +import com.bloxbean.cardano.yaci.core.model.governance.Vote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.Map; + +@Getter +@Setter +@Builder +public class Proposal { + private GovActionId govActionId; + private Map committeeVotes; + private Map dRepVotes; + private Map stakePoolVotes; + private ProposalProcedure proposalProcedure; + private Integer expiredAfter; + private Integer proposedIn; +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/ProposalType.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/ProposalType.java new file mode 100644 index 00000000..82513e45 --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/ProposalType.java @@ -0,0 +1,5 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model; + +public enum ProposalType { + COMMITTEE, CONSTITUTION, HARD_FORK, P_PARAM_UPDATE +} diff --git a/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/RatifyState.java b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/RatifyState.java new file mode 100644 index 00000000..8fac2e21 --- /dev/null +++ b/core/src/main/java/com/bloxbean/cardano/yaci/core/protocol/localstate/queries/model/RatifyState.java @@ -0,0 +1,18 @@ +package com.bloxbean.cardano.yaci.core.protocol.localstate.queries.model; + +import com.bloxbean.cardano.yaci.core.model.governance.GovActionId; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class RatifyState { + private List enactedGovActions; + private List expiredGovActions; + private EnactState nextEnactState; + private Boolean ratificationDelayed; +} diff --git a/core/src/test/java/com/bloxbean/cardano/yaci/core/BaseTest.java b/core/src/test/java/com/bloxbean/cardano/yaci/core/BaseTest.java index dd844afc..ac7c1256 100644 --- a/core/src/test/java/com/bloxbean/cardano/yaci/core/BaseTest.java +++ b/core/src/test/java/com/bloxbean/cardano/yaci/core/BaseTest.java @@ -7,7 +7,9 @@ public class BaseTest { protected String node = Constants.PREPROD_IOHK_RELAY_ADDR; protected int nodePort = Constants.PREPROD_IOHK_RELAY_PORT; protected long protocolMagic = Constants.PREPROD_PROTOCOL_MAGIC; + protected long sanchoProtocolMagic = Constants.SANCHONET_PROTOCOL_MAGIC; protected Point knownPoint = new Point(13003663, "b896e43a25de269cfc47be7afbcbf00cad41a5011725c2732393f1b4508cf41d"); protected String nodeSocketFile = "/Users/satya/work/cardano-node/prepod/db/node.socket"; + protected String sanchoNodeSocketFile = "/Users/satya/work/cardano-node/sanchonet/db/node.socket"; } diff --git a/core/src/test/java/com/bloxbean/cardano/yaci/core/protocol/localstate/LocalStateQueryAgentIT.java b/core/src/test/java/com/bloxbean/cardano/yaci/core/protocol/localstate/LocalStateQueryAgentIT.java index 0984c876..917aaa90 100644 --- a/core/src/test/java/com/bloxbean/cardano/yaci/core/protocol/localstate/LocalStateQueryAgentIT.java +++ b/core/src/test/java/com/bloxbean/cardano/yaci/core/protocol/localstate/LocalStateQueryAgentIT.java @@ -1,24 +1,25 @@ package com.bloxbean.cardano.yaci.core.protocol.localstate; import com.bloxbean.cardano.yaci.core.BaseTest; +import com.bloxbean.cardano.yaci.core.model.Credential; +import com.bloxbean.cardano.yaci.core.model.certs.StakeCredType; import com.bloxbean.cardano.yaci.core.network.UnixSocketNodeClient; import com.bloxbean.cardano.yaci.core.protocol.chainsync.messages.Point; import com.bloxbean.cardano.yaci.core.protocol.handshake.HandshakeAgent; import com.bloxbean.cardano.yaci.core.protocol.handshake.HandshakeAgentListener; import com.bloxbean.cardano.yaci.core.protocol.handshake.messages.Reason; import com.bloxbean.cardano.yaci.core.protocol.handshake.util.N2CVersionTableConstant; +import com.bloxbean.cardano.yaci.core.protocol.localstate.api.Era; import com.bloxbean.cardano.yaci.core.protocol.localstate.api.Query; import com.bloxbean.cardano.yaci.core.protocol.localstate.api.QueryResult; import com.bloxbean.cardano.yaci.core.protocol.localstate.messages.MsgFailure; -import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.BlockHeightQuery; -import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.ChainPointQuery; -import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.SystemStartQuery; -import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.SystemStartResult; +import com.bloxbean.cardano.yaci.core.protocol.localstate.queries.*; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -380,4 +381,168 @@ public void resultReceived(Query query, QueryResult result) { n2CClient.shutdown(); } + + @Test + void constitutionQuery_shouldReturn_Constitution() throws InterruptedException { + HandshakeAgent handshakeAgent = new HandshakeAgent(N2CVersionTableConstant.v1AndAbove(sanchoProtocolMagic)); + LocalStateQueryAgent localStateQueryAgent = new LocalStateQueryAgent(); + + UnixSocketNodeClient n2CClient = new UnixSocketNodeClient(sanchoNodeSocketFile, handshakeAgent, localStateQueryAgent); + + CountDownLatch countDownLatch = new CountDownLatch(2); + handshakeAgent.addListener(new HandshakeAgentListener() { + @Override + public void handshakeOk() { + log.info("HANDSHAKE Successful"); + localStateQueryAgent.acquire(); + localStateQueryAgent.sendNextMessage(); + } + + @Override + public void handshakeError(Reason reason) { + log.info("ERROR {}", reason); + } + }); + + AtomicBoolean failed = new AtomicBoolean(false); + localStateQueryAgent.addListener(new LocalStateQueryListener() { + @Override + public void acquireFailed(MsgFailure.Reason reason) { + countDownLatch.countDown(); + failed.set(true); + } + + @Override + public void acquired(Point point) { + countDownLatch.countDown(); + localStateQueryAgent.query(new ConstitutionQuery(Era.Conway)); + localStateQueryAgent.sendNextMessage(); + } + + @Override + public void resultReceived(Query query, QueryResult result) { + System.out.println("Query >> " + query); + System.out.println("Result >> " + result); + System.out.println("Result : " + result); + countDownLatch.countDown(); + } + }); + + n2CClient.start(); + countDownLatch.await(20, TimeUnit.SECONDS); + n2CClient.shutdown(); + } + + @Test + void dRepStateQuery_shouldReturn_dRepStateList() throws InterruptedException { + HandshakeAgent handshakeAgent = new HandshakeAgent(N2CVersionTableConstant.v1AndAbove(sanchoProtocolMagic)); + LocalStateQueryAgent localStateQueryAgent = new LocalStateQueryAgent(); + + UnixSocketNodeClient n2CClient = new UnixSocketNodeClient(sanchoNodeSocketFile, handshakeAgent, localStateQueryAgent); + + CountDownLatch countDownLatch = new CountDownLatch(2); + handshakeAgent.addListener(new HandshakeAgentListener() { + @Override + public void handshakeOk() { + log.info("HANDSHAKE Successful"); + localStateQueryAgent.acquire(); + localStateQueryAgent.sendNextMessage(); + } + + @Override + public void handshakeError(Reason reason) { + log.info("ERROR {}", reason); + } + }); + + AtomicBoolean failed = new AtomicBoolean(false); + localStateQueryAgent.addListener(new LocalStateQueryListener() { + @Override + public void acquireFailed(MsgFailure.Reason reason) { + countDownLatch.countDown(); + failed.set(true); + } + + @Override + public void acquired(Point point) { + countDownLatch.countDown(); + localStateQueryAgent.query(new DRepStateQuery(List.of( + Credential + .builder() + .type(StakeCredType.ADDR_KEYHASH) + .hash("5e80b2b80990a738aece6d6068b2991eaea21c52e79c7974719ac275") + .build(), + Credential + .builder() + .type(StakeCredType.ADDR_KEYHASH) + .hash("6e066d1a8bce348956b34438556abb43d597d075f9fdab03bb6f4d39") + .build() + ))); + localStateQueryAgent.sendNextMessage(); + } + + @Override + public void resultReceived(Query query, QueryResult result) { + System.out.println("Query >> " + query); + System.out.println("Result >> " + result); + countDownLatch.countDown(); + } + }); + + n2CClient.start(); + countDownLatch.await(20, TimeUnit.SECONDS); + n2CClient.shutdown(); + } + + + @Test + void govStateQuery_shouldReturn_govState() throws InterruptedException { + HandshakeAgent handshakeAgent = new HandshakeAgent(N2CVersionTableConstant.v1AndAbove(sanchoProtocolMagic)); + LocalStateQueryAgent localStateQueryAgent = new LocalStateQueryAgent(); + + UnixSocketNodeClient n2CClient = new UnixSocketNodeClient(sanchoNodeSocketFile, handshakeAgent, localStateQueryAgent); + + CountDownLatch countDownLatch = new CountDownLatch(2); + handshakeAgent.addListener(new HandshakeAgentListener() { + @Override + public void handshakeOk() { + log.info("HANDSHAKE Successful"); + localStateQueryAgent.acquire(); + localStateQueryAgent.sendNextMessage(); + } + + @Override + public void handshakeError(Reason reason) { + log.info("ERROR {}", reason); + } + }); + + AtomicBoolean failed = new AtomicBoolean(false); + localStateQueryAgent.addListener(new LocalStateQueryListener() { + @Override + public void acquireFailed(MsgFailure.Reason reason) { + countDownLatch.countDown(); + failed.set(true); + } + + @Override + public void acquired(Point point) { + countDownLatch.countDown(); + localStateQueryAgent.query(new GovStateQuery(Era.Conway)); + localStateQueryAgent.sendNextMessage(); + } + + @Override + public void resultReceived(Query query, QueryResult result) { + System.out.println("Query >> " + query); + System.out.println("Result >> " + result); + countDownLatch.countDown(); + } + }); + + n2CClient.start(); + countDownLatch.await(20, TimeUnit.SECONDS); + n2CClient.shutdown(); + } + }