diff --git a/Sources/BeaconChain/StateTransition.swift b/Sources/BeaconChain/StateTransition.swift index 16587eb..7c617bb 100644 --- a/Sources/BeaconChain/StateTransition.swift +++ b/Sources/BeaconChain/StateTransition.swift @@ -24,9 +24,10 @@ extension StateTransition { eth1data(state: &state, block: block) proposerSlashings(state: &state, block: block) attesterSlashings(state: &state, block: block) - attestations(state: &state, block: block) - deposits(state: &state, block: block) - voluntaryExits(state: &state, block: block) + Attestations.transition(state: &state, block: block) + Deposits.transition(state: &state, block: block) + VoluntaryExits.transition(state: &state, block: block) + Transfers.transition(state: &state, block: block) } static func blockSignature(state: inout BeaconState, block: BeaconBlock) { @@ -137,167 +138,6 @@ extension StateTransition { } } - static func attestations(state: inout BeaconState, block: BeaconBlock) { - assert(block.body.attestations.count <= MAX_ATTESTATIONS) - - for attestation in block.body.attestations { - assert(attestation.data.slot >= GENESIS_SLOT) - assert(attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot) - assert(state.slot < attestation.data.slot + SLOTS_PER_EPOCH) - - let e = (attestation.data.slot + 1).toEpoch() >= BeaconChain.getCurrentEpoch(state: state) ? state.justifiedEpoch : state.previousJustifiedEpoch - assert(attestation.data.justifiedEpoch == e) - assert(attestation.data.justifiedBlockRoot == BeaconChain.getBlockRoot(state: state, slot: attestation.data.justifiedEpoch.startSlot())) - - assert( - state.latestCrosslinks[Int(attestation.data.shard)] == attestation.data.latestCrosslink || - state.latestCrosslinks[Int(attestation.data.shard)] == Crosslink( - epoch: attestation.data.slot.toEpoch(), - crosslinkDataRoot: attestation.data.crosslinkDataRoot - ) - ) - - assert(attestation.custodyBitfield == Data(repeating: 0, count: 32)) - assert(attestation.aggregationBitfield != Data(repeating: 0, count: 32)) - - let crosslinkCommittee = BeaconChain.crosslinkCommittees(state, at: attestation.data.slot).filter { - $0.1 == attestation.data.shard - }.first?.0 - - for i in 0.. epoch.delayedActivationExitEpoch()) - assert(epoch >= exit.epoch) - - assert( - BLS.verify( - pubkey: validator.pubkey, - message: BeaconChain.signedRoot(exit, field: "signature"), - signature: exit.signature, - domain: state.fork.domain(epoch: exit.epoch, type: .exit) - ) - ) - - state.validatorRegistry[Int(exit.validatorIndex)].initiatedExit = true - } - } - - static func transfers(state: inout BeaconState, block: BeaconBlock) { - assert(block.body.transfers.count <= MAX_TRANSFERS) - - for transfer in block.body.transfers { - assert(state.validatorBalances[Int(transfer.from)] >= transfer.amount) - assert(state.validatorBalances[Int(transfer.from)] >= transfer.fee) - assert( - state.validatorBalances[Int(transfer.from)] == transfer.amount + transfer.fee - || state.validatorBalances[Int(transfer.from)] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT - ) - - assert(state.slot == transfer.slot) - assert( - BeaconChain.getCurrentEpoch(state: state) >= state.validatorRegistry[Int(transfer.from)].withdrawableEpoch - || state.validatorRegistry[Int(transfer.from)].activationEpoch == FAR_FUTURE_EPOCH - ) - assert(state.validatorRegistry[Int(transfer.from)].withdrawalCredentials == BLS_WITHDRAWAL_PREFIX_BYTE + BeaconChain.hash(transfer.pubkey).suffix(from: 1)) - - assert( - BLS.verify( - pubkey: transfer.pubkey, - message: BeaconChain.signedRoot(transfer, field: "signature"), - signature: transfer.signature, - domain: state.fork.domain(epoch: transfer.slot.toEpoch(), type: .transfer) - ) - ) - - state.validatorBalances[Int(transfer.from)] -= transfer.amount + transfer.fee - state.validatorBalances[Int(transfer.to)] += transfer.amount - state.validatorBalances[Int(BeaconChain.getBeaconProposerIndex(state: state, slot: state.slot))] += transfer.fee - } - } - static func verifyMerkleBranch(leaf: Bytes32, branch: [Bytes32], depth: Int, index: Int, root: Bytes32) -> Bool { var value = leaf for i in 0..= GENESIS_SLOT) + assert(attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot) + assert(state.slot < attestation.data.slot + SLOTS_PER_EPOCH) + + let e = (attestation.data.slot + 1).toEpoch() >= BeaconChain.getCurrentEpoch(state: state) ? state.justifiedEpoch : state.previousJustifiedEpoch + assert(attestation.data.justifiedEpoch == e) + assert(attestation.data.justifiedBlockRoot == BeaconChain.getBlockRoot(state: state, slot: attestation.data.justifiedEpoch.startSlot())) + + assert( + state.latestCrosslinks[Int(attestation.data.shard)] == attestation.data.latestCrosslink || + state.latestCrosslinks[Int(attestation.data.shard)] == Crosslink( + epoch: attestation.data.slot.toEpoch(), + crosslinkDataRoot: attestation.data.crosslinkDataRoot + ) + ) + + assert(attestation.custodyBitfield == Data(repeating: 0, count: 32)) + assert(attestation.aggregationBitfield != Data(repeating: 0, count: 32)) + + let crosslinkCommittee = BeaconChain.crosslinkCommittees(state, at: attestation.data.slot).filter { + $0.1 == attestation.data.shard + }.first?.0 + + for i in 0..= transfer.amount) + assert(state.validatorBalances[Int(transfer.from)] >= transfer.fee) + assert( + state.validatorBalances[Int(transfer.from)] == transfer.amount + transfer.fee + || state.validatorBalances[Int(transfer.from)] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT + ) + + assert(state.slot == transfer.slot) + assert( + BeaconChain.getCurrentEpoch(state: state) >= state.validatorRegistry[Int(transfer.from)].withdrawableEpoch + || state.validatorRegistry[Int(transfer.from)].activationEpoch == FAR_FUTURE_EPOCH + ) + assert(state.validatorRegistry[Int(transfer.from)].withdrawalCredentials == BLS_WITHDRAWAL_PREFIX_BYTE + BeaconChain.hash(transfer.pubkey).suffix(from: 1)) + + assert( + BLS.verify( + pubkey: transfer.pubkey, + message: BeaconChain.signedRoot(transfer, field: "signature"), + signature: transfer.signature, + domain: state.fork.domain(epoch: transfer.slot.toEpoch(), type: .transfer) + ) + ) + + state.validatorBalances[Int(transfer.from)] -= transfer.amount + transfer.fee + state.validatorBalances[Int(transfer.to)] += transfer.amount + state.validatorBalances[Int(BeaconChain.getBeaconProposerIndex(state: state, slot: state.slot))] += transfer.fee + } + } +} diff --git a/Sources/BeaconChain/StateTransitions/Blocks/VoluntaryExits.swift b/Sources/BeaconChain/StateTransitions/Blocks/VoluntaryExits.swift new file mode 100644 index 0000000..25325c9 --- /dev/null +++ b/Sources/BeaconChain/StateTransitions/Blocks/VoluntaryExits.swift @@ -0,0 +1,27 @@ +import Foundation + +class VoluntaryExits: BlockTransitions { + + static func transition(state: inout BeaconState, block: BeaconBlock) { + assert(block.body.voluntaryExits.count <= MAX_VOLUNTARY_EXITS) + + for exit in block.body.voluntaryExits { + let validator = state.validatorRegistry[Int(exit.validatorIndex)] + + let epoch = BeaconChain.getCurrentEpoch(state: state) + assert(validator.exitEpoch > epoch.delayedActivationExitEpoch()) + assert(epoch >= exit.epoch) + + assert( + BLS.verify( + pubkey: validator.pubkey, + message: BeaconChain.signedRoot(exit, field: "signature"), + signature: exit.signature, + domain: state.fork.domain(epoch: exit.epoch, type: .exit) + ) + ) + + state.validatorRegistry[Int(exit.validatorIndex)].initiatedExit = true + } + } +}