// File: NeoResearch[P]dbft3-spork-detect/main.cpp
// Function: getCommitCountFromCancels(std::vector<int, std::allocator<int>>, std::vector<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int>>>, std::allocator<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int>>>>>, int)
int getCommitCountFromCancels(vector<int> cancels, vector<vector<pair<int, int>>> selections, int f)
{
    // compute commit counts
    // commit zero (X_0) may be issued when any zero is present
    // commit one (X_1) may be issued when 2*f+1 ones is present

    bool hasCommitOne = false;
    bool hasCommitZero = false; // a little bit more complex

    bool hasBadZero = false;     // bad zero condition, may help commit one too... BadZero + 2 ones (N=4).. when 1 is faulty
    bool hasTrustedZero = false; // trusted zero should be the same as BadZero above...

    // look for zero commits
    for (unsigned i = 0; i < cancels.size(); i++)
    {
        // if not cancel zero, proceed...
        if (cancels[i] != 0)
            continue;

        // found POSSIBLE X_0

        // must verify primary edge case
        if (i == 0) // may be tricky (mandatory for replica 0 to issue cancel 0)
        {
            // if primary 0 has another independent confirmation, then it's good
            int confirmations = 0;
            // selections contains only prepare responses (not request!)
            for (unsigned k = 0; k < selections[0].size(); k++)
                if ((selections[0][k].second == 0)) //&& (selections[0][k].first != 0)) // a zero from someone else
                    confirmations++;                // including itself
            if (confirmations >= 1)                 // more than itself
            {
                hasCommitZero = true;
                break; // guaranteed
            }
            else
            {
                // only itself...
                hasTrustedZero = true;
                // one may received this "Cancel 0" with two other Cancel 1 (for 2f+1 = 3)
                // must find in ALL other possible Cancel 1, if it could provide evidence that ONE NON-FAULTY zero exists.
                // let's go.
                int countConfirmed = 0; // must have at least 2f OTHERS including a VALID zero (a non-faulty zero)
                for (unsigned j = 1; j < cancels.size(); j++)
                {
                    if (cancels[j] == 0) // OK, if you are lucky to receive this one...
                        countConfirmed++;
                    else
                    {
                        // not so lucky this time...
                        if (cancels[j] == 1) // any good option must include extra f+1
                        {
                            for (unsigned k = 0; k < selections[j].size(); k++)
                                if ((selections[j][k].second == 0) && (selections[j][k].first != 0))
                                {
                                    countConfirmed++;
                                    break;
                                }
                        }
                    }
                } // for j=1 to N-1

                // one needs this zero + 2f good ones (TODO: confirm for 7 nodes... maybe this is N-2... for 4 its same as 2f+1.. who knows)
                if (countConfirmed >= 2 * f)
                    hasCommitZero = true;
                else
                    hasBadZero = true; // bad zero may help commit one, perhaps!
            }
        }                         // end replica 0 for cancel 0
        else                      // this is trivial, not primary, thus certain value.
            hasCommitZero = true; // this one is certainly good

        // if found zero already, breaks search
        if (hasCommitZero)
            break;
    } // end looking for zeros

    // look for one commits
    int ones = 0;
    for (unsigned i = 0; i < cancels.size(); i++)
        if (cancels[i] == 1)
            ones++;
    if (ones >= 2 * f + 1) // found a possible X_1
        hasCommitOne = true;

    // special case: two one's and one BadZero (N=4) and a failed node...
    if (ones + hasBadZero == 2 * f + 1) // since ones are never in primary when BadZero is, this is good.
        hasCommitOne = true;

    cout << "trustedzero: " << hasTrustedZero << endl;
    cout << "badzero: " << hasBadZero << endl;
    cout << "commit0: " << hasCommitZero << endl;
    cout << "commit1: " << hasCommitOne << endl;

    return hasCommitZero + hasCommitOne;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq %rdi, -0x48(%rbp)
movq %rsi, -0x40(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movb $0x0, -0x15(%rbp)
movb $0x0, -0x16(%rbp)
movb $0x0, -0x17(%rbp)
movb $0x0, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movq -0x48(%rbp), %rdi
movl -0x1c(%rbp), %eax
movq %rax, -0x50(%rbp)
callq 0x44b0
movq %rax, %rcx
movq -0x50(%rbp), %rax
cmpq %rcx, %rax
jae 0x313f
movq -0x48(%rbp), %rdi
movl -0x1c(%rbp), %eax
movl %eax, %esi
callq 0x44d0
cmpl $0x0, (%rax)
je 0x2f7a
jmp 0x3131
cmpl $0x0, -0x1c(%rbp)
jne 0x3123
movl $0x0, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movq -0x40(%rbp), %rdi
movl -0x24(%rbp), %eax
movq %rax, -0x58(%rbp)
xorl %eax, %eax
movl %eax, %esi
callq 0x4d30
movq %rax, %rdi
callq 0x4da0
movq %rax, %rcx
movq -0x58(%rbp), %rax
cmpq %rcx, %rax
jae 0x2ff0
movq -0x40(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4d30
movq %rax, %rdi
movl -0x24(%rbp), %eax
movl %eax, %esi
callq 0x4d50
cmpl $0x0, 0x4(%rax)
jne 0x2fe3
movl -0x20(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x20(%rbp)
jmp 0x2fe5
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x2f92
cmpl $0x1, -0x20(%rbp)
jl 0x2fff
movb $0x1, -0x16(%rbp)
jmp 0x313f
movb $0x1, -0x18(%rbp)
movl $0x0, -0x28(%rbp)
movl $0x1, -0x2c(%rbp)
movq -0x48(%rbp), %rdi
movl -0x2c(%rbp), %eax
movq %rax, -0x60(%rbp)
callq 0x44b0
movq %rax, %rcx
movq -0x60(%rbp), %rax
cmpq %rcx, %rax
jae 0x3109
movq -0x48(%rbp), %rdi
movl -0x2c(%rbp), %eax
movl %eax, %esi
callq 0x44d0
cmpl $0x0, (%rax)
jne 0x3052
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x30f9
movq -0x48(%rbp), %rdi
movl -0x2c(%rbp), %eax
movl %eax, %esi
callq 0x44d0
cmpl $0x1, (%rax)
jne 0x30f7
movl $0x0, -0x30(%rbp)
movq -0x40(%rbp), %rdi
movl -0x30(%rbp), %eax
movq %rax, -0x68(%rbp)
movl -0x2c(%rbp), %eax
movl %eax, %esi
callq 0x4d30
movq %rax, %rdi
callq 0x4da0
movq %rax, %rcx
movq -0x68(%rbp), %rax
cmpq %rcx, %rax
jae 0x30f5
movq -0x40(%rbp), %rdi
movl -0x2c(%rbp), %eax
movl %eax, %esi
callq 0x4d30
movq %rax, %rdi
movl -0x30(%rbp), %eax
movl %eax, %esi
callq 0x4d50
cmpl $0x0, 0x4(%rax)
jne 0x30e5
movq -0x40(%rbp), %rdi
movl -0x2c(%rbp), %eax
movl %eax, %esi
callq 0x4d30
movq %rax, %rdi
movl -0x30(%rbp), %eax
movl %eax, %esi
callq 0x4d50
cmpl $0x0, (%rax)
je 0x30e5
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x30f5
jmp 0x30e7
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x3070
jmp 0x30f7
jmp 0x30f9
jmp 0x30fb
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x3011
movl -0x28(%rbp), %eax
movl -0x14(%rbp), %ecx
shll %ecx
cmpl %ecx, %eax
jl 0x311b
movb $0x1, -0x16(%rbp)
jmp 0x311f
movb $0x1, -0x17(%rbp)
jmp 0x3121
jmp 0x3127
movb $0x1, -0x16(%rbp)
testb $0x1, -0x16(%rbp)
je 0x312f
jmp 0x313f
jmp 0x3131
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x2f42
movl $0x0, -0x34(%rbp)
movl $0x0, -0x38(%rbp)
movq -0x48(%rbp), %rdi
movl -0x38(%rbp), %eax
movq %rax, -0x70(%rbp)
callq 0x44b0
movq %rax, %rcx
movq -0x70(%rbp), %rax
cmpq %rcx, %rax
jae 0x3192
movq -0x48(%rbp), %rdi
movl -0x38(%rbp), %eax
movl %eax, %esi
callq 0x44d0
cmpl $0x1, (%rax)
jne 0x3185
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x3187
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0x314d
movl -0x34(%rbp), %eax
movl -0x14(%rbp), %ecx
shll %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jl 0x31a5
movb $0x1, -0x15(%rbp)
movl -0x34(%rbp), %eax
movb -0x17(%rbp), %cl
andb $0x1, %cl
movzbl %cl, %ecx
addl %ecx, %eax
movl -0x14(%rbp), %ecx
shll %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jne 0x31c3
movb $0x1, -0x15(%rbp)
movq 0xae0e(%rip), %rdi      # 0xdfd8
leaq 0x5f36(%rip), %rsi      # 0x9107
callq 0x10f0
movq %rax, %rdi
movb -0x18(%rbp), %al
andb $0x1, %al
movzbl %al, %esi
callq 0x11d0
movq %rax, %rdi
movq 0xadd8(%rip), %rsi      # 0xdfc8
callq 0x1130
movq 0xaddc(%rip), %rdi      # 0xdfd8
leaq 0x5f12(%rip), %rsi      # 0x9115
callq 0x10f0
movq %rax, %rdi
movb -0x17(%rbp), %al
andb $0x1, %al
movzbl %al, %esi
callq 0x11d0
movq %rax, %rdi
movq 0xada6(%rip), %rsi      # 0xdfc8
callq 0x1130
movq 0xadaa(%rip), %rdi      # 0xdfd8
leaq 0x5eea(%rip), %rsi      # 0x911f
callq 0x10f0
movq %rax, %rdi
movb -0x16(%rbp), %al
andb $0x1, %al
movzbl %al, %esi
callq 0x11d0
movq %rax, %rdi
movq 0xad74(%rip), %rsi      # 0xdfc8
callq 0x1130
movq 0xad78(%rip), %rdi      # 0xdfd8
leaq 0x5ec2(%rip), %rsi      # 0x9129
callq 0x10f0
movq %rax, %rdi
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %esi
callq 0x11d0
movq %rax, %rdi
movq 0xad42(%rip), %rsi      # 0xdfc8
callq 0x1130
movb -0x16(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
movb -0x15(%rbp), %cl
andb $0x1, %cl
movzbl %cl, %ecx
addl %ecx, %eax
addq $0x70, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)