Skip to content

Commit

Permalink
add custom marshaller for GetChainConfigResponse api (ava-labs#546)
Browse files Browse the repository at this point in the history
* add yet another custom marshaller to GetChainConfigResponse api

* enforce a json len before allocation

* Move chain config wrapper type to params/ and add test

* Fix trailing newline

* Remove flaky unit test

* Add back unit test with JSONeq

---------

Co-authored-by: Darioush Jalali <[email protected]>
Co-authored-by: aaronbuchwald <[email protected]>
  • Loading branch information
3 people authored Mar 2, 2023
1 parent 67a5db7 commit e3c0cc5
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 12 deletions.
14 changes: 2 additions & 12 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,8 @@ func (s *EthereumAPI) Syncing() (interface{}, error) {
return false, nil
}

type GetChainConfigResponse struct {
*params.ChainConfig
params.UpgradeConfig `json:"upgrades"`
}

func (s *BlockChainAPI) GetChainConfig(ctx context.Context) GetChainConfigResponse {
config := s.b.ChainConfig()
resp := GetChainConfigResponse{
ChainConfig: config,
UpgradeConfig: config.UpgradeConfig,
}
return resp
func (s *BlockChainAPI) GetChainConfig(ctx context.Context) *params.ChainConfigWithUpgradesMarshalled {
return s.b.ChainConfig().ToWithUpgradesMarshalled()
}

// TxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential.
Expand Down
49 changes: 49 additions & 0 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import (
"github.com/ethereum/go-ethereum/common"
)

const maxJSONLen = 64 * 1024 * 1024 // 64MB

var (
errNonGenesisForkByHeight = errors.New("subnet-evm only supports forking by height at the genesis block")

Expand Down Expand Up @@ -211,6 +213,53 @@ func (c ChainConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(raw)
}

type ChainConfigWithUpgradesMarshalled struct {
*ChainConfig
UpgradeConfig UpgradeConfig `json:"upgrades,omitempty"`
}

// MarshalJSON implements json.Marshaler. This is a workaround for the fact that
// the embedded ChainConfig struct has a MarshalJSON method, which prevents
// the default JSON marshalling from working for UpgradeConfig.
// TODO: consider removing this method by allowing external tag for the embedded
// ChainConfig struct.
func (s *ChainConfigWithUpgradesMarshalled) MarshalJSON() ([]byte, error) {
// embed the ChainConfig struct into the response
chainConfigJSON, err := json.Marshal(s.ChainConfig)
if err != nil {
return nil, err
}
if len(chainConfigJSON) > maxJSONLen {
return nil, errors.New("value too large")
}

type upgrades struct {
UpgradeConfig UpgradeConfig `json:"upgrades"`
}

upgradeJSON, err := json.Marshal(upgrades{s.UpgradeConfig})
if err != nil {
return nil, err
}
if len(upgradeJSON) > maxJSONLen {
return nil, errors.New("value too large")
}

// merge the two JSON objects
mergedJSON := make([]byte, 0, len(chainConfigJSON)+len(upgradeJSON)+1)
mergedJSON = append(mergedJSON, chainConfigJSON[:len(chainConfigJSON)-1]...)
mergedJSON = append(mergedJSON, ',')
mergedJSON = append(mergedJSON, upgradeJSON[1:]...)
return mergedJSON, nil
}

func (c *ChainConfig) ToWithUpgradesMarshalled() *ChainConfigWithUpgradesMarshalled {
return &ChainConfigWithUpgradesMarshalled{
ChainConfig: c,
UpgradeConfig: c.UpgradeConfig,
}
}

// UpgradeConfig includes the following configs that may be specified in upgradeBytes:
// - Timestamps that enable avalanche network upgrades,
// - Enabling or disabling precompiles as network upgrades.
Expand Down
18 changes: 18 additions & 0 deletions params/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (

"github.com/ava-labs/subnet-evm/precompile/contracts/nativeminter"
"github.com/ava-labs/subnet-evm/precompile/contracts/rewardmanager"
"github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -227,3 +228,20 @@ func TestActivePrecompiles(t *testing.T) {
rules1 := config.AvalancheRules(common.Big0, common.Big1)
require.False(t, rules1.IsPrecompileEnabled(nativeminter.Module.Address))
}

func TestChainConfigMarshalWithUpgrades(t *testing.T) {
config := ChainConfigWithUpgradesMarshalled{
ChainConfig: TestChainConfig,
UpgradeConfig: UpgradeConfig{
PrecompileUpgrades: []PrecompileUpgrade{
{
Config: txallowlist.NewConfig(big.NewInt(100), nil, nil),
},
},
},
}
result, err := json.Marshal(&config)
require.NoError(t, err)
expectedJSON := `{"chainId":1,"feeConfig":{"gasLimit":8000000,"targetBlockRate":2,"minBaseFee":25000000000,"targetGas":15000000,"baseFeeChangeDenominator":36,"minBlockGasCost":0,"maxBlockGasCost":1000000,"blockGasCostStep":200000},"homesteadBlock":0,"eip150Block":0,"eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"subnetEVMTimestamp":0,"upgrades":{"precompileUpgrades":[{"txAllowListConfig":{"blockTimestamp":100}}]}}`
require.JSONEq(t, expectedJSON, string(result))
}

0 comments on commit e3c0cc5

Please sign in to comment.