Skip to content

PR #69, #70: Chain Configurator Implementations

meows edited this page Dec 6, 2019 · 5 revisions

Abstract

There is a change set which establishes chain configuration interface types https://github.com/etclabscore/multi-geth/pull/69, and an subsequent change set which installs these interfaces throughout multi-geth https://github.com/etclabscore/multi-geth/pull/70.

Motivation

Go-Ethereum uses interfaces for a lot of important things.

Interfaces are particularly useful when you want to emphasize a pattern of process, as opposed to a structure of data.

Go-Ethereum is very opinionated about it's structure of configuration data because it's very opinionated about the content of that data; it is designed and maintained in support of a few endorsed chain configurations.

Multi-Geth works to remove this opinion. As it has done so - refactoring to use EIP-driven feature implementation, refactoring to expose legible and extensible Difficulty and Reward logics, and has done so all the while working to retrofit a params.ChainConfig data structure by simply adding fields and echoing a simple IsForked pattern analogous to those fields.

As Multi-Geth grows it's cross-network relevance beyond the "canonical" chains, it also needs to grow it's awareness across clients. With the exception of Parity, its has been a general pattern for clients to be purpose built for a certain or limited set of chains. And Parity has been VERY popular, and has shown itself to be an indisposable tool for both development and production use across the EVM ecosystem. Multi-Geth wants to adopt this pattern, and bring this opinion-agnostic and highly-extensible, accessible attitude and resource to the Golang domain.

Implementing a Chain Configurator interface allows Multi-Geth to abstract the idea of chain configuration away from a noun and into a verb. It enables multi-geth to support various chain configuration data types natively, and to be able to act as leveragable intersection between them.

Want to convert between Parity and Go-Ethereum chain config JSON files?

convert.Convert(myParityConfig, myGethConfig)

Want to ask an abstract question comparing them? How about:

myParityConfig.GetEIP649Transition() == myGethConfig.GetEIP649Transition()

Even though these configuration schemas represent this idea very differently:

Parity:

blockReward: "2e+18",
difficultyBombDelay: {
   0: 5000000
}

Geth:

ByzantiumBlock: 0

You can now interface with them in way that is reflective of, and congruent to, the IP specifications that initially shaped them. Beyond individual features, we can now also do some fancy things rather simply:

common.Forks(myGethConfig)
> [1150000 1920000 2150000 2500000 2650000 ...]

common.Identical(myGethConfig, myParityConfig)
> true

common.Valid(myGethConfig) && common.Valid(myParityConfig)
> true

And one of the nice things, behind the scenes, is that the methods available at the interface API level use predicatable names and signatures, which means that the heavy-lifting logic for the methods above are largely dynamic, implemented with the reflect package. This reduces the space for developer maintenance and development cost, helps ensure thoroughness and, well, configuration parity, and allows developers to reason in ways that value generalizeability and communicable ecosystem-first patterns.

With this I hope to make a go-ethereum implementation that is a tool for the developers, instead of a tool from The Developers.

Establishing type [Chain]Configurator interface

Installing the interfaces

TODO

  • Resolve .gitmodules remote url. Either

    • use etclabscore/tests,
    • or multi-geth/tests permanently,
    • or see if they'll take a PR upstream,
    • or un-include the generated tests and remove the associated tooling and test runners.
  • Implement Aleth data type Configurator

  • Implement PyEthereum data type Configurator

  • Design and implement some global idea of Configuration default availability. This pattern (below) is not good. It should be some kind of iteration of a canonical set.

func dataDirPathForCtxChainConfig(ctx *cli.Context, baseDataDirPath string) string {
	switch {
	case ctx.GlobalBool(TestnetFlag.Name):
		return filepath.Join(baseDataDirPath, "testnet")
	case ctx.GlobalBool(ClassicFlag.Name):
		return filepath.Join(baseDataDirPath, "classic")
	case ctx.GlobalBool(MordorFlag.Name):
		return filepath.Join(baseDataDirPath, "mordor")
	case ctx.GlobalBool(SocialFlag.Name):
		return filepath.Join(baseDataDirPath, "social")
	case ctx.GlobalBool(MixFlag.Name):
		return filepath.Join(baseDataDirPath, "mix")
	case ctx.GlobalBool(EthersocialFlag.Name):
		return filepath.Join(baseDataDirPath, "ethersocial")
	case ctx.GlobalBool(MusicoinFlag.Name):
		return filepath.Join(baseDataDirPath, "musicoin")
	case ctx.GlobalBool(RinkebyFlag.Name):
		return filepath.Join(baseDataDirPath, "rinkeby")
	case ctx.GlobalBool(KottiFlag.Name):
		return filepath.Join(baseDataDirPath, "kotti")
	case ctx.GlobalBool(GoerliFlag.Name):
		return filepath.Join(baseDataDirPath, "goerli")
	}
	return baseDataDirPath
}
  • Implement an flag for passing a runtime Configurator value (ie read this JSON config file and run geth using it)
  • Implement echainspec tool for working with chainspec values (conversion, validation, enumeration, identies)
  • Implement JSON files as canonical definitions for default chain configs