Here are some areas of improvement and questions to think about for the next version of fallback(). Contributions are always welcome!
As of this writing, test coverage is pretty limited. The parts of fallback() that are in greatest need of better tests are:
the utility libraries — those in
the core HTTP request parsing code in
HttpMessages.solgenerally seems to perform well on simple, well-formed requests, its performance on malformed and more complex HTTP requests isn't well-tested.
The initial fallback() code was written with limited attention to gas optimization, and there are likely many places in the contracts where gas usage could be cut down. For example:
StringConcat.sol— in many cases, the
StringConcat.concatfunction is just used to create intermediate strings which are subsequently concatenated again. Is it possible to "concatenate by reference" and only allocate a new string once the final concatenated result needs to be used?
There are two parts to this — contract security and web security.
There's a Solhint rule called
no-complex-fallback, under the "Security" category, which encourages the
fallback function to have less than 2 statements.
- What are the security implications of making the
fallbackfunction so complex and open-ended in this project?
Right now, all HTTP requests and responses are publicly accessible (if the contract is
eth_called) or written in plaintext on-chain (if we use
eth_send*). This makes this app unsuitable for sending sensitive/authenticated information (e.g. a JSON Web token, or user data) over the wire. What do we need to do to make this possible?
See the Encrypted Requests/Responses section for more details.
Examples and Documentation
Some ideas for improvements in documentation or examples:
- Would it be possible to write TodoMVC or something similar using fallback()?
- Are there any other canonical web app examples we could implement in fallback()?
There are places in the code where it isn't exactly clear why something is working (but it still seems to work fine!). For example:
It is unclear why the
WebApp.solneeds to return 32 extra bytes for
HttpHandler.solto receive the 404 response correctly when a nonexistent route handler function is called (when the 32 bytes aren't added, ABI-decoding the returned data into an
Author's note: As I was developing the
WebAppand trying to figure out why ABI-decoding was failing in
HttpHandler, I decided to compare the returndata of
WebApp— not the main
HttpProxy) to that of a function which already existed on
I noticed that when an existing function on
WebAppwas called, the returned data had 32 extra bytes at the end versus the returned data from the
WebApp. So I changed the assembly to return 32 extra bytes from
WebApp. Once I did that,
HttpHandlerstarted decoding the return value correctly into an
The exact reason why these bytes needed to be added probably has something to do with the specifics of the
returnopcode and the ABI encoding spec for dynamic
bytesarrays, but (simply content with it just working for now) I haven't looked deeply enough to figure out the specific reasons why.
Some ideas for further work:
A major limitation of the contract as written now is that if run in
send mode (i.e. mutating the blockchain), it "logs" all HTTP requests on-chain as input data and HTTP responses on-chain as output data.
See the todo app contract's transactions on Etherscan for an example of the data that is written on-chain.
- What would it take to maintain the same HTTP request/response functionality while encrypting requests?
- Can we implement HTTPS on-chain, or is there some sort of more blockchain-native zk-SNARK solution we can use?
Some other protocols that could be implemented Ethereum using the same
fallback function idea: