Ledger: Block Validation
Block validation is the process of applying a set of ledger rules to a candidate block before adding it to the blockchain and updating the state of the ledger. Each era has it’s own set of rules for block validation.
note
TODO: Write a full introduction here with relevant terminology and concepts defined.
While different node implementations may implement these rules in different ways, it’s vital that they all agree on the outcome of the validation process to prevent forks in the blockchain.
Conway Block Validation
In this section, we will walk through the cardano-ledger implementation of Conway era block validation. We will break up the validation process into smaller sections to make it easier to visualize and understand. All diagrams should be read from left to right and top to bottom in terms of order of execution.
The cardano-ledger has the concept of an EraRule, which is a set of validations that are applied to a block in a specific era. Often, a newer era may call a previous era’s EraRule instead of reimplementing the same logic.
EraRule BBODY
This is the “entrypoint” for block validation, responsible for validating the body of a block.
flowchart LR EBBC[EraRule BBODY Conway] EBBC --> CBBT[conwayBbodyTransition] CBBT --> totalScriptRefSize(totalScriptRefSize <= maxRefScriptSizePerBlock) CBBT --> S[(state)] EBBC --> ABBT[alonzoBbodyTransition] ABBT --> ELC[EraRule LEDGERS Conway] ABBT --> txTotalExUnits(txTotal <= ppMax ExUnits) ABBT --> BBodyState[(BbodyState @era ls')]
EraRule LEDGERS
This EraRule is responsible for validating and updating the ledger state, namely UTxO state, governance state, and certificate state.
flowchart LR ELC[EraRule LEDGERS Conway] ELC --> ELS[EraRule LEDGERS Shelley] ELS --> ledgersTransition ledgersTransition --> |repeat| ledgerTransition ledgerTransition --> |when mempool| EMC[EraRule Mempool Conway] EMC --> mempoolTransition mempoolTransition --> unelectedCommitteeMembers(failOnNonEmpty unelectedCommitteeMembers) ledgerTransition --> isValid{isValid} isValid --> |True| ltDoBlock[do] ltDoBlock --> |currentTreasuryValueTxBodyL| submittedTreasuryValue(submittedTreasuryValue == actualTreasuryValue) ltDoBlock --> totalRefScriptSize(totalRefScriptSize <= maxRefScriptSizePerTx) ltDoBlock --> nonExistentDelegations(failOnNonEmpty nonExistentDelegations) ltDoBlock --> ECSC[EraRule CERTS Conway] ltDoBlock --> EGC[EraRule GOV Conway] ltDoBlock --> utxoState[(utxoState', certStateAfterCerts)] isValid --> |False| utxoStateCertState[(utxoState, certState)] ledgerTransition --> EUC[EraRule UTXOW Conway]
EraRule CERTS
This EraRule is responsible for validating and updating the certificate state.
flowchart LR ECSC --> conwayCertsTransition conwayCertsTransition --> certificates{isEmpty certificates} certificates --> |True| cctDoBlock[do] cctDoBlock --> validateZeroRewards(validateZeroRewards) cctDoBlock --> certStateWithDrepExiryUpdated[(certStateWithDrepExiryUpdated)] certificates --> |False| sizeCheck{size > 1} sizeCheck --> |True| conwayCertsTransition sizeCheck --> |False| ECC[EraRule CERT Conway] ECC --> certTransition certTransition --> |ConwayTxCertDeleg| EDC[EraRule DELEG Conway] EDC --> conwayDelegTransition conwayDelegTransition --> |ConwayRegCert| crcDoBlock[do] crcDoBlock --> crcCheckDepositAgaintPParams(checkDespoitAgainstPParams) crcDoBlock --> crcCheckStakeKeyNotRegistered(checkStakeKeyNotRegistered) conwayDelegTransition --> |ConwayUnregCert| cucDoBlock[do] cucDoBlock --> checkInvalidRefund(checkInvalidRefund) cucDoBlock --> mUMElem(isJust mUMElem) cucDoBlock --> cucCheckStakeKeyHasZeroRewardBalance(checkStakeKeyHasZeroRewardBalance) conwayDelegTransition --> |ConwayDelegCert| cdcDoBlock[do] cdcDoBlock --> checkStakeKeyIsRegistered(checkStakeKeyIsRegistered) cdcDoBlock --> checkStakeDelegateeRegistered(checkStakeDelegateeRegistered) conwayDelegTransition --> |ConwayRegDelegCert| crdcDoBlock[do] crdcDoBlock --> checkDepositAgainstPParams(checkDepositAgainstPParams) crdcDoBlock --> checkStakeKeyNotRegistered(checkStakeKeyNotRegistered) crdcDoBlock --> checkStakeKeyZeroRewardBalance(checkStakeKeyHasZeroRewardBalance) certTransition --> EPC[EraRule POOL Conway] EPC --> EPS[EraRule POOL Shelley] EPS --> poolDelegationTransition poolDelegationTransition --> |regPool| rpDoBlock[do] rpDoBlock --> actualNetId(actualNetId == suppliedNetId) rpDoBlock --> pmHash(length pmHash <= sizeHash) rpDoBlock --> ppCost(ppCost >= minPoolCost) rpDoBlock --> ppId{ppId ∉ dom psStakePoolParams} ppId --> |True| payPoolDeposit --> psDeposits[(psDeposits)] ppId --> |False| psFutureStakePoolParams[(psFutureStakePoolParams, psRetiring)] poolDelegationTransition --> |RetirePool| retirePoolDoBlock[do] retirePoolDoBlock --> hk(hk ∈ dom psStakePoolParams) retirePoolDoBlock --> cEpoch(cEpoch < e && e <= limitEpoch) retirePoolDoBlock --> psRetiring[(psRetiring)] certTransition --> EGOVERTC[EraRule GOVERT Conway] EGOVERTC --> conwayGovCertTransition conwayGovCertTransition --> |ConwayRegDRep| crdrDoBlock[do] crdrDoBlock --> notMemberCredVsDReps(Map.notMember cred vsDReps) crdrDoBlock --> deposit(deposit == ppDRepDeposit) crdrDoBlock --> crdrDRepState[(dRepState)] conwayGovCertTransition --> |ConwayUnregDRep| curdrDoBlock[do] curdrDoBlock --> mDRepState(isJust mDRepState) curdrDoBlock --> drepRefundMismatch(failOnJust drepRefundMismatch) curdrDoBlock --> curdrDRepState[(dRepState)] conwayGovCertTransition -->|ConwayUpdateDRep| cudrDoBlock[do] cudrDoBlock --> memberCredVsDreps(Map.member cred vsDReps) cudrDoBlock --> cudrDRepState[(vsDReps)] conwayGovCertTransition --> |ConwayResignCommitteeColdKey| crcckDoBlock[do] conwayGovCertTransition --> |ConwayAuthCommitteeHotKey| cachkDoBlock[do] crcckDoBlock --> checkAndOverwriteCommitteMemberState cachkDoBlock --> checkAndOverwriteCommitteMemberState checkAndOverwriteCommitteMemberState --> coldCredResigned(failOnJust coldCredResigned) checkAndOverwriteCommitteMemberState --> isCurrentMember(isCurrentMember OR isPotentialFutureMember) checkAndOverwriteCommitteMemberState --> vsCommitteeState[(vsCommitteeState)]
EraRule GOV
This EraRule is responsible for validating and updating the governance state.
flowchart LR EGC[EraRule GOV Conway] EGC --> govTransition govTransition --> badHardFork(failOnJust badHardFork) govTransition --> actionWellFormed(actionWellFormed) govTransition --> refundAddress(refundAddress) govTransition --> nonRegisteredAccounts(nonRegisteredAccounts) govTransition --> pProcDepost(pProcDeposit == expectedDeposit) govTransition --> pProcReturnAddr(pProcReturnAddr == expectedNetworkId) govTransition --> govAction{case pProcGovAction} govAction --> |TreasuryWithdrawals| twDoBlock[do] twDoBlock --> mismatchedAccounts(mismatchedAccounts) twDoBlock --> twCheckPolicy(checkPolicy) govAction --> |UpdateCommittee| ucDoBlock[do] ucDoBlock --> setNull(Set.null conflicting) ucDoBlock --> mapNull(Map.null invalidMembers) govAction --> |ParameterChange| pcDoBlock[do] pcDoBlock --> checkPolicy(checkPolicy) govTransition --> ancestryCheck(ancestryCheck) govTransition --> unknownVoters(failOnNonEmpty unknownVoters) govTransition --> unknwonGovActionIds(failOnNonEmpty unknownGovActionIds) govTransition --> checkBootstrapVotes(checkBootstrapVotes) govTransition --> checkVotesAreNotForExpiredActions(checkVotesAreNotForExpiredActions) govTransition --> checkVotersAreValid(checkVotersAreValid) govTransition --> updatedProposalStates[(updatedProposalStates)]
EraRule UTXOW
This EraRule is responsible for validating and updating the UTxO state.
flowchart LR EUC[EraRule UTXOW Conway] EUC --> babbageUtxowTransition babbageUtxowTransition --> validateFailedBabbageScripts(validateFailedBabbageScripts) babbageUtxowTransition --> babbageMissingScripts(babbageMissingScripts) babbageUtxowTransition --> missingRequiredDatums(missingRequiredDatums) babbageUtxowTransition --> hasExactSetOfRedeemers(hasExactSetOfRedeemers) babbageUtxowTransition --> validateVerifiedWits(Shelley.validateVerifiedWits) babbageUtxowTransition --> validateNeededWitnesses(validateNeededWitnesses) babbageUtxowTransition --> validateMetdata(Shelley.validateMetadata) babbageUtxowTransition --> validateScriptsWellFormed(validateScriptsWellFormed) babbageUtxowTransition --> ppViewHashesMatch(ppViewHashesMatch) babbageUtxowTransition --> EUTXOC[EraRule UTXO Conway] EUTXOC --> utxoTransition utxoTransition --> disjointRefInputs(disjointRefInputs) utxoTransition --> validateOutsideValidityIntervalUtxo(Allegra.validateOutsideValidityIntervalUtxo) utxoTransition --> validateOutsideForecast(Alonzo.validateOutsideForecast) utxoTransition --> validateInputSetEmptyUTxO(Shelley.validateInputSetEmptyUTxO) utxoTransition --> feesOk(feesOk) utxoTransition --> validateBadInputsUTxO(Shelley.validateBadInputsUTxO) utxoTransition --> validateValueNotConservedUTxO(Shelley.validateValueNotConservedUTxO) utxoTransition --> validateOutputTooSmallUTxO(validateOutputTooSmallUTxO) utxoTransition --> validateOutputTooBigUTxO(Alonzo.validateOutputTooBigUTxO) utxoTransition --> validateOutputBootAddrAttrsTooBig(Shelley.validateOuputBootAddrAttrsTooBig) utxoTransition --> validateWrongNetwork(Shelley.validateWrongNetwork) utxoTransition --> validateWrongNetworkWithdrawal(Shelley.validateWrongNetworkWithdrawal) utxoTransition --> validateWrongNetworkInTxBody(Alonzo.validateWrongNetworkInTxBody) utxoTransition --> validateMaxTxSizeUTxO(Shelley.vallidateMaxTxSizeUTxO) utxoTransition --> validateExUnitsTooBigUTxO(Alonzo.validateExUnitsTooBigUTxO) utxoTransition --> EUTXOSC[EraRule UTXOS Conway] EUTXOSC --> utxosTransition utxosTransition --> isValidTxL{isValidTxL} isValidTxL --> |True| conwayEvalScriptsTxValid conwayEvalScriptsTxValid --> expectScriptsToPass(expactScriptsToPass) conwayEvalScriptsTxValid --> conwayEvalScriptsTxValidUtxosPrime[(utxos')] isValidTxL --> |False| babbageEvalScriptsTxInvalid babbageEvalScriptsTxInvalid --> evalPlutusScripts(evalPlutusScripts FAIL) babbageEvalScriptsTxInvalid --> babbageEvalScriptsTxInvalidUtxosPrime([utxos']) EUC --> LedgerState[(LedgerState utxoState'' certStateAfterCERTS)]
Full Diagram
Here is the full diagram, with all EraRules combined.
flowchart LR EBBC[EraRule BBODY Conway] EBBC --> CBBT[conwayBbodyTransition] CBBT --> totalScriptRefSize(totalScriptRefSize <= maxRefScriptSizePerBlock) CBBT --> S[(state)] EBBC --> ABBT[alonzoBbodyTransition] ABBT --> ELC[EraRule LEDGERS Conway] ELC --> ELS[EraRule LEDGERS Shelley] ELS --> ledgersTransition ledgersTransition --> |repeat| ledgerTransition ledgerTransition --> |when mempool| EMC[EraRule Mempool Conway] EMC --> mempoolTransition mempoolTransition --> unelectedCommitteeMembers(failOnNonEmpty unelectedCommitteeMembers) ledgerTransition --> isValid{isValid} isValid --> |True| ltDoBlock[do] ltDoBlock --> |currentTreasuryValueTxBodyL| submittedTreasuryValue(submittedTreasuryValue == actualTreasuryValue) ltDoBlock --> totalRefScriptSize(totalRefScriptSize <= maxRefScriptSizePerTx) ltDoBlock --> nonExistentDelegations(failOnNonEmpty nonExistentDelegations) ltDoBlock --> ECSC[EraRule CERTS Conway] ECSC --> conwayCertsTransition conwayCertsTransition --> certificates{isEmpty certificates} certificates --> |True| cctDoBlock[do] cctDoBlock --> validateZeroRewards(validateZeroRewards) cctDoBlock --> certStateWithDrepExiryUpdated[(certStateWithDrepExiryUpdated)] certificates --> |False| sizeCheck{size > 1} sizeCheck --> |True| conwayCertsTransition sizeCheck --> |False| ECC[EraRule CERT Conway] ECC --> certTransition certTransition --> |ConwayTxCertDeleg| EDC[EraRule DELEG Conway] EDC --> conwayDelegTransition conwayDelegTransition --> |ConwayRegCert| crcDoBlock[do] crcDoBlock --> crcCheckDepositAgaintPParams(checkDespoitAgainstPParams) crcDoBlock --> crcCheckStakeKeyNotRegistered(checkStakeKeyNotRegistered) conwayDelegTransition --> |ConwayUnregCert| cucDoBlock[do] cucDoBlock --> checkInvalidRefund(checkInvalidRefund) cucDoBlock --> mUMElem(isJust mUMElem) cucDoBlock --> cucCheckStakeKeyHasZeroRewardBalance(checkStakeKeyHasZeroRewardBalance) conwayDelegTransition --> |ConwayDelegCert| cdcDoBlock[do] cdcDoBlock --> checkStakeKeyIsRegistered(checkStakeKeyIsRegistered) cdcDoBlock --> checkStakeDelegateeRegistered(checkStakeDelegateeRegistered) conwayDelegTransition --> |ConwayRegDelegCert| crdcDoBlock[do] crdcDoBlock --> checkDepositAgainstPParams(checkDepositAgainstPParams) crdcDoBlock --> checkStakeKeyNotRegistered(checkStakeKeyNotRegistered) crdcDoBlock --> checkStakeKeyZeroRewardBalance(checkStakeKeyHasZeroRewardBalance) certTransition --> EPC[EraRule POOL Conway] EPC --> EPS[EraRule POOL Shelley] EPS --> poolDelegationTransition poolDelegationTransition --> |regPool| rpDoBlock[do] rpDoBlock --> actualNetId(actualNetId == suppliedNetId) rpDoBlock --> pmHash(length pmHash <= sizeHash) rpDoBlock --> ppCost(ppCost >= minPoolCost) rpDoBlock --> ppId{ppId ∉ dom psStakePoolParams} ppId --> |True| payPoolDeposit --> psDeposits[(psDeposits)] ppId --> |False| psFutureStakePoolParams[(psFutureStakePoolParams, psRetiring)] poolDelegationTransition --> |RetirePool| retirePoolDoBlock[do] retirePoolDoBlock --> hk(hk ∈ dom psStakePoolParams) retirePoolDoBlock --> cEpoch(cEpoch < e && e <= limitEpoch) retirePoolDoBlock --> psRetiring[(psRetiring)] certTransition --> EGOVERTC[EraRule GOVERT Conway] EGOVERTC --> conwayGovCertTransition conwayGovCertTransition --> |ConwayRegDRep| crdrDoBlock[do] crdrDoBlock --> notMemberCredVsDReps(Map.notMember cred vsDReps) crdrDoBlock --> deposit(deposit == ppDRepDeposit) crdrDoBlock --> crdrDRepState[(dRepState)] conwayGovCertTransition --> |ConwayUnregDRep| curdrDoBlock[do] curdrDoBlock --> mDRepState(isJust mDRepState) curdrDoBlock --> drepRefundMismatch(failOnJust drepRefundMismatch) curdrDoBlock --> curdrDRepState[(dRepState)] conwayGovCertTransition -->|ConwayUpdateDRep| cudrDoBlock[do] cudrDoBlock --> memberCredVsDreps(Map.member cred vsDReps) cudrDoBlock --> cudrDRepState[(vsDReps)] conwayGovCertTransition --> |ConwayResignCommitteeColdKey| crcckDoBlock[do] conwayGovCertTransition --> |ConwayAuthCommitteeHotKey| cachkDoBlock[do] crcckDoBlock --> checkAndOverwriteCommitteMemberState cachkDoBlock --> checkAndOverwriteCommitteMemberState checkAndOverwriteCommitteMemberState --> coldCredResigned(failOnJust coldCredResigned) checkAndOverwriteCommitteMemberState --> isCurrentMember(isCurrentMember OR isPotentialFutureMember) checkAndOverwriteCommitteMemberState --> vsCommitteeState[(vsCommitteeState)] ltDoBlock --> EGC[EraRule GOV Conway] EGC --> govTransition govTransition --> badHardFork(failOnJust badHardFork) govTransition --> actionWellFormed(actionWellFormed) govTransition --> refundAddress(refundAddress) govTransition --> nonRegisteredAccounts(nonRegisteredAccounts) govTransition --> pProcDepost(pProcDeposit == expectedDeposit) govTransition --> pProcReturnAddr(pProcReturnAddr == expectedNetworkId) govTransition --> govAction{case pProcGovAction} govAction --> |TreasuryWithdrawals| twDoBlock[do] twDoBlock --> mismatchedAccounts(mismatchedAccounts) twDoBlock --> twCheckPolicy(checkPolicy) govAction --> |UpdateCommittee| ucDoBlock[do] ucDoBlock --> setNull(Set.null conflicting) ucDoBlock --> mapNull(Map.null invalidMembers) govAction --> |ParameterChange| pcDoBlock[do] pcDoBlock --> checkPolicy(checkPolicy) govTransition --> ancestryCheck(ancestryCheck) govTransition --> unknownVoters(failOnNonEmpty unknownVoters) govTransition --> unknwonGovActionIds(failOnNonEmpty unknownGovActionIds) govTransition --> checkBootstrapVotes(checkBootstrapVotes) govTransition --> checkVotesAreNotForExpiredActions(checkVotesAreNotForExpiredActions) govTransition --> checkVotersAreValid(checkVotersAreValid) govTransition --> updatedProposalStates[(updatedProposalStates)] ltDoBlock --> utxoState[(utxoState', certStateAfterCerts)] isValid --> |False| utxoStateCertState[(utxoState, certState)] ledgerTransition --> EUC[EraRule UTXOW Conway] EUC --> babbageUtxowTransition babbageUtxowTransition --> validateFailedBabbageScripts(validateFailedBabbageScripts) babbageUtxowTransition --> babbageMissingScripts(babbageMissingScripts) babbageUtxowTransition --> missingRequiredDatums(missingRequiredDatums) babbageUtxowTransition --> hasExactSetOfRedeemers(hasExactSetOfRedeemers) babbageUtxowTransition --> validateVerifiedWits(Shelley.validateVerifiedWits) babbageUtxowTransition --> validateNeededWitnesses(validateNeededWitnesses) babbageUtxowTransition --> validateMetdata(Shelley.validateMetadata) babbageUtxowTransition --> validateScriptsWellFormed(validateScriptsWellFormed) babbageUtxowTransition --> ppViewHashesMatch(ppViewHashesMatch) babbageUtxowTransition --> EUTXOC[EraRule UTXO Conway] EUTXOC --> utxoTransition utxoTransition --> disjointRefInputs(disjointRefInputs) utxoTransition --> validateOutsideValidityIntervalUtxo(Allegra.validateOutsideValidityIntervalUtxo) utxoTransition --> validateOutsideForecast(Alonzo.validateOutsideForecast) utxoTransition --> validateInputSetEmptyUTxO(Shelley.validateInputSetEmptyUTxO) utxoTransition --> feesOk(feesOk) utxoTransition --> validateBadInputsUTxO(Shelley.validateBadInputsUTxO) utxoTransition --> validateValueNotConservedUTxO(Shelley.validateValueNotConservedUTxO) utxoTransition --> validateOutputTooSmallUTxO(validateOutputTooSmallUTxO) utxoTransition --> validateOutputTooBigUTxO(Alonzo.validateOutputTooBigUTxO) utxoTransition --> validateOutputBootAddrAttrsTooBig(Shelley.validateOuputBootAddrAttrsTooBig) utxoTransition --> validateWrongNetwork(Shelley.validateWrongNetwork) utxoTransition --> validateWrongNetworkWithdrawal(Shelley.validateWrongNetworkWithdrawal) utxoTransition --> validateWrongNetworkInTxBody(Alonzo.validateWrongNetworkInTxBody) utxoTransition --> validateMaxTxSizeUTxO(Shelley.vallidateMaxTxSizeUTxO) utxoTransition --> validateExUnitsTooBigUTxO(Alonzo.validateExUnitsTooBigUTxO) utxoTransition --> EUTXOSC[EraRule UTXOS Conway] EUTXOSC --> utxosTransition utxosTransition --> isValidTxL{isValidTxL} isValidTxL --> |True| conwayEvalScriptsTxValid conwayEvalScriptsTxValid --> expectScriptsToPass(expactScriptsToPass) conwayEvalScriptsTxValid --> conwayEvalScriptsTxValidUtxosPrime[(utxos')] isValidTxL --> |False| babbageEvalScriptsTxInvalid babbageEvalScriptsTxInvalid --> evalPlutusScripts(evalPlutusScripts FAIL) babbageEvalScriptsTxInvalid --> babbageEvalScriptsTxInvalidUtxosPrime([utxos']) EUC --> LedgerState[(LedgerState utxoState'' certStateAfterCERTS)] ABBT --> txTotalExUnits(txTotal <= ppMax ExUnits) ABBT --> BBodyState[(BbodyState @era ls')]