Skip to main content

AnteHandler

Dchain and other apps that use this AnteHandler decorator can specify fine-grained verifiable presentation requirements for individual messages in a transaction. Each required verifiable presentation is verified natively (in Go) before the messages are processed by the app.

For example, a cosmos.staking.v1beta1.MsgCreateValidator message can be gated so that it only passes if the transaction also carries an SD-JWT presentation whose disclosed validator claim equals the validator address in the message, derived from a credential issued by one of a set of trusted issuers. That requirement is configured in the message's Route (see state). The AnteHandler decorator looks up the Route for the message type, reads the presentation from the transaction's ExtensionOptions, and verifies it against the issuer's public JWK and requirements - no smart contract is invoked.

AnteHandler verifying ExtensionOptions

The decorator is VcvExtensionOptionsDecorator (x/vcv/ante/ante.go). It is constructed with a list of VPVerifierI keepers - the vcv keeper and any other module keeper (e.g. the x/notary keeper) that registers gated routes and reuses the verification.

The decorator's flow on each transaction is:

  1. If the block height is 0 (genesis), verification is skipped entirely.
  2. It extracts the VP ExtensionOptions from the transaction. A VP extension option is an Any whose type URL is the module's ExtensionOptionTypeUrl (/d.vcv.v1.VerifiablePresentation).
  3. For every message it counts how many require verification by asking each keeper IsMsgExtensionOptionsRequired(msg). The vcv keeper requires verification for cosmos.staking.v1beta1.MsgCreateValidator and cosmos.gov.v1.MsgVote.
  4. It asserts that the number of messages requiring verification equals the number of VP extension options provided; otherwise the transaction is rejected.
  5. For each message that requires verification it calls VerifyMsgExtensionOptions(msg, vp) with the next VP extension option in order.
TxBody {
Messages [MsgCreateValidator, MsgSend, MsgVote]
ExtensionOptions[VP1, VP2]
}

In this example MsgSend does not require a presentation, so only two VP extension options are supplied - one for MsgCreateValidator and one for MsgVote, matched in message order.

The ExtensionOptions value is the protobuf-encoded d.vcv.v1.VerifiablePresentation carrying a compact SD-JWT in its presentation bytes:

message VerifiablePresentation { bytes presentation = 1; }

If no Route is registered for a message that a keeper considers "required", verification returns ErrRouteNotFound, which the decorator tolerates - the message is allowed to pass. Any other verification error rejects the transaction.

Verification flow

VerifyMsgExtensionOptions (x/vcv/keeper/keeper_sdjwt_verify.go):

  1. Looks up the Route by proto.MessageName(msg).
  2. Unmarshals the extension option bytes into a VerifiablePresentation and reads the compact SD-JWT from presentation.
  3. Calls sdjwt.Verify(token, {Now: ctx.BlockTime(), IssuerKeysResolver: route}). The Route itself acts as the issuer-key resolver, supplying the issuer's public JWK for signature verification.
  4. For each of the issuer's content_requirements, resolves the requirement's Criterion against the disclosed claim and a compareTo value taken from the message - for MsgCreateValidator the message's validator address (claim validator), and for MsgVote the voter address (claim voter).

Verification in the proposal pipeline

Beyond the AnteHandler, the vcv keeper also verifies VPs in the ABCI proposal pipeline: the proposer's VP (MsgProcessProposal, comparing the proposer to the validator claim) and each validator's vote-extension VP (ValidatorVoteExtension, comparing the validator consensus address to the validator claim). The same VerifyVerifiablePresentation routine is used.

Implementation into app

The ExtensionOptions AnteHandler decorator is wired into the app's ante chain. In Dchain, see app/ante.go.