diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 64307033d8..346357afda 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -121,3 +121,4 @@ * [Tick Verification](proposals/tick-verification.md) * [Block Confirmation](proposals/block-confirmation.md) * [ABI Management](proposals/abi-management.md) + * [Rust Clients](proposals/rust-clients.md) diff --git a/docs/src/proposals/rust-clients.md b/docs/src/proposals/rust-clients.md new file mode 100644 index 0000000000..850d7f85e9 --- /dev/null +++ b/docs/src/proposals/rust-clients.md @@ -0,0 +1,52 @@ +# Rust Clients + +## Problem + +High-level tests, such as bench-tps, are written in terms of the `Client` +trait. When we execute these tests as part of the test suite, we use the +low-level `BankClient` implementation. When we need to run the same test +against a cluster, we use the `ThinClient` implementation. The problem with +that approach is that it means the trait will continually expand to include new +utility functions and all implementations of it need to add the new +functionality. By separating the user-facing object from the trait that abstracts +the network interface, we can expand the user-facing object to include all sorts +of useful functionality, such as the "spinner" from RpcClient, without concern +for needing to extend the trait and its implementations. + +## Proposed Solution + +Instead of implementing the `Client` trait, `ThinClient` should be constructed +with an implementation of it. That way, all utility functions currently in the +`Client` trait can move into `ThinClient`. `ThinClient` could then move into +`solana-sdk` since all its network dependencies would be in the implementation +of `Client`. We would then add a new implementation of `Client`, called +`ClusterClient`, and that would live in the `solana-client` crate, where +`ThinClient` currently resides. + +After this reorg, any code needing a client would be written in terms of +`ThinClient`. In unit tests, the functionality would be invoked with +`ThinClient`, whereas `main()` functions, benchmarks and +integration tests would invoke it with `ThinClient`. + +If higher-level components require more functionality than what could be +implemented by `BankClient`, it should be implemented by a second object +that implements a second trait, following the same pattern described here. + +### Error Handling + +The `Client` should use the existing `TransportError` enum for errors, except +that the `Custom(String)` field should be changed to `Custom(Box)`. + +### Implementation Strategy + +1. Add new object to `solana-sdk`, `RpcClientTng`, where the `Tng` suffix is + temporary and stands for "The Next Generation" +2. Initialize `RpcClientTng` with a `SyncClient` implementation. +3. Add new object to `solana-sdk`, `ThinClientTng`; initialize it with + `RpcClientTng` and an `AsyncClient` implementation +4. Move all unit-tests from `BankClient` to `ThinClientTng` +5. Add `ClusterClient` +5. Move `ThinClient` users to `ThinClientTng` +6. Delete `ThinClient` and rename `ThinClientTng` to `ThinClient` +7. Move `RpcClient` users to new `ThinClient` +8. Delete `RpcClient` and rename `RpcClientTng` to `RpcClient`