TrackVac — Track COVID-19 Vaccination on Blockchain

Andriy Shapochka
TechTale
Published in
15 min readDec 15, 2020

In this story, we conceptualize and architect a Blockchain based approach to the problem of trustworthy and efficient validation of the international travelers vaccinated against COVID-19. We also build and discuss a smart contract prototypes to demo our architecture with the working code.

Problem

It a few months vaccination against COVID-19 will become a widespread powerful tool fighting the pandemic. When this happens, to protect their citizens, governments around the globe will most likely be introducing changes to the rules of entry for the foreign travelers involving the proof of mandatory vaccination with one of the certified vaccines.

There are a few important concerns to account for in that new reality:

  • Each sovereign nation will have its own rules, legislation, capabilities affecting vaccination of its citizens: which vaccines are approved, what medical facilities administer them, how vaccinated citizens are certified
  • Travel and, especially, border crossing is already overloaded with various checks. One more check for vaccination at the border must be efficient, fast, trustworthy, and reliable with minimal paperwork
  • Countries build their national registries to the own standards. Integration across a hundred plus of country-specific registries can be a years-long project, not ready to serve authorities, airlines, hotels, medical centers around the globe to simplify vaccination data exchange and access anytime soon

We ask ourselves a question — how technology can help address these points with speed and elegance.

Blockchain to Rescue

We have more than a hundred of independent parties (nations represented by their governments) in the need of collaboration in vaccination data exchange and verification. Each of the parties wants to own and to be able to access relevant vaccination data at all times. Each of them wants transparency of the rules from the others and ability to decide on the own rules.

We claim this case maps well to the distributed multi-node blockchain ledger serving as a technology underlying an international consortium of the nations. Each country participates in the consortium network by owning one or multiple peer nodes connected to it and storing shared transactional data in their local copies of the ledger.

Architecting for Vaccination Validation

To show our approach to the vaccination validation in action and support our bold claim both with analysis and runnable proof of concept we concentrate on the scenario:

  1. A traveler comes for COVID-19 vaccination to one of the official vaccination centers in the country of residence
  2. The vaccination center administers a shot of vaccine and issues a vaccination certificate to the traveler
  3. The traveler provides the certificate to the authority or an agent acting on behalf of the authority, e.g. an airport or airline to prove compliance with the vaccination rules of the destination country or region
  4. The authority validates the certificate and either allows or denies the traveler entrance to the country

Key points, in this scenario, are: support of the online submission of the certificate by the traveler or on behalf of the traveler, utmost automation of the validation rules, seamless cross-border interoperability of the authority certifying vaccination and the authority validating vaccination.

The figure depicts this scenario in detail with emphasis on the role of a Blockchain consortium in its successful execution.

Scenario execution based on Blockchain technology

The conceptual architecture relies on a few ideas:

  • Record issued vaccination certificates on the Blockchain ledger shared among all participating countries by Blockchain consensus
  • Use crypto-hashes of certificates as a verifiable proof of the certification held by the traveler. Validation of these proofs is key to vaccination validation
  • Use crypto-hashes of traveler’s passport or similar ID to be able to validate traveler’s identity while avoiding to store any sensitive personal data on the ledger
  • Build the core of the distributed system with smart contracts supporting vaccination center registration, and vaccination certificate registration, and validation with a set of rules customizable by country
  • Let vaccination centers, airlines, and authorities execute business logic and access data shared by means of these smart contracts as a single, albeit highly replicated, source of truth

Next figure zooms into the three smart contracts comprising the system’s core.

Vaccination Registry is a contract central to the entire system, providing the data structure to store vaccination proofs/certificates and methods to register and validate them.

Vaccination Center Registry implements registration and validation of vaccination centers officially operating in the collaborating countries.

Vaccination Acceptance Rules is a contract providing each country’s government with a capability to set up their own validation rules such as acceptable time period passed since vaccination and the list of nationally approved vaccines.

Enforcing Trust

Having defined the conceptual architectural approach, we need to clearly understand how trust is supported and enforced in this system.

There are legal sources of trust, that we typically expect to find in the context of international affairs.

  • The primary basis is the legal agreements achieved among the participating governments guaranteeing the proper access control for the Blockchain nodes owned by the governments. This control should prevents unauthorized vaccination center registration or changes in vaccination acceptance rules
  • Each licensed and registered vaccination center takes a legal responsibility of entering valid vaccination data for the travelers

There are Blockchain technology specific sources enforcing trust in the system data.

  • Each transaction is signed by the sending vaccination center and is committed by the consensus of the nodes. Once committed, it is replicated to the nodes owned by each country
  • Transactions stored in the ledger cannot be modified or erased
  • The center committing a new certificate is validated by the smart contract to be one of the officially registered centers
  • Rules validating certificates are automated by the smart contracts and rely on the data recorded to the ledger by the proper authorities. This approach eliminates people factor in validation and enforces its transparency and repeatability
  • Strong cryptography is used to produce certificate and person identity proofs as well as to guarantee blockchain data integrity
  • All operations on the ledger can transparently be protected with regular “own resource and grant/deny permission” access controls implemented with smart contracts

As a whole, this combination of legal and technical means ensures the level of trust in the vaccination validation procedure that might easily surpass conventional manual checks of the vaccination paperwork.

Automation and Efficiency

One highly important benefit of our architecture is its efficiency achieved by means of the high level of automation.

Operations implementing vaccination validation rules are coded as smart contracts in a programming language and deployed on the ledger ready to call from the front-ends or other clients. They offload much of manual work from the personnel responsible for those checks. And at the same time if properly automated these smart contract driven tasks are much more accurate and harder to circumvent.

The traveler submits the certificate proof by entering its hash number or by scanning a QR code at the time of the online flight check-in and the person id is verified against passport data entered at the same check-in form. The airline system verifies the submitted proof automatically by calling the Vaccination Registry smart contract and either approves or denies the check-in based on the Vaccination Acceptance Rules smart contract. If approved the traveler presenting or scanning their passport or another supported ID at the airport automatically confirms the certificate is theirs and is approved for the flight.

Compare the above with more conventional scenarios of putting the burden of validation on the airline or airport staff directly (for example, as we witness in the case of COVID-19 test validation at present), causing extra lines and extra wait times added up to the already long and tiresome process of getting from the airport entrance to the concourse gate and the inherent efficiency of the mathematically provable, almost fully automated validation, that does not take extra time at the airport at all, becomes obvious.

One more contributor to efficiency is the possibility to validate vaccination rules as early as at the check-in time instead of the arrival time at the destination. This offloads the staff at the destination and greatly improves peace of traveler’s minds who, once approved online, can be sure they will not be denied entry due to vaccination issues at their arrival.

Why Not Centralize

When we come up with one more cool idea to put on the Blockchain one of the first questions to ask ourselves should be: whether the conventional “centralized” architecture can let us build the same solution for the lower budget or, in other words, what extra benefit Blockchain brings to the table that we cannot get at the lower price of commoditized database technologies.

In the case we design for in this post the answer is relatively simple: sovereign nations would likely tend to avoid setting up one more central international authority concentrating vaccination validation functions in its hands. The same way they manage and enforce their other rules for travelers crossing sovereign borders not relying on any international super-authority. Each country oversees and controls their vaccination network and wants control over the rules affecting its situation with pandemic as well. As an example, in the past COVID-19 caused EU countries to temporarily make borders much less transparent even within the Union itself.

Blockchain naturally fits the concept of sovereignty — each country decides to join the consortium or retract at its own free will, when it sees it appropriate and keeps all the data and admittance controls at its own hands, protecting and guarding them at the national level as required by the national legislation. An extremely constrained set of data only (vaccination certificates and data required to validate them) is shared among participating countries for the common benefit.

Proof of Concept

Next, we discuss a proof of concept prototype demonstrating the envisioned architecture with two scenarios: vaccination certificate registration by a vaccination center and validation by an airline or another authority.

Technology Stack

We implement the prototype functionality (certificate registration and validation) as Solidity smart contracts. The scenarios themselves are coded in the form of unit tests executing these smart contracts deployed on the fly in the Ganache virtual machine simulating Ethereum Virtual Machine (EVM). The entire project relies on the brownie smart contract development framework.

The entire source code of the proof of concept is available in the git repository at https://github.com/ashapochka/trackvac.

Our choice of the technology stack indicates our decision to base the prototype implementation on the Ethereum or Quorum platform. There are multiple open source blockchain or distributed ledger platforms available on the market today. While sharing the common concept of distributed state machine coupled with an append-only replicated database they are built with different business scenarios in mind and have different levels of maturity. The Ethereum based stack is one of the most mature platforms. It is easy to develop for as long as the engineer has learned a few simple development tools and one of its smart contract programming languages, either Solidity or Viper. Smart contracts built with this stack are compatible with both public Ethereum and enterprise Ethereum (e.g. Consensys Quorum).

While the actual deployment concern is outside of the scope of this proof of concept it is worth mentioning that consortiums like the one we discuss are typically built on the enterprise blockchain network deployments closed from the outer world by default. Indeed, only a country signing the vaccination validation treaty with other participating countries should be able to join the consortium with its array of Blockchain peer nodes.

Next two subsections outline our take on the implementation of the certificate registration and validation scenarios.

Certificate Registration Scenario

The figure shows collaboration of different entities to execute registration of a new vaccination certificate for a traveler.

Registration scenario sequence diagram

The scenario does a few important things: establishment of the traveler’s identity on the ledger in a way that precludes recording and distributing any personal data, verification of the vaccination center trying to register the certificate, finally, generation of the proof of the issued certificate and registration of this certificate on the ledger.

The storage facility for the vaccination certificates is defined in the VaccinationRegistry.sol as a mapping of Vaccination records (essentially, an unbounded hash map growing as needed).

contract VaccinationRegistry {
struct Vaccination {
bool isRegistered;
uint256 centerId;
uint256 timestamp;
string vaccineCodeType;
string vaccineCode;
bytes32 personId;
}

VaccinationCenterRegistry public vaccinationCenterRegistry;
VaccinationAcceptanceRules public vaccinationAcceptanceRules;

mapping(bytes32 => Vaccination) public vaccinations;

We record the essential vaccination data only, including: the center which administered the shot of vaccine, timestamp of this event, what vaccine was used, and the deindentified person id.

Certificate proofs are used in the quality of vaccination mapping keys laying the foundation for the validation procedure defined in the next section.

To standardize person id computation while avoiding recording of the actual personal data in the transaction log we define a pure function computing the Keccak 256 hash of the combined personal data fields in the same smart contract that will be run without committing a transaction to the ledger.

function computePersonId(
string memory _fullName,
string memory _birthDate,
string memory _passportNumber,
string memory _nationality
) public pure returns(bytes32) {
bytes32 personId = keccak256(
abi.encode(
_fullName, _birthDate, _passportNumber, _nationality
)
);
return personId;
}

We do the same trick to compute certificate proofs in the smart contract. But now this is done not to de-identify yet to obtain a compact piece of data serving both as the key in the mapping of the vaccinations as defined above and the certificate proof the traveler can keep in the electronic form or as part of the printed record for future validations.

function computeCertificateProof(
uint256 _centerId,
uint256 _timestamp,
string memory _vaccineCodeType,
string memory _vaccineCode,
bytes32 _personId
) public pure returns(bytes32) {
bytes32 proof = keccak256(
abi.encode(
_centerId, _timestamp, _vaccineCodeType, _vaccineCode, _personId
)
);
return proof;
}

Based on the above the registration implementation works simple: validate the vaccination center registering the certificate, then compute the proof, and finally record the vaccination itself.

function registerVaccination(
uint256 _centerId,
uint256 _timestamp,
string memory _vaccineCodeType,
string memory _vaccineCode,
bytes32 _personId
) public returns(bytes32) {
vaccinationCenterRegistry.validateCenter(_centerId, msg.sender);
bytes32 recordId = computeCertificateProof(
_centerId, _timestamp, _vaccineCodeType, _vaccineCode, _personId
);
Vaccination storage record = vaccinations[recordId];
record.isRegistered = true;
record.centerId = _centerId;
record.timestamp = _timestamp;
record.vaccineCodeType = _vaccineCodeType;
record.vaccineCode = _vaccineCode;
record.personId = _personId;
return recordId;
}

The test file test_vcr.py runs unit tests for the smart contracts based on the pytest, brownie, and ganache capabilities. It also conveniently serves to demo the scenarios from the perspective of the various actors participating in the scenarios.

The function below tests successful certificate registration path starting with the call of certify_vaccination. As soon as the certificate is registered the certificate proof becomes available (by means of return recordId; in the smart contract method function registerVaccination).

def test_register_vaccination(vcr, vr, accounts):
"""
a trusted registered center can successfully register its vaccinations
:param vcr:
:param vr:
:return:
"""
center = municipal_vac_12(accounts[1])
register_center(vcr, center)
certificate = certify_vaccination(
vr, center, jane_smith, coronavac
)
register_certificate(vr, center, certificate)
assert certificate.proof
vac = vr.vaccinations.call(certificate.proof)
assert vac[0] is True
assert vac[1] == certificate.center_id
assert vac[2] == certificate.vaccination_time.timestamp()
assert vac[3] == certificate.vaccine.code_type
assert vac[4] == certificate.vaccine.code
assert vac[5] == certificate.person_id

But if, for instance, a fake vaccination center gets access to the system API and tries to submit a vaccination certificate, the smart contract will reject certificate registration as in the next test. In this case the system checks the center’s account signing and sending the transaction is invalid. See details how this check works in VaccinationCenterRegistry.sol.

def test_register_vaccination_fails_center_address_invalid(vcr, vr, accounts):
"""
tests the case, when a fake center pretends to be a valid center
using its registration information but fails certificate registration
from a fake address (the valid account will be locked without knowing
a password in the realistic deployment)

:param vcr:
:param vr:
:return:
"""
center = municipal_vac_12(accounts[1])
fake_address = accounts[2]
register_center(vcr, center)
certificate = certify_vaccination(
vr, center, jane_smith, coronavac
)
# noinspection PyUnresolvedReferences
with brownie.reverts(
"Registered center's address is different from the passed address"
):
register_certificate(
vr, center, certificate,
center_address=fake_address
)

In a real world implementation this skeletal registration process can be extended to support extra rules and steps, allow for more or different fields in the personal data and certificates, or call an external government registry via an oracle to perform vaccination center credentials verification.

Certificate Validation Scenario

Now, we are capable of entering vaccination certificates into the distributed ledger and it is high time to talk about their validation.

The validation scenario assumes the traveler already possesses the certificate proof which is registered on the ledger and is about to submit it at the flight check-in or at the airport.

Validation scenario sequence diagram

Upon confirmation of the traveler’s identity and reception of the certificate proof the airline interface calls into the smart contract to verify the certificate by a few rules:

  • The certificate with this proof (hash) is indeed registered on the ledger
  • The person associated with this certificate and the person who has submitted the certificate proof have the same personal data (name, passport number, date of birth, etc.)
  • Vaccination was done within the accepted time frame
  • The administered vaccine is on the list of the accepted vaccines in the destination area

If all the requirements are passed the traveler is permitted to check-in, otherwise the flight is denied.

The validation function defined in the VaccinationRegistry is rather small because it validates only the first two rules regarding certificate registration and person id and delegates the rest to another contract VaccinationAcceptanceRules.

function validateVaccination(
string memory _area,
uint256 _departureTime,
bytes32 _certificateProof,
bytes32 _personId
) public view {
Vaccination storage record = vaccinations[_certificateProof];
require(record.isRegistered, "Vaccination is not registered");
require(record.personId == _personId, "Vaccinated person mismatch is detected");
vaccinationAcceptanceRules.validateVaccination(
_area, _departureTime, record.timestamp,
record.vaccineCodeType, record.vaccineCode
);
}

VaccinationAcceptanceRules.sol defines a configurable validation rule engine. For the purpose of demonstration it supports two types of rules only: time of vaccination within the limits and whether the vaccine is accepted. Nothing prevents us from adding more types of rules though.

To make these rules customizable per region or country the dynamic mapping storing RuleSets is declared. Time is stored as the number of seconds from the Unix epoch. Vaccine hashes mapped to true define the set of vaccines accepted for the target area.

struct RuleSet {
bool isRegistered;
uint256 timeBeforeDeparture;
mapping(bytes32 => bool) vaccines;
}

mapping(string => RuleSet) public rules;

Based on this structure the validation function is straightforward. It checks time of the vaccination and inclusion of the vaccine in the list of accepted vaccines. As a side note, the validation does not require a transaction commit which makes it fast and idempotent.

function validateVaccination(
string memory _area,
uint256 _departureTime,
uint256 _vaccinationTime,
string memory _vaccineCodeType,
string memory _vaccineCode
) public view {
RuleSet storage ruleSet = rules[_area];
require(
ruleSet.isRegistered,
"Vaccination rules are not registered for the area"
);

uint256 passedTime = _departureTime.sub(_vaccinationTime);
require(
ruleSet.timeBeforeDeparture >= passedTime,
"Vaccination time is too far in the past"
);

bytes32 vaccineId = keccak256(abi.encode(_vaccineCodeType, _vaccineCode));
bool acceptedVaccine = ruleSet.vaccines[vaccineId];
require(
acceptedVaccine,
"The used vaccine is not accepted in the area"
);
}

The following test executes the entire success path of the certificate vaccination and validation. The validation itself consists of two steps:

  1. An airline computes the person id from the personal data the same way the id was computed at the time the certificate was issued. This step involves a call to the smart contract but does not execute in the transactional scope and does not record any trace of the personal data to the ledger
  2. The actual validation of the sequence of the defined rules happens, again, as a non-transactional call to the smart contract (validateVaccination is invoked)
def test_validate_vaccination(vcr, var, vr, accounts):
vac_center = municipal_vac_12(accounts[1])
arrival_area = 'Garivas'
time_before_departure = timedelta(days=30)
accepted_vaccines = [coronavac]
traveler = jane_smith
vac_time = datetime.fromisoformat('2020-12-10 11:30')
vaccine = accepted_vaccines[0]
departure_time = vac_time + timedelta(days=10)
airport_address = accounts[3]

# register vaccination centers and validation rules as a prerequisite
# to scenario execution
register_center(vcr, vac_center)
register_rules(var, arrival_area, time_before_departure, accepted_vaccines)

# vaccination center vaccinates the traveler and registers
# traveler's vaccination certificate
certificate = certify_vaccination(
vr, vac_center, traveler, vaccine, vaccination_time=vac_time
)
register_certificate(vr, vac_center, certificate)

# an airport where the traveler either departs from or arrives in
# validates the vaccination certificate presented by the traveler
traveler_id = compute_person_id(vr, traveler)
validate_vaccination(
vr, arrival_area, departure_time,
certificate.proof, traveler_id,
airport_address
)

To test one of possible rule failure branches the test below does the same steps with a different type of vaccine which is not whitelisted for the destination area. As a result the corresponding rule in the smart contract is failed and the validation itself fails.

def test_validate_vaccination_fails_vaccine_not_accepted(
vcr, var, vr, accounts
):
vac_center = municipal_vac_12(accounts[1])
arrival_area = 'Garivas'
time_before_departure = timedelta(days=30)
accepted_vaccines = [coronavac]
traveler = jane_smith
vac_time = datetime.fromisoformat('2020-12-10 11:30')
vaccine = sputnikvac
departure_time = vac_time + timedelta(days=15)
airport_address = accounts[3]

# register vaccination centers and validation rules as a prerequisite
# to scenario execution
register_center(vcr, vac_center)
register_rules(var, arrival_area, time_before_departure, accepted_vaccines)

# vaccination center vaccinates the traveler and registers
# traveler's vaccination certificate
certificate = certify_vaccination(
vr, vac_center, traveler, vaccine, vaccination_time=vac_time
)
register_certificate(vr, vac_center, certificate)

# an airport where the traveler either departs from or arrives in
# validates the vaccination certificate presented by the traveler
# validation is failed because the vaccine is not on the accepted list
traveler_id = compute_person_id(vr, traveler)
# noinspection PyUnresolvedReferences
with brownie.reverts(
"The used vaccine is not accepted in the area"
):
validate_vaccination(
vr, arrival_area, departure_time,
certificate.proof, traveler_id,
airport_address
)

The prototype code linked from this post implements more tests covering all the implemented rules ensuring proper test coverage and demonstration of all the important branches of the scenarios.

Final Thoughts

This concludes our discussion of the vaccination validation architecture and the proof of concept based on the Blockchain technology. The presented prototype is quite far from the production quality or functional completeness. At the same time, it hopefully proves Blockchain may potentially be a good match for the challenges of the global scope, challenges affecting the whole of humankind, all due to the fact architecture of Blockchain itself was created with the concept of decentralized trust and integrity in mind and so it fits perfectly well inherently decentralized, collaborative scenarios where multiple independent parties act for the common good in a consortium.

If you have further questions please create an issue for the repository at https://github.com/ashapochka/trackvac.

--

--

Andriy Shapochka
TechTale

Software architect, who’s been working in software engineering for more than two decades. Interested in technical debt, architecture design, blockchain