package org.bitcoinj.evolution;

import org.bitcoinj.core.*;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

import static org.bitcoinj.core.Sha256Hash.hashTwice;

public class SimplifiedMasternodeListDiff extends Message {
    public Sha256Hash prevBlockHash;
    public Sha256Hash blockHash;
    PartialMerkleTree cbTxMerkleTree;
    Transaction coinBaseTx;
    protected HashSet<Sha256Hash> deletedMNs;
    protected ArrayList<SimplifiedMasternodeListEntry> mnList;


    public SimplifiedMasternodeListDiff(NetworkParameters params, byte [] payload) {
        super(params, payload, 0);
    }

    @Override
    protected void parse() throws ProtocolException {
        prevBlockHash = readHash();
        blockHash = readHash();

        cbTxMerkleTree = new PartialMerkleTree(params, payload, cursor);
        cursor += cbTxMerkleTree.getMessageSize();

        coinBaseTx = new Transaction(params, payload, cursor);
        cursor += coinBaseTx.getMessageSize();

        int size = (int)readVarInt();
        deletedMNs = new HashSet<Sha256Hash>(size);
        for(int i = 0; i < size; ++i) {
            deletedMNs.add(readHash());
        }

        size = (int)readVarInt();
        mnList = new ArrayList<SimplifiedMasternodeListEntry>(size);
        for(int i = 0; i < size; ++i)
        {
            SimplifiedMasternodeListEntry mn = new SimplifiedMasternodeListEntry(params, payload, cursor);
            cursor += mn.getMessageSize();
            mnList.add(mn);
        }
        length = cursor - offset;
    }

    @Override
    protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
        stream.write(prevBlockHash.getReversedBytes());
        stream.write(blockHash.getReversedBytes());

        cbTxMerkleTree.bitcoinSerializeToStream(stream);
        coinBaseTx.bitcoinSerialize(stream);

        stream.write(new VarInt(deletedMNs.size()).encode());
        for(Sha256Hash entry : deletedMNs) {
            stream.write(entry.getReversedBytes());
        }

        stream.write(new VarInt(mnList.size()).encode());
        for(SimplifiedMasternodeListEntry entry : mnList) {
            entry.bitcoinSerializeToStream(stream);
        }
    }

    public boolean hasChanges() {
        return !mnList.isEmpty() || !deletedMNs.isEmpty();
    }

    boolean verify() {
        //check that coinbase is in the merkle root
        return true;
    }

    @Override
    public String toString() {
        return "Simplified MNList Diff:  adding " + mnList.size() + " and removing " + deletedMNs.size() + " masternodes";
    }
}

@@ -53,16 +53,93 @@
 .core.*;
+%0Aimport org.bitcoinj.quorums.FinalCommitment;%0Aimport org.bitcoinj.utils.Pair;
 %0A%0Aimport
@@ -571,16 +571,137 @@
 nList;%0A%0A
+    protected ArrayList%3CPair%3CInteger, Sha256Hash%3E%3E deletedQuorums;%0A    protected ArrayList%3CFinalCommitment%3E newQuorums;%0A%0A
 %0A    pub
@@ -1709,24 +1709,736 @@
 ;%0A        %7D%0A
+%0A        //0.14 format include quorum information%0A        if(payload.length %3E cursor - offset) %7B%0A            size = (int)readVarInt();%0A            deletedQuorums = new ArrayList%3CPair%3CInteger, Sha256Hash%3E%3E(size);%0A            for(int i = 0; i %3C size; ++i) %7B%0A                deletedQuorums.add(new Pair((int)readBytes(1)%5B0%5D, readHash()));%0A            %7D%0A%0A            size = (int)readVarInt();%0A            newQuorums = new ArrayList%3CFinalCommitment%3E(size);%0A            for(int i = 0; i %3C size; ++i) %7B%0A                FinalCommitment commitment = new FinalCommitment(params, payload, cursor);%0A                cursor += commitment.getMessageSize();%0A                newQuorums.add(commitment);%0A%0A            %7D%0A        %7D%0A%0A
         leng
@@ -3379,24 +3379,24 @@
 oString() %7B%0A
-
         retu
@@ -3504,16 +3504,400 @@
 ernodes%22
+ +%0A                %22 while adding %22 + newQuorums.size() + %22 and removing %22 + deletedQuorums.size() + %22 quorums%22;%0A    %7D%0A%0A    public Transaction getCoinBaseTx() %7B%0A        return coinBaseTx;%0A    %7D%0A%0A    public ArrayList%3CPair%3CInteger, Sha256Hash%3E%3E getDeletedQuorums() %7B%0A        return deletedQuorums;%0A    %7D%0A%0A    public ArrayList%3CFinalCommitment%3E getNewQuorums() %7B%0A        return newQuorums
 ;%0A    %7D%0A

Handle Quorums (Dash Core 0.14)