diff --git a/Sources/BeaconChain/BeaconChain.swift b/Sources/BeaconChain/BeaconChain.swift index e825da1..a847d67 100644 --- a/Sources/BeaconChain/BeaconChain.swift +++ b/Sources/BeaconChain/BeaconChain.swift @@ -273,62 +273,6 @@ extension BeaconChain { extension BeaconChain { - static func verifySlashableAttestation(state: BeaconState, slashableAttestation: SlashableAttestation) -> Bool { - if slashableAttestation.custodyBitfield != Data(repeating: 0, count: slashableAttestation.custodyBitfield.count) { - return false - } - - if slashableAttestation.validatorIndices.count == 0 { - return false - } - - for i in 0..<(slashableAttestation.validatorIndices.count - 1) { - if slashableAttestation.validatorIndices[i] >= slashableAttestation.validatorIndices[i + 1] { - return false - } - } - - if !verifyBitfield(bitfield: slashableAttestation.custodyBitfield, committeeSize: slashableAttestation.validatorIndices.count) { - return false - } - - if slashableAttestation.validatorIndices.count > MAX_INDICES_PER_SLASHABLE_VOTE { - return false - } - - var custodyBit0Indices = [UInt64]() - var custodyBit1Indices = [UInt64]() - - for (i, validatorIndex) in slashableAttestation.validatorIndices.enumerated() { - if getBitfieldBit(bitfield: slashableAttestation.custodyBitfield, i: i) == 0b0 { - custodyBit0Indices.append(validatorIndex) - } else { - custodyBit1Indices.append(validatorIndex) - } - } - - return BLS.verify( - pubkeys: [ - BLS.aggregate( - pubkeys: custodyBit0Indices.map { (i) in - return state.validatorRegistry[Int(i)].pubkey - } - ), - BLS.aggregate( - pubkeys: custodyBit1Indices.map { (i) in - return state.validatorRegistry[Int(i)].pubkey - } - ) - ], - messages: [ - hashTreeRoot(AttestationDataAndCustodyBit(data: slashableAttestation.data, custodyBit: false)), - hashTreeRoot(AttestationDataAndCustodyBit(data: slashableAttestation.data, custodyBit: true)), - ], - signature: slashableAttestation.aggregateSignature, - domain: getDomain(fork: state.fork, epoch: slashableAttestation.data.slot.toEpoch(), domainType: Domain.ATTESTATION) - ) - } - static func isDoubleVote(_ left: AttestationData, _ right: AttestationData) -> Bool { return left.slot.toEpoch() == right.slot.toEpoch() } diff --git a/Sources/BeaconChain/DataStructures/Transactions/AttesterSlashings/SlashableAttestation.swift b/Sources/BeaconChain/DataStructures/Transactions/AttesterSlashings/SlashableAttestation.swift index 47efd6d..722d846 100644 --- a/Sources/BeaconChain/DataStructures/Transactions/AttesterSlashings/SlashableAttestation.swift +++ b/Sources/BeaconChain/DataStructures/Transactions/AttesterSlashings/SlashableAttestation.swift @@ -5,4 +5,60 @@ struct SlashableAttestation { let data: AttestationData let custodyBitfield: Data let aggregateSignature: Data + + func verify(state: BeaconState) -> Bool { + if custodyBitfield != Data(repeating: 0, count: custodyBitfield.count) { + return false + } + + if validatorIndices.count == 0 { + return false + } + + for i in 0..<(validatorIndices.count - 1) { + if validatorIndices[i] >= validatorIndices[i + 1] { + return false + } + } + + if !BeaconChain.verifyBitfield(bitfield: custodyBitfield, committeeSize: validatorIndices.count) { + return false + } + + if validatorIndices.count > MAX_INDICES_PER_SLASHABLE_VOTE { + return false + } + + var custodyBit0Indices = [UInt64]() + var custodyBit1Indices = [UInt64]() + + for (i, validatorIndex) in validatorIndices.enumerated() { + if BeaconChain.getBitfieldBit(bitfield: custodyBitfield, i: i) == 0b0 { + custodyBit0Indices.append(validatorIndex) + } else { + custodyBit1Indices.append(validatorIndex) + } + } + + return BLS.verify( + pubkeys: [ + BLS.aggregate( + pubkeys: custodyBit0Indices.map { (i) in + return state.validatorRegistry[Int(i)].pubkey + } + ), + BLS.aggregate( + pubkeys: custodyBit1Indices.map { (i) in + return state.validatorRegistry[Int(i)].pubkey + } + ) + ], + messages: [ + BeaconChain.hashTreeRoot(AttestationDataAndCustodyBit(data: data, custodyBit: false)), + BeaconChain.hashTreeRoot(AttestationDataAndCustodyBit(data: data, custodyBit: true)), + ], + signature: aggregateSignature, + domain: BeaconChain.getDomain(fork: state.fork, epoch: data.slot.toEpoch(), domainType: Domain.ATTESTATION) + ) + } } diff --git a/Sources/BeaconChain/StateTransition.swift b/Sources/BeaconChain/StateTransition.swift index aac73d6..c059139 100644 --- a/Sources/BeaconChain/StateTransition.swift +++ b/Sources/BeaconChain/StateTransition.swift @@ -133,8 +133,8 @@ extension StateTransition { || BeaconChain.isSurroundVote(slashableAttestation1.data, slashableAttestation2.data) ) - assert(BeaconChain.verifySlashableAttestation(state: state, slashableAttestation: slashableAttestation1)) - assert(BeaconChain.verifySlashableAttestation(state: state, slashableAttestation: slashableAttestation2)) + assert(slashableAttestation1.verify(state: state)) + assert(slashableAttestation2.verify(state: state)) let slashableIndices = slashableAttestation1.validatorIndices.filter { slashableAttestation2.validatorIndices.contains($0)