Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(sia): Sia http client refactor and #2108

Draft
wants to merge 136 commits into
base: dev
Choose a base branch
from

Conversation

Alrighttt
Copy link
Member

@Alrighttt Alrighttt commented May 4, 2024

Changelog

Add Docker Test Framework

Adapted the existed Docker test framework to allow running a self contained "regtest-like" blockchain network including instant block mining, a custom developer subsidy address and v1/v2 activation time frames.

See sia_docker_tests.rs. Currently uses docker.io/alrighttt/walletd-komodo which utilizes my custom fork of walletd, https://github.com/Alrighttt/walletd/tree/Komodo-persistent-testnet.

Refactor http_client moedule and Add http_endpoints Module

Refactors the SiaApiClient significantly for better developer ease of use. Introduces the dispatcher method for SiaApiClient. This method is likely to be the main way a developer can interact with the Sia walletd API. See unit tests in sia_docker_tests.rs for example usage.

Moves the individual endpoint implementations into a seperate http_endpoints module.

Add specifier Module

Adds a small module to initialize the equivalent of Sia Go's "Identifier" encoding. These identifiers are used extensively in the Sia's transaction and block encoding.

See specifier.rs.

Add transaction module

Begin work on transaction encoding and decoding. This module will ultimately implement both Sia v1 and v2 consensus. Adds many unit tests.

See transaction.rs. See https://github.com/Alrighttt/core/blob/rust-port-unit-tests/types/rust_port_test.go .

Add Encodable trait

Adds the Encodable trait to allow better mimicking the code patterns of Sia's Go developers.

See encoding.rs. See transaction.rs unit tests for usage.

Extend Api Client Error Handling

Refactors the fetch_and_parse function of the API client to begin implementing more graceful handling of error messages or

Todo

  • Remove or finalize developer comments

  • Add inline docs.rs documentation

  • Handle unexpected HTTP responses. Eg, HTTP 200 but unexpected data structure

  • Update Go port unit tests

  • Better organization of the Go/Rust equivalent unit tests. Ie, rust_port_test.go

Copy link
Collaborator

@mariocynicys mariocynicys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First review iteration.
Looking good. A couple of nits though.

Comment on lines +4 to +25
macro_rules! define_byte_array_const {
($name:ident, $size:expr, $value:expr) => {
pub const $name: [u8; $size] = {
let mut arr = [0u8; $size];
let bytes = $value.as_bytes();
let mut i = 0;
while i < bytes.len() && i < $size {
arr[i] = bytes[i];
i += 1;
}
arr
};
};
}

define_byte_array_const!(ED25519, 16, "ed25519");
define_byte_array_const!(SIACOIN_OUTPUT, 16, "siacoin output");
define_byte_array_const!(SIAFUND_OUTPUT, 16, "siafund output");
define_byte_array_const!(FILE_CONTRACT, 16, "file contract");
define_byte_array_const!(STORAGE_PROOF, 16, "storage proof");
define_byte_array_const!(FOUNDATION, 16, "foundation");
define_byte_array_const!(ENTROPY, 16, "entropy");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow!
That's very clever. Never knew runtime computed expressions can be assigned to constants.

Comment on lines +38 to +41
impl Encodable for Specifier {
fn encode(&self, encoder: &mut Encoder) { encoder.write_slice(self.identifier.as_bytes()); }
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a protocol level thing right? I see this will encode the bytes of strings defined above (ed25519, siacoin output, etc...).

If this is just used to distinguish between different specifier on our side then we could possibly replace these strings with numbers instead, and encode those.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a direct port of their encoding. It's intentionally encoding ASCII.

@@ -21,6 +22,10 @@ impl Address {
}
}

impl Encodable for Address {
fn encode(&self, encoder: &mut Encoder) { encoder.write_slice(&self.0 .0.as_ref()); }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
fn encode(&self, encoder: &mut Encoder) { encoder.write_slice(&self.0 .0.as_ref()); }
fn encode(&self, encoder: &mut Encoder) { self.0.encode(encoder) }

type Response = AddressBalanceResponse;

fn to_http_request(&self, base_url: &Url) -> Result<Request, SiaApiClientError> {
// TODO use .join method of Url to prevent any possibility of path traversal
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if self.address is a valid address (h256), there won't be any possibility for path traversal.

Comment on lines +144 to +149
impl Encodable for SiacoinOutput {
fn encode(&self, encoder: &mut Encoder) {
self.value.encode(encoder);
self.address.encode(encoder);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be less error-prone to not implement Encodable for the un-versioned types and only use their version-ers to encode them.

}

// SiacoinOutput remains the same data structure between V1 and V2 however the encoding changes
pub enum SiacoinOutputVersion {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the version-ers are only used for encoding, they can hold a reference to avoid unnecessary copying/cloning.

}

impl Encodable for PublicKey {
fn encode(&self, encoder: &mut Encoder) { encoder.write_len_prefixed_bytes(&self.to_bytes()); }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like pubkeys shouldn't be len prefixed, since the length isn't variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants