-
Notifications
You must be signed in to change notification settings - Fork 483
Generic network layer #577
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
Generic network layer #577
Conversation
Enum to compose request to the node params. In most cases request params are passed to Ethereum JSON RPC request as array of mixed type values, such as `[12,"this",true]`, thus this is not appropriate API design we have what we have. Meanwhile swift don't provide strict way to compose such array it gives some hacks to solve this task and one of them is using `RawRepresentable` protocol. Conforming this protocol gives designated type ability to represent itself in `String` representation in any way. So in our case we're using such to implement custom `encode` method to any used in node request params types.
…lls to Eth node. `prepareRequest` still takes `[Encodable]` as parameter argument and maps it to the `[JSONRPCParameter]`. All network tests pass well.
…er` protocol. Also there's added `RPCParameter` enum which implements internal encoding logic of value of any conformed `JSONRPCParameter` type. Unfortunately there's no way in swift yet to encode generic types. Therefore there's no way to made both `JSONRPCParameter` & `RPCParameter` types extendable. So yet there's a manual restriction for supported types, **must** conforms rather `JSONRPCParameter` protocol for base types, and `JSONParameterElement` protocol for types that are stored in arrays. The latter protocol is internal to deny conforming to it by a library user. `JSONRPCParameter` itself could be one to conform with by a user custom type, since there's a lack of making this type internal due to `RawRepresentable` protocol restrictions. So there's nothing we can do, but a leaving a documentation with denying to do this.
ABI API left unchanged.
It didn't converts blocks amount into hex number system.
There were two API calls to same task for iOS 15 and pre iOS. Have made one to both cases.
…onse<U>` are now generic and error prone. It must be used as `getValue<T>() -> T` like: `let someResponse: EthResponse<String> = sendRequest(with: .blockNumber)`
- JSONRPCParameter -> APIRequestParameterType - JSONParameterElement -> APIRequestParameterElementType
…neric implementation. There's follow types presented: - enum `APIRequest` - main type that user should be working with. - `APIResponse<T>` - type that returns network request method on successfully API call, where generic `T` type is the any given value of `result`. - protocol `APIResponseType` - protocol that must conforms any possible `result` type. - protocol `LiteralInitableFromString` - protocol that conforms any `Numeric` literals that `result` property hols as `String`. - protocol `IntegerInitableWithRadix` - utility protocol that conforms any `Integer` literals that have follow initializee: `init?(from hexString: String)`
This types uses to encode all given attributes to heterogeneous array, so it should not be public.
- FeeHistory - GetAccount - GetBlockNumber BlockNumber now stores in UInt.
- `GetAccoung` - `GetBalance` - `GetBlockByHash` - `GetBlockByNumber`
- `GasPrice` - `GetTransactionCount`
- `GetCode` - `GetTransactionCount` - `GetTransactionReceipt` - `CreateAccount` - `UnlockAccount`
This changes will follow that every math operation within Transaction either Block properties will require to cast type back and forth, so such pedantic behavior didn't worth it.
- Delete `EthereumTransaction.createRequest` - Delete `CallingBlockPolicy` enum which duplicating `BlockNumber` enum
…unt(for:, onBlock:)`
- Temporary disabled getting Network within Web3HttpProvider init. -
…s synchronous, but after switching all concurrency to async/await all of that method becomes redundant and more than that it becomes async.
@mloit @JeneaVranceanu @pharms-eth Please take a look to that PR guys. |
Temporary disabled tests that requires temporary deleted methods.
Tests failing yet also as expected. Since haven't debugging them yet. |
let request = RequestBody(method: self.call, params: self.parameters) | ||
// this is safe to force try this here | ||
// Because request must failed to compile if it not conformable with `Encodable` protocol | ||
return try! JSONEncoder().encode(request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest removing force try
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this PR and new code for 3.0 I suggest we don't open PR's with force unwraps/for try etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally i agreed with you, but in some case force try is reasonable, like that one which were used in gas prediction PR, so this rule should not be carved in stone.
But here i'm agreed with you, it's unnecessary here, and i'll fix it soon.
} | ||
|
||
extension APIRequest { | ||
public static func sendRequest<Result>(with provider: Web3Provider, for call: APIRequest) async throws -> APIResponse<Result> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we have this not be a static
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt it.
I've considered to move this method to web3httpprovider
class, but it's complicated because then you've should to make the whole provider struct generic and then make protocol that it conforms with associated type. Which leads to you need to rewrite almost every method in whole lib, so i refused it.
Making this method non static within this enum makes API kinda wired. It'll be looks like this:
let request: APIRequest = .gasPrice
let response: APIResponse<BigUInt> = request.send(with: web3.provider)
So i've refused that either.
Node throws and error if these parameters exist in request and lower than `21100` for formet and `10000000` for latter.
…ocol. - Rename init of `DecodableFromHex` protocol to make it crossing with `LiteralInitiableFromString`.
Now all tests are green.
- Drop methods `sendRequest` from Web3Provider protocol. - Move out network request code from `Web3HTTPProvider`. - Network enum are now inits from UInt instead of Int. Fixed bug of not decoding Data responses.
a02dbdf
to
90e2061
Compare
Generic network layer
There’s totally new network layer API.
It based on generic implementation and on some cascade of protocols. Let’s take a closer look in it.
How to
Using new API is as easy as write three line of a code:
Result
type and making a network request.And that’s it, you’re done here.
Types overview
There’s follow types have been implemented
Main types
public enum APIRequest
This is the main type of whole network layer API. It responsible to both compose API request to a node and to send it to a node with a given provider (which stores Node URL and session), as cases it have all available JSON RPC requests and most of them have associated values to pass request parameters there.
Additionally it have follow computed properties:
public responseType: APIResultType.Type
- this variable returns appropriateResult
generic parameter type for each API call. Which can be split generally in two parts:Int
,BigInt
) which could not be extended on client side.Block
) which could be extended on client side. That said that user able to add additionalResult
type on their side if it’s not literal (e.g. if it’s astruct
orclass
).method: REST
- this internal variable returns REST method for each API call. Currently its returning onlyPOST
one.parameters: [RequestParameter]
- this internal variable is purposed to return parameters of request as an heterogeneous Array which is Node expected in most cases.encodedBody: Data
- this internal variable returns encoded data ofRequestBody
type, which is required to compose correct request to a Node.call: String
- this internal variable returns method call string, which is one of property ofRequestBody
type.There’s two methods are provided for API calls.
public static func sendRequest<Result>(with provider: Web3Provider, for call: APIRequest) async throws -> APIResponse<Result>
- this method is the main one. It composes and sends request to a Node. This method could be called only with explicitly return type declaration likelet response: APIResponse<BigUInt> = try await APIRequest.sendRequest(with: self.provider, for: .gasPrice)
, whereresponse
is the whole APIResponse struct with a service properties and theresponse.result
is a point of interests in example above — gas price.static func setupRequest(for call: APIRequest, with provider: Web3Provider) -> URLRequest
- this internal method is just composing network request from all properties of relatedAPIRequest
case.public struct APIResponse<Result>: Decodable where Result: APIResultType
This generic struct is any Ethereum node response container, where all stored properties are utility fields and one generic
result: Result
is the property that stores strictly typed result of any given request.Protocols
To make things work there’s are some protocols be presented which both adds restriction to types that could be passed within new API and add some common methods to Literal types to be able initialize it from a hex string.
APIResultType
This protocol responsible for any nonliteral type that could be stored within
APIResponse<Result>
generic struct. This protocol have no requirements except it conformsDecodable
protocol. So any decodable type could be extended to conforms it.LiteralInitiableFromString
This protocol responsible for any literal types that could be stored within
APIResponse<Result>
. This protocol conformsAPIResultType
and it adds some requirements to it, like initializer from hex string. Despite that a given type could be extended to implement such initializer ==this should be done on a user side== because to make it work it requires some work withinsendRequest
method to be done.IntegerInitableWithRadix
This protocol is just utility one, which declares some convenient initializer which have both
Int
andBigInt
types, but don’t have any common protocol which declares such requirement.Utility types
struct RequestBody: Encodable
— just a request body that passes into request body.public enum REST: String
— enum of REST methods. OnlyPOST
andGET
presented yet.enum RequestParameter
— this enum is a request composing helper. It make happened to encode request attribute as heterogeneous array.protocol APIRequestParameterType: Encodable
— this type is part of theRequestParameter
enum mechanism which purpose is to restrict types that can be passed as associated types withinRequestParameter
cases.protocol APIRequestParameterElementType: Encodable
— this type purpose is the same asAPIRequestParameterType
one except this one is made forElement
s of anArray
s when the latter is an associated type of a givenRequestParameter
case.