-
Notifications
You must be signed in to change notification settings - Fork 241
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The goal of the this codec is to serialize `params.UpgradeConfig` in a deterministic way, to be hashed later. This hash is going to be share by nodes at handshake, so they can determine if they have the same upgrade config. This PR leverages the newly introduced support to serilize Maps ava-labs/avalanchego#1790, which are deterministic (the values are sorted by keys before serializing)
- Loading branch information
Showing
6 changed files
with
207 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// (c) 2019-2023, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package handshake | ||
|
||
import ( | ||
"github.com/ava-labs/avalanchego/codec" | ||
"github.com/ava-labs/avalanchego/codec/linearcodec" | ||
"github.com/ava-labs/avalanchego/utils/units" | ||
"github.com/ava-labs/avalanchego/utils/wrappers" | ||
) | ||
|
||
const ( | ||
Version = uint16(0) | ||
maxMessageSize = 1 * units.MiB | ||
) | ||
|
||
var ( | ||
Codec codec.Manager | ||
) | ||
|
||
func init() { | ||
Codec = codec.NewManager(maxMessageSize) | ||
c := linearcodec.NewDefault() | ||
|
||
errs := wrappers.Errs{} | ||
errs.Add( | ||
c.RegisterType(UpgradeConfig{}), | ||
|
||
Codec.RegisterCodec(Version, c), | ||
) | ||
|
||
if errs.Errored() { | ||
panic(errs.Err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package handshake | ||
|
||
import ( | ||
"crypto/sha256" | ||
"fmt" | ||
|
||
"github.com/ava-labs/subnet-evm/params" | ||
"github.com/ava-labs/subnet-evm/precompile/modules" | ||
"github.com/ava-labs/subnet-evm/precompile/precompileconfig" | ||
) | ||
|
||
type PrecompileUpgrade struct { | ||
StructName string `serialize:"true"` | ||
Bytes []byte `serialize:"true"` | ||
} | ||
|
||
type UpgradeConfig struct { | ||
OptionalNetworkUpgrades []params.Fork `serialize:"true"` | ||
|
||
// Config for modifying state as a network upgrade. | ||
StateUpgrades []params.StateUpgrade `serialize:"true"` | ||
|
||
// Config for enabling and disabling precompiles as network upgrades. | ||
PrecompileUpgrades []PrecompileUpgrade `serialize:"true"` | ||
config params.UpgradeConfig | ||
bytes []byte | ||
} | ||
|
||
func ParseUpgradeConfig(bytes []byte) (*UpgradeConfig, error) { | ||
var config UpgradeConfig | ||
version, err := Codec.Unmarshal(bytes, &config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if version != Version { | ||
return nil, fmt.Errorf("Invalid version") | ||
} | ||
|
||
var PrecompileUpgrades []params.PrecompileUpgrade | ||
|
||
for _, precompileUpgrade := range config.PrecompileUpgrades { | ||
module, ok := modules.GetPrecompileModule(precompileUpgrade.StructName) | ||
if !ok { | ||
return nil, fmt.Errorf("unknown precompile config: %s", precompileUpgrade.StructName) | ||
} | ||
preCompile := module.MakeConfig() | ||
|
||
version, err := Codec.Unmarshal(precompileUpgrade.Bytes, preCompile) | ||
if version != Version { | ||
return nil, fmt.Errorf("Invalid version") | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
if Config, ok := preCompile.(precompileconfig.Config); ok { | ||
PrecompileUpgrades = append(PrecompileUpgrades, params.PrecompileUpgrade{Config: Config}) | ||
} else { | ||
return nil, fmt.Errorf("Error deserializing precompile %s", precompileUpgrade.StructName) | ||
} | ||
} | ||
|
||
config.config = params.UpgradeConfig{ | ||
OptionalNetworkUpgrades: ¶ms.OptionalNetworkUpgrades{config.OptionalNetworkUpgrades}, | ||
StateUpgrades: config.StateUpgrades, | ||
PrecompileUpgrades: PrecompileUpgrades, | ||
} | ||
config.bytes = bytes | ||
|
||
return &config, nil | ||
} | ||
|
||
func NewUpgradeConfig(config params.UpgradeConfig) (*UpgradeConfig, error) { | ||
PrecompileUpgrades := make([]PrecompileUpgrade, 0) | ||
for _, precompileConfig := range config.PrecompileUpgrades { | ||
bytes, err := Codec.Marshal(Version, precompileConfig.Config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
PrecompileUpgrades = append(PrecompileUpgrades, PrecompileUpgrade{ | ||
StructName: precompileConfig.Key(), | ||
Bytes: bytes, | ||
}) | ||
} | ||
|
||
optionalNetworkUpgrades := make([]params.Fork, 0) | ||
if config.OptionalNetworkUpgrades != nil { | ||
optionalNetworkUpgrades = config.OptionalNetworkUpgrades.Updates | ||
} | ||
|
||
wrappedConfig := UpgradeConfig{ | ||
OptionalNetworkUpgrades: optionalNetworkUpgrades, | ||
StateUpgrades: config.StateUpgrades, | ||
PrecompileUpgrades: PrecompileUpgrades, | ||
config: config, | ||
bytes: make([]byte, 0), | ||
} | ||
bytes, err := Codec.Marshal(Version, wrappedConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
wrappedConfig.bytes = bytes | ||
|
||
return &wrappedConfig, nil | ||
} | ||
|
||
func (r *UpgradeConfig) Config() params.UpgradeConfig { | ||
return r.config | ||
} | ||
|
||
func (r *UpgradeConfig) Bytes() []byte { | ||
return r.bytes | ||
} | ||
|
||
func (r *UpgradeConfig) Hash() [32]byte { | ||
return sha256.Sum256(r.bytes) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package handshake | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ava-labs/subnet-evm/params" | ||
"github.com/ava-labs/subnet-evm/precompile/contracts/nativeminter" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestSerialize(t *testing.T) { | ||
var t0 uint64 = 0 | ||
var t1 uint64 = 1 | ||
config, err := NewUpgradeConfig(params.UpgradeConfig{ | ||
PrecompileUpgrades: []params.PrecompileUpgrade{ | ||
{ | ||
Config: nativeminter.NewConfig(&t0, nil, nil, nil), // enable at genesis | ||
}, | ||
{ | ||
Config: nativeminter.NewDisableConfig(&t1), // disable at timestamp 1 | ||
}, | ||
}, | ||
}) | ||
assert.NoError(t, err) | ||
|
||
config2, err := ParseUpgradeConfig(config.Bytes()) | ||
assert.NoError(t, err) | ||
|
||
config3, err := NewUpgradeConfig(config2.Config()) | ||
assert.NoError(t, err) | ||
|
||
assert.Equal(t, config2, config3) | ||
assert.Equal(t, config.Hash(), config2.Hash()) | ||
assert.Equal(t, config.Hash(), config3.Hash()) | ||
} |