-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
# Introduction | ||
|
||
cardano-data-lite (CDL) was written as a web-native replacement to | ||
[cardano-serialization-lib](https://github.com/emurgo/cardano-serialization-lib), hence it | ||
uses CSL itself for testing compatibility. | ||
|
||
CDL should be able to deserialize most existing Cardano transactions and re-create them with | ||
bit-by-bit compatibility. It also features a nearly identical interface to CSL, making it | ||
ideally a very low-effort task to replace one by the other. | ||
|
||
## Compatibility goals | ||
|
||
CDL makes the following compatility claims: | ||
|
||
1. If a class or method is available in CSL, *in most cases* it will also be provided | ||
by CDL with a nearly identical interface (see [Types and methods normalization]). | ||
|
||
However, some deprecated or utility classes that CSL offers are deliberately not implemented | ||
(see the [The API suite]). | ||
|
||
2. CDL should be able to deserialize any Conway-era transaction and serialize it with an | ||
*identical* wire representation (the CBOR representation should be the same). | ||
|
||
Note that this applies to *whole* transactions. This means CDL can and does encode certain | ||
transaction parts differently to CSL (see [Encoding of tagged sum variants]). | ||
This is allowed because it simplifies the implementation of the library and it does not | ||
compromise the ability of CDL of handling arbitrary transactions. | ||
|
||
To test the achievement of each goal, a test suite has been implemented. | ||
|
||
## The API suite | ||
|
||
The CDL interface is tested by the API suite, implemented in `api/test.ts`. What the suite does is: | ||
|
||
1. Parse the declaration files of the CSL and CDL libraries and collect all | ||
method declarations (For each class: method name, argument types, return type). | ||
2. Perform a normalization on these declarations (see [Types and methods normalization]) | ||
3. Compare the type declaration of each method in the CSL interface to the corresponding | ||
type declaration in the CDL interface. If they are equal, the test passes. | ||
|
||
The suite also performs a coverage test which checks that all methods in the CSL | ||
interface are also available in the CDL interface. However, some coverage exceptions | ||
exist, and these are specified in the `class-info.json` file, under the `api_ignore_classes` | ||
and `api_ignore_methods` fields. | ||
|
||
TODO: Check that these ignored classes/methods are up to date and we are not ignoring | ||
unnecessary parts of the API. | ||
|
||
## The serialization suite | ||
|
||
The (de)serialization capabilities are tested in `serialization/serialization.test.ts`. | ||
|
||
The suite runs on a set of `staging` and `regression` transactions. Transactions can be fetched | ||
from the mainnet and put automatically in the `staging` folder by running the script: | ||
|
||
``` | ||
npm run get-transactions | ||
``` | ||
|
||
Staging TXs are not checked in the repository, while regression TXs _are_. If | ||
a staging TX fails at any point of the tests, it is automatically promoted to a | ||
regression TX (and it should be checked into the repository). | ||
|
||
|
||
Both testing and regression transactions are tested in the same way: | ||
|
||
┌──────┐ ┌──────┐ | ||
│ │ │ │ | ||
┌───── (CSL) Deserialize ────► │ TX ├───── (CSL) Serialize ─────► │ TX ┼──────┐ | ||
│ │( CSL)│ │(CBOR)│ │ | ||
┌──┴───┐ └──────┘ └──────┘ ▼ | ||
│ │ | ||
│ TX │ equal? | ||
│(CBOR)│ | ||
└──┬───┘ ┌──────┐ ┌──────┐ ▲ | ||
│ │ │ │ │ │ | ||
└───── (CDL) Deserialize ────► │ TX ┼───── (CDL) Serialize ─────► │ TX ┼──────┘ | ||
│( CDL)│ │(CBOR)│ | ||
└──────┘ └──────┘ | ||
|
||
The transactions fetched from the blockchain are both deserialized and serialized by CDL | ||
and CSL. The resulting CBOR encoding generated by each library are then tested for equality. | ||
|
||
In practice, however, the TXs are not monolitically tested. There is an intermediate step | ||
between deserialization and serialization in which transactions are split into their constituent parts | ||
(code in `serialization_utils.ts`). | ||
|
||
This allows us to test each component separately and also lets us detect which TX components | ||
are the ultimate cause of a given error. For example, the suite will inform if a deserialization | ||
error in the `TransactionWitnessSet` is actually due to a child `VkeyWitness` not being parsed correctly. | ||
This is normally reported as a `Child failed to deserialize` error. | ||
|
||
Just like for the API suite, there are some exceptions specified in `class-info.json` pertaining to | ||
the serialization suite: | ||
|
||
* The `extraction_unsupported_fields` contain transaction components that can't be extracted | ||
and tested separately because our extraction code can't handle them. These components are still | ||
test, just not separately. | ||
|
||
* The `extraction_unsupported_types` contains types that we are interested in testing, like `boolean` | ||
or `bignum`. Their correctness is just given. | ||
|
||
## Types and methods normalization | ||
|
||
The API test suite "normalizes" CDL and CSL method declarations and types before comparing | ||
them. This is for two reasons: | ||
|
||
* CDL usually passes an additional optional argument called `path[]: [string]` | ||
to `deserialize` and related functions while CSL does not. | ||
|
||
This is what allows CDL to pin-point with precision what exact component of a | ||
transaction is failing to be deserialized and is very useful for debugging | ||
purposes. | ||
|
||
* Some methods in CSL may throw or return `undefined`, while their CDL | ||
counterparts do not (and viceversa). | ||
|
||
We consider these minor differences, because the behaviour of the method when | ||
it returns succesfully is still the same. | ||
|
||
## Encoding of tagged sum variants | ||
|
||
CDL, just like CSL, uses code generation to generate most class and method implementations | ||
that can be found in `generated.ts`. The schema for all classes are the YAML files that | ||
can be found under the `conway-cddl/yaml` directory, which are half procedurally generated, | ||
half manually written, based on the official CDDL files that describe the Cardano ledger. | ||
|
||
Most of the time, CDL encodes things just the same as CSL. The main exception to these are | ||
_sum variants_. If a transaction component is described in the CDDL ledger file as a tagged | ||
sum, CDL will encode it correctly. But the variants of the specific sum type *will not* be encoded | ||
as specified in the ledger spec. | ||
|
||
For example: the `pool_params` component has the following definition in the Conway spec: | ||
|
||
``` | ||
certificate = [stake_registration | ||
// stake_deregistration | ||
// stake_delegation | ||
// pool_registration | ||
... (and many other variants) | ||
] | ||
``` | ||
|
||
`certificate` is a sum type that is encoded an array with two elements: the variant's "tag" | ||
and the variant's content. The tag and the content depend on the specific variant that is being encoded. | ||
|
||
Both CDL and CSL serialize this class (`Certificate`) exactly the same. However, let's look at one of the | ||
variants inside `certificate`: | ||
|
||
``` | ||
pool_registration = (3, pool_params) | ||
``` | ||
|
||
This specific variant has a tag equal to 3, and the content is a `pool_params`. If CSL is asked to | ||
serialize this class (`PoolRegistration`), it will produce a certificate like this: | ||
|
||
``` | ||
[3, pool_params] | ||
``` | ||
|
||
(Note that the variant is encoded exactly the same as the type that contains it, `certificate`) | ||
|
||
While CDL will produce a | ||
|
||
``` | ||
pool_params | ||
``` | ||
|
||
(Note the absence of the tag) | ||
|
||
Because of this discrepancy, all tagged sum variants are *not* tested separately, but rather as | ||
constituents of the sum that contains them. The list of variants not tested are contained in the | ||
`serialization_bad_variants` field of the `class-info.json` file. | ||
|