Skip to content

Milestone 4 summary

eloylp edited this page Apr 24, 2023 · 6 revisions

uniffi-zcash-lib

During the milestone 4 we added the necessary features for interacting with transactions. This work heavily depends on previous milestones, in which we implemented the key derivation features.

During the next sections we will go through the original RFP requirements regarding transactions and also cover most of the development nuances. We can assume that are all the parts are ready for evaluation, unless this document says the opposite.

Producing a raw transaction

We are currently able to generate transactions for Transparent, Sapling and Orchard. We decided to concentrate our efforts in exposing the general transaction builder, as it looked the higher level interface for users. During this journey, some decisions were made:

  • The general transaction builder has support for adding Transparent and Sapling information to the transaction, but not for Orchard . Looks like the Orchard support is a work in progress at the time of this write. In the meanwhile, we opted for creating a separated Orchard transaction builder, which uses the Orchard bundle builder under the hood. Whenever the general builder implements the Orchard support, we think this project should strive for exposing it, unifying everything under the same transaction builder.

  • Structs with type parameters like lifetimes as in the general transaction builder are not friendly with the UniFFI way of managing lifetimes (and trespassing the FFI barrier in general). Thats one of the reasons because we needed to create an indirection, which first collects the needed information from the user and then, in a final step (the build() method), instantiates the original builder, does all the operations in the same function scope and returns the result. The code of the builder can be found here.

  • We applied the same strategy for the previously commented Orchard transaction builder as in the above point, but due to different reasons. UniFFI does not support methods that accept a &mut references due to its concurrency safe conventions. This forces API implementations to add thread-safe interior mutability patterns, like using Mutex or RwLock . Apart from that, the Orchard bundle owned builder exhaust the builder after calling the build() method, by doing a move of self. That seems incompatible with UniFFi , as it expects &self in the build() method.

  • Some structs like TransactionsData implements the state pattern by using generic type parameters. In cases like this, we are only exposing the Authorized implementation of them, as its the only, final state in which the transactions are returned from builders when invoking the build() method.

  • At the time of this write, only python tests are present for transactions. Read more about in the "testing discussion" section below.

Sign a transaction

All the implemented builders (see above section) , signs the transactions when the build() method is called. They only return signed transactions.

Explore the internal structure of a transaction

The first level fields methods of the transaction have been exposed, except the fee_paid() one. This is because such method requires a closure as parameter, which is not FFI friendly. The code is commented by the way, waiting for an acceptable solution if needed.

The different transaction bundles (Transparent, Sapling , Orchard) which conforms a transaction are also exposed up to a certain grade of detail. It would be relatively easy to add more definition in the future if needed.

For the Orchard bundle, this crypto methods were also exposed, but we still need to test them. That is going to be addressed in Milestone 5 by this issue.

Encoding and decoding transactions

Transactions implements from_bytes() and to_bytes() methods, that should help on fulfilling this requirement and contribute to interoperability.

Broadcast a transaction

Initially, team investigations determined there is no such support in librustzcash library so its currently not implemented. However, we are open to implement this functionality if the community point us to the relevant code.

Discussion regarding testing

There is an active discussion in the team regarding having tests for all the relevant languages. Here are the general pros and cons we are analyzing:

  • Pros
    • They serve as live documentation for the different languages/communities.
    • The UniFFI library is still under heavy development. Having tests for all languages apparently give us more confidence that a specific language binding generation its not broken.
  • Cons
    • It seems we are testing the UniFFI library not only our wrapper code. We think this is not the goal.
    • Increased testing time, so slow feedback loop while developing.

We are currently going for implementing all the tests for all languages, specially for the transactions part, as we consider the community will appreciate it.

We also opened this issue for addressing the high CI times in tests.