Skip to content

Go API bindings for Eth2, Lighthouse/Teku compat + customization (work in progress)

License

Notifications You must be signed in to change notification settings

protolambda/eth2api

Repository files navigation

Eth2 API bindings

Fully typed API bindings, for both client and server, to implement the standard Eth2.0 API specification.

Work in progress, testing in progress

TODO:

  • Client
    • Types for full API spec
    • Bindings for full API spec
      • Beacon API
      • Debug API
      • Config API
      • Node API
      • Validator API
    • Abstraction of requests/responses
    • HTTP client implementation
    • Testing: API Integration test-suite against test vectors (generated from Lighthouse API, verified with spec)
      • Beacon API
      • Debug API
      • Config API
      • Node API
      • Validator API
    • Tests for the util methods
  • Server
    • (WIP) Interfaces for serverside API
    • (WIP) Abstract server that consumes above interfaces, runs API server

The API design is not definite yet, current bindings are based on Eth2.0-apis commit ceb555f9b40ff9c2094d038e9f70a19419e5b652.

Example

package main

import (
	"context"
	"fmt"
	"github.com/protolambda/eth2api"
	"github.com/protolambda/eth2api/client/beaconapi"
	"github.com/protolambda/zrnt/eth2/beacon/common"
	"github.com/protolambda/zrnt/eth2/configs"
	"net/http"
	"os"
	"time"
)

func main() {
	// Make an HTTP client (reuse connections!)
	client := &eth2api.Eth2HttpClient{
		Addr: "http://localhost:5052",
		Cli: &http.Client{
			Transport: &http.Transport{
				MaxIdleConnsPerHost: 123,
			},
			Timeout: 10 * time.Second,
		},
	  Codec: eth2api.JSONCodec{},
	}


	//// e.g. cancel requests with a context.WithTimeout/WithCancel/WithDeadline
	ctx := context.Background()

	var genesis eth2api.GenesisResponse
	if exists, err := beaconapi.Genesis(ctx, client, &genesis); !exists {
		fmt.Println("chain did not start yet")
		os.Exit(1)
	} else if err != nil {
		fmt.Println("failed to get genesis", err)
		os.Exit(1)
	}
	spec := configs.Mainnet
	// or load testnet config info from a YAML file
	// yaml.Unmarshal(data, &spec.Config)

	// every fork has a digest. Blocks are versioned by name in the API,
	// but wrapped with digest info in ZRNT to do enable different kinds of processing
	altairForkDigest := common.ComputeForkDigest(spec.ALTAIR_FORK_VERSION, genesis.GenesisValidatorsRoot)


	id := eth2api.BlockHead
	// or try other block ID types:
	// eth2api.BlockIdSlot(common.Slot(12345))
	// eth2api.BlockIdRoot(common.Root{0x.....})
	// eth2api.BlockGenesis

	// standard errors are part of the API.
	var versionedBlock eth2api.VersionedSignedBeaconBlock
	if exists, err := beaconapi.BlockV2(ctx, client, id, &versionedBlock); !exists {
		fmt.Println("block not found")
		os.Exit(1)
	} else if err != nil {
		fmt.Println("failed to get block", err)
		os.Exit(1)
	} else {
		fmt.Println("block version:", versionedBlock.Version)
		// get the block (any fork)
		fmt.Printf("data: %v\n", versionedBlock.Data)

		// add digest:
		envelope := versionedBlock.Data.Envelope(spec, altairForkDigest)
		fmt.Println("got block:", envelope.BlockRoot)
	}
}

Testing

Testing is not fully automated yet, awaiting first test vector release.

For now, you can:

  • Use protolambda/eth2-api-testgen to generate test vectors.
  • Copy the output dir to the tests dir in this repo. (cp -r ../eth2-api-testgen/output tests)
  • Run the Go tests in this repo (go test ./...)

Architecture

  • Strictly typed client bindings that send a PreparedRequest via a Client and decode the Response
  • Strictly typed server routes, backed by chain/db interfaces, with handlers which take a Request and produce a PreparedResponse
  • A Server is a mux of routes, calling the handlers, and encoding the PreparedResponse to serve to the requesting client

The Client and Server essentially do the encoding and transport, and are fully replaceable, without rewriting any API.

                                    __________________ Client __________________
                                   |                                            |
call binding ---PreparedRequest---> Eth2HttpClient ---http.Request--> HttpClient

                          _______________________ Server _________________________
                         |                                                        |
create route ---Route---> Eth2HttpMux ---http.Handler---> julienschmidt/httprouter


  ________________ Server ________________                                                     _________________ Server _______________ 
 |                                        |                                                   |                                        |
 ---http.Request---> Eth2HttpMux & Decoder ---Request---> route handler ---PreparedResponse---> Http server Encoder ---http.Response--->

How is this different from prysmaticlabs/ethereumapis?

  • Stricter typing, bazed on ZRNT
  • Full transport abstraction, no protobufs, implement it how you like
  • Focus on full JSON compatibility with Lighthouse and Teku
  • Avoids allocations, optimized requests
  • Minimal dependencies
  • Designed for customization. Swap the transport, change the encoding, add Eth2 Phase1, whatever.

License

MIT, see LICENSE file.

About

Go API bindings for Eth2, Lighthouse/Teku compat + customization (work in progress)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors 4

  •  
  •  
  •  
  •  

Languages