Table of Contents

Verifier

A system that verifies the validity of a transaction, based the state of the stream and the ruleset.

Container diagram

Description

The verifier is a self contained system, that implements a single gRPC endpoint that takes a transaction and a stream of transactions, and returns a boolean value indicating if the transaction is valid or not.

The verifier is programmed and configured with a ruleset, that defines the rules for the transactions (rules of the network).

The verifier gets the current state of the stream (the list of transactions) and the transaction to verify. It then uses stream to build the actual state of the object, and based on the ruleset, it verifies the transaction. It returns a boolean value, indicating if the transaction is valid or not, and if not, it returns a reason why.

sequenceDiagram
    participant R as Registry
    participant V as Verifier
    R->>+V: VerifyTransaction(transaction, stream)
    V->>V: Build state from stream
    V->>V: Verify transaction against state

    alt is valid
        V->>R: Transaction is valid
    else is invalid
        V->>-R: Transaction is invalid (reason)
    end

Ruleset

The ruleset for different transactions can very if they are only code based or partly configurable.

The issuer verifier are configured with which issuer keys are valid for each grid area.

Verifier API

Below is the protobuf definition for the verifier API.

syntax = "proto3";

import "registry.proto";

package project_origin.verifier.v1;

service VerifierService {
    rpc VerifyTransaction(VerifyTransactionRequest) returns (VerifyTransactionResponse);
}

message VerifyTransactionRequest {
    project_origin.registry.v1.Transaction transaction = 1;
    repeated project_origin.registry.v1.Transaction stream = 2;
}

message VerifyTransactionResponse {
    bool valid = 1;
    // If the transaction is not valid, this will contain the reason why
    string error_message = 2;
}

Example verifier issuer verifier

Below one can see a implemented verifier. It takes, the transaction, the state object, and deserialized transaction, and verifies if it is valid based on the rules.

using ProjectOrigin.Electricity.Extensions;
using ProjectOrigin.Registry.V1;
using System.Threading.Tasks;
using ProjectOrigin.Electricity.Server.Models;
using ProjectOrigin.Electricity.Server.Interfaces;
using System;

namespace ProjectOrigin.Electricity.Server.Verifiers;

public class IssuedEventVerifier : IEventVerifier<V1.IssuedEvent>
{
    private readonly IGridAreaIssuerService _gridAreaIssuerService;

    public IssuedEventVerifier(IGridAreaIssuerService gridAreaIssuerService)
    {
        _gridAreaIssuerService = gridAreaIssuerService;
    }

    public Task<VerificationResult> Verify(Transaction transaction, GranularCertificate? certificate, V1.IssuedEvent payload)
    {
        if (certificate is not null)
            return new VerificationResult.Invalid($"Certificate with id ”{payload.CertificateId.StreamId}” already exists");

        if (!payload.QuantityCommitment.VerifyCommitment(payload.CertificateId.StreamId.Value))
            return new VerificationResult.Invalid("Invalid range proof for Quantity commitment");

        if (payload.Type == V1.GranularCertificateType.Invalid)
            return new VerificationResult.Invalid("Invalid certificate type");

        if (!payload.OwnerPublicKey.TryToModel(out _))
            return new VerificationResult.Invalid("Invalid owner key, not a valid publicKey");

        if (payload.Period.GetTimeSpan() > TimeSpan.FromHours(1))
            return new VerificationResult.Invalid("Invalid period, maximum period is 1 hour");

        if (payload.Period.GetTimeSpan() < TimeSpan.FromMinutes(1))
            return new VerificationResult.Invalid("Invalid period, minimum period is 1 minute");

        var areaPublicKey = _gridAreaIssuerService.GetAreaPublicKey(payload.GridArea);
        if (areaPublicKey is null)
            return new VerificationResult.Invalid($"No issuer found for GridArea ”{payload.GridArea}”");

        if (!transaction.IsSignatureValid(areaPublicKey))
            return new VerificationResult.Invalid($"Invalid issuer signature for GridArea ”{payload.GridArea}”");

        return new VerificationResult.Valid();
    }
}

System documentation

More documentation can be found in the verifier electricity project.