use of bisq.core.dao.governance.ballot.BallotList in project bisq-core by bisq-network.
the class MyBlindVoteListService method publishBlindVote.
public void publishBlindVote(Coin stake, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
try {
SecretKey secretKey = BlindVoteConsensus.createSecretKey();
BallotList sortedBallotList = BlindVoteConsensus.getSortedBallotList(ballotListService);
byte[] encryptedVotes = getEncryptedVotes(sortedBallotList, secretKey);
byte[] opReturnData = getOpReturnData(encryptedVotes);
Coin blindVoteFee = BlindVoteConsensus.getFee(bsqStateService, bsqStateService.getChainHeight());
Transaction blindVoteTx = getBlindVoteTx(stake, blindVoteFee, opReturnData);
String blindVoteTxId = blindVoteTx.getHashAsString();
byte[] encryptedMeritList = getEncryptedMeritList(blindVoteTxId, secretKey);
// We prefer to not wait for the tx broadcast as if the tx broadcast would fail we still prefer to have our
// blind vote stored and broadcasted to the p2p network. The tx might get re-broadcasted at a restart and
// in worst case if it does not succeed the blind vote will be ignored anyway.
// Inconsistently propagated blind votes in the p2p network could have potentially worse effects.
BlindVote blindVote = new BlindVote(encryptedVotes, blindVoteTxId, stake.value, encryptedMeritList);
addBlindVoteToList(blindVote);
addToP2PNetwork(blindVote, errorMessage -> {
log.error(errorMessage);
exceptionHandler.handleException(new PublishToP2PNetworkException(errorMessage));
});
// We store our source data for the blind vote in myVoteList
myVoteListService.createAndAddMyVote(sortedBallotList, secretKey, blindVote);
publishTx(resultHandler, exceptionHandler, blindVoteTx);
} catch (CryptoException | TransactionVerificationException | InsufficientMoneyException | WalletException | IOException exception) {
exceptionHandler.handleException(exception);
}
}
use of bisq.core.dao.governance.ballot.BallotList in project bisq-core by bisq-network.
the class VoteResultService method createBallotList.
private BallotList createBallotList(VoteWithProposalTxIdList voteWithProposalTxIdList) throws MissingBallotException {
// We convert the list to a map with proposalTxId as key and the vote as value
Map<String, Vote> voteByTxIdMap = voteWithProposalTxIdList.stream().filter(voteWithProposalTxId -> voteWithProposalTxId.getVote() != null).collect(Collectors.toMap(VoteWithProposalTxId::getProposalTxId, VoteWithProposalTxId::getVote));
// We make a map with proposalTxId as key and the ballot as value out of our stored ballot list
Map<String, Ballot> ballotByTxIdMap = ballotListService.getBallotList().stream().collect(Collectors.toMap(Ballot::getTxId, ballot -> ballot));
List<String> missingBallots = new ArrayList<>();
List<Ballot> ballots = voteByTxIdMap.entrySet().stream().map(entry -> {
String txId = entry.getKey();
if (ballotByTxIdMap.containsKey(txId)) {
// why not use proposalList?
Ballot ballot = ballotByTxIdMap.get(txId);
// We create a new Ballot with the proposal from the ballot list and the vote from our decrypted votes
Vote vote = entry.getValue();
// received from the network?
return new Ballot(ballot.getProposal(), vote);
} else {
// We got a vote but we don't have the ballot (which includes the proposal)
// We add it to the missing list to handle it as exception later. We want all missing data so we
// do not throw here.
missingBallots.add(txId);
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
if (!missingBallots.isEmpty())
throw new MissingBallotException(ballots, missingBallots);
// Let's keep the data more deterministic by sorting it by txId. Though we are not using the sorting.
ballots.sort(Comparator.comparing(Ballot::getTxId));
return new BallotList(ballots);
}
use of bisq.core.dao.governance.ballot.BallotList in project bisq-core by bisq-network.
the class VoteResultService method getDecryptedBallotsWithMeritsSet.
private Set<DecryptedBallotsWithMerits> getDecryptedBallotsWithMeritsSet(int chainHeight) {
// We want all voteRevealTxOutputs which are in current cycle we are processing.
return bsqStateService.getVoteRevealOpReturnTxOutputs().stream().filter(txOutput -> periodService.isTxInCorrectCycle(txOutput.getTxId(), chainHeight)).map(txOutput -> {
// TODO make method
byte[] opReturnData = txOutput.getOpReturnData();
String voteRevealTxId = txOutput.getTxId();
Optional<Tx> optionalVoteRevealTx = bsqStateService.getTx(voteRevealTxId);
if (!optionalVoteRevealTx.isPresent()) {
log.error("optionalVoteRevealTx is not present. voteRevealTxId={}", voteRevealTxId);
// TODO throw exception
return null;
}
Tx voteRevealTx = optionalVoteRevealTx.get();
try {
// TODO maybe verify version in opReturn
byte[] hashOfBlindVoteList = VoteResultConsensus.getHashOfBlindVoteList(opReturnData);
SecretKey secretKey = VoteResultConsensus.getSecretKey(opReturnData);
TxOutput blindVoteStakeOutput = VoteResultConsensus.getConnectedBlindVoteStakeOutput(voteRevealTx, bsqStateService);
long blindVoteStake = blindVoteStakeOutput.getValue();
Tx blindVoteTx = VoteResultConsensus.getBlindVoteTx(blindVoteStakeOutput, bsqStateService, periodService, chainHeight);
String blindVoteTxId = blindVoteTx.getId();
// Here we deal with eventual consistency of the p2p network data!
// TODO make more clear we are in p2p domain now
List<BlindVote> blindVoteList = BlindVoteConsensus.getSortedBlindVoteListOfCycle(blindVoteListService);
Optional<BlindVote> optionalBlindVote = blindVoteList.stream().filter(blindVote -> blindVote.getTxId().equals(blindVoteTxId)).findAny();
if (optionalBlindVote.isPresent()) {
BlindVote blindVote = optionalBlindVote.get();
VoteWithProposalTxIdList voteWithProposalTxIdList = VoteResultConsensus.decryptVotes(blindVote.getEncryptedVotes(), secretKey);
MeritList meritList = MeritConsensus.decryptMeritList(blindVote.getEncryptedMeritList(), secretKey);
// We lookup for the proposals we have in our local list which match the txId from the
// voteWithProposalTxIdList and create a ballot list with the proposal and the vote from
// the voteWithProposalTxIdList
BallotList ballotList = createBallotList(voteWithProposalTxIdList);
return new DecryptedBallotsWithMerits(hashOfBlindVoteList, voteRevealTxId, blindVoteTxId, blindVoteStake, ballotList, meritList);
} else {
// TODO handle recovering
log.warn("We have a blindVoteTx but we do not have the corresponding blindVote in our local list.\n" + "That can happen if the blindVote item was not properly broadcast. We will go on " + "and see if that blindVote was part of the majority data view. If so we should " + "recover the missing blind vote by a request to our peers. blindVoteTxId={}", blindVoteTxId);
return null;
}
} catch (MissingBallotException e) {
// TODO handle case that we are missing proposals
log.error("We are missing proposals to create the vote result: " + e.toString());
return null;
} catch (Throwable e) {
log.error("Could not create DecryptedBallotsWithMerits: " + e.toString());
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toSet());
}
Aggregations