Skip to content

ilkamo/ethparser-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ethereum Parser

I had a lot of fun working on this project. My approach was to create a parser that could be easily extended with new repositories and ethereum clients. Most of the code is tested with unit tests and I tried to keep it as clean as possible. The most interesting parts are commented in the code so that reviewers can understand my thought process.

Packages

I created different packages to have a separation of concerns and I used the internal package for the components that I don't want to expose to the public.

  • internal

    • e2e e2e test suite.
    • ethereum logic to interact with the needed methods of the ethereum client. It relies on a generic RPCClient interface that can be implemented by any client. Inside the package, there are some utility functions to deal with ethereum hex numbers.
    • jsonrpc logic to interact with any JSON-RPC server. It is used by my ethereum client. Inside, there are some transport-layer types. The HTTPRequestBuilder is a really simple builder, and it could be replaced with a more generic one.
    • storage implementation of an in-memory concurrency safe TransactionsRepository and AddressesRepository.
    • mock mocks for the tests.
    • testdata test data used by the tests. Here I used go:embed to simply load a json file with real ethereum block data.
  • parser logic to parse and observe the ethereum blocks and transactions. The parser accepts different options to enhance the default implementation with more sophisticated components.

  • types types used by the main components.

Usage

The default parser can be initialized in the following way:

ctx := context.Background()
log := slog.New(slog.NewJSONHandler(os.Stdout, nil))

p, err := parser.NewParser(
  "https://cloudflare-eth.com",
  log,
)
// handle the error

err = p.Run(ctx)

The parser can be extended with different components by passing options to the constructor. For example, to use a different repository, you can pass the WithTransactionsRepository option:

repo := NewTransactionsRepository()

p, err := parser.NewParser(
  "https://cloudflare-eth.com",
  log,
  parser.WithTransactionsRepository(repo),
)

All the available options are defined in the parser/options.go file.

Testing

All the unit tests can be run with the following command:

make test

To display the tests coverage in an interactive html page, run the following command:

make display_coverage

In addition, I created a simple e2e test suite that runs the parser with a real ethereum client to show that it works as expected. The test is located in the tests/e2e folder. Usually I would run this with a docker-compose file that would start an ethereum emulator, but wanted to keep it simple for this project. To start the test, just run the following command:

make test_e2e

Linting

To lint the code, run the following command:

make lint

To fix linting issues, run the following command:

make fmt

CI

I added a simple GitHub Actions workflow that runs the tests and linter on every pull request.

Considerations

type Parser interface {
    GetCurrentBlock() int
    Subscribe(address string) bool
    GetTransactions(address string) []Transaction
}

During the implementation, I thought about some improvements that could be made to the public interface of the parser.

  • context is not being used in the parser methods. I would definitely add it in a real-world scenario to allow the caller to cancel the operation and pass trace information.
  • The Subscribe and GetTransactions methods could be improved to return an error. This way, the caller could know if the subscription failed and why (really useful it there is a cache or a network error).
  • The parser doesn't have a method to start parsing. I assumed that it would start parsing when the parser is created. I really don't like this approach this is why I added a Run method to the parser. This way, the caller can start the parser and control it with a context.
  • The GetCurrentBlock returns an int. I would change it to return an uint64 to avoid possible future overflow issues.

About

Easy extendable Ethereum parser.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published