Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion plugin/evm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/ava-labs/subnet-evm/plugin/evm/message"
"github.com/ava-labs/subnet-evm/trie/triedb/hashdb"

warpcontract "github.com/ava-labs/subnet-evm/precompile/contracts/warp"
"github.com/ava-labs/subnet-evm/rpc"
statesyncclient "github.com/ava-labs/subnet-evm/sync/client"
"github.com/ava-labs/subnet-evm/sync/client/stats"
Expand Down Expand Up @@ -998,7 +999,18 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]http.Handler, error) {
}

if vm.config.WarpAPIEnabled {
validatorsState := warpValidators.NewState(vm.ctx)
requirePrimaryNetworkSigners := func() bool {
warpCfgIntf, ok := vm.currentRules().ActivePrecompiles[warpcontract.ContractAddress]
if !ok {
return false
}
warpCfg, ok := warpCfgIntf.(*warpcontract.Config)
if !ok {
return false
}
return warpCfg.RequirePrimaryNetworkSigners
}
validatorsState := warpValidators.NewState(vm.ctx, requirePrimaryNetworkSigners)
if err := handler.RegisterName("warp", warp.NewAPI(vm.ctx.NetworkID, vm.ctx.SubnetID, vm.ctx.ChainID, validatorsState, vm.warpBackend, vm.client)); err != nil {
return nil, err
}
Expand Down Expand Up @@ -1046,6 +1058,12 @@ func (vm *VM) GetCurrentNonce(address common.Address) (uint64, error) {
return state.GetNonce(address), nil
}

// currentRules returns the chain rules for the current block.
func (vm *VM) currentRules() params.Rules {
header := vm.eth.APIBackend.CurrentHeader()
return vm.chainConfig.Rules(header.Number, header.Time)
}

func (vm *VM) startContinuousProfiler() {
// If the profiler directory is empty, return immediately
// without creating or starting a continuous profiler.
Expand Down
10 changes: 8 additions & 2 deletions precompile/contracts/warp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ var (
// adds specific configuration for Warp.
type Config struct {
precompileconfig.Upgrade
QuorumNumerator uint64 `json:"quorumNumerator"`
QuorumNumerator uint64 `json:"quorumNumerator"`
RequirePrimaryNetworkSigners bool `json:"requirePrimaryNetworkSigners"`
}

// NewConfig returns a config for a network upgrade at [blockTimestamp] that enables
Expand All @@ -59,6 +60,11 @@ func NewConfig(blockTimestamp *uint64, quorumNumerator uint64) *Config {
}
}

func (c *Config) WithRequirePrimaryNetworkSigners(requirePrimaryNetworkSigners bool) *Config {
c.RequirePrimaryNetworkSigners = requirePrimaryNetworkSigners
return c
}

// NewDefaultConfig returns a config for a network upgrade at [blockTimestamp] that enables
// Warp with the default quorum numerator (0 denotes using the default).
func NewDefaultConfig(blockTimestamp *uint64) *Config {
Expand Down Expand Up @@ -202,7 +208,7 @@ func (c *Config) VerifyPredicate(predicateContext *precompileconfig.PredicateCon
context.Background(),
&warpMsg.UnsignedMessage,
predicateContext.SnowCtx.NetworkID,
warpValidators.NewState(predicateContext.SnowCtx), // Wrap validators.State on the chain snow context to special case the Primary Network
warpValidators.NewState(predicateContext.SnowCtx, func() bool { return c.RequirePrimaryNetworkSigners }), // Wrap validators.State on the chain snow context to special case the Primary Network
predicateContext.ProposerVMBlockCtx.PChainHeight,
quorumNumerator,
WarpQuorumDenominator,
Expand Down
14 changes: 12 additions & 2 deletions precompile/contracts/warp/predicate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ func createValidPredicateTest(snowCtx *snow.Context, numKeys uint64, predicateBy
}

func TestWarpMessageFromPrimaryNetwork(t *testing.T) {
for _, requirePrimaryNetworkSigners := range []bool{true, false} {
testWarpMessageFromPrimaryNetwork(t, requirePrimaryNetworkSigners)
}
}

func testWarpMessageFromPrimaryNetwork(t *testing.T, requirePrimaryNetworkSigners bool) {
require := require.New(t)
numKeys := 10
cChainID := ids.GenerateTestID()
Expand Down Expand Up @@ -272,13 +278,17 @@ func TestWarpMessageFromPrimaryNetwork(t *testing.T) {
return constants.PrimaryNetworkID, nil // Return Primary Network SubnetID
},
GetValidatorSetF: func(ctx context.Context, height uint64, subnetID ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
require.Equal(snowCtx.SubnetID, subnetID)
expectedSubnetID := snowCtx.SubnetID
if requirePrimaryNetworkSigners {
expectedSubnetID = constants.PrimaryNetworkID
}
require.Equal(expectedSubnetID, subnetID)
return getValidatorsOutput, nil
},
}

test := testutils.PredicateTest{
Config: NewDefaultConfig(utils.NewUint64(0)),
Config: NewDefaultConfig(utils.NewUint64(0)).WithRequirePrimaryNetworkSigners(requirePrimaryNetworkSigners),
PredicateContext: &precompileconfig.PredicateContext{
SnowCtx: snowCtx,
ProposerVMBlockCtx: &block.Context{
Expand Down
16 changes: 9 additions & 7 deletions warp/validators/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ var _ validators.State = (*State)(nil)
// signatures from a threshold of the RECEIVING subnet validator set rather than the full Primary Network
// since the receiving subnet already relies on a majority of its validators being correct.
type State struct {
chainContext *snow.Context
validators.State
chainContext *snow.Context
requirePrimaryNetworkSigners func() bool
}

// NewState returns a wrapper of [validators.State] which special cases the handling of the Primary Network.
//
// The wrapped state will return the chainContext's Subnet validator set instead of the Primary Network when
// the Primary Network SubnetID is passed in.
func NewState(chainContext *snow.Context) *State {
func NewState(chainContext *snow.Context, requirePrimaryNetworkSigners func() bool) *State {
return &State{
chainContext: chainContext,
State: chainContext.ValidatorState,
State: chainContext.ValidatorState,
chainContext: chainContext,
requirePrimaryNetworkSigners: requirePrimaryNetworkSigners,
}
}

Expand All @@ -39,9 +41,9 @@ func (s *State) GetValidatorSet(
height uint64,
subnetID ids.ID,
) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
// If the subnetID is anything other than the Primary Network, this is a direct
// passthrough
if subnetID != constants.PrimaryNetworkID {
// If the subnetID is anything other than the Primary Network, or Primary
// Network signers are required, this is a direct passthrough.
if s.requirePrimaryNetworkSigners() || subnetID != constants.PrimaryNetworkID {
return s.State.GetValidatorSet(ctx, height, subnetID)
}

Expand Down
2 changes: 1 addition & 1 deletion warp/validators/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestGetValidatorSetPrimaryNetwork(t *testing.T) {
snowCtx := utils.TestSnowContext()
snowCtx.SubnetID = mySubnetID
snowCtx.ValidatorState = mockState
state := NewState(snowCtx)
state := NewState(snowCtx, func() bool { return false })
// Expect that requesting my validator set returns my validator set
mockState.EXPECT().GetValidatorSet(gomock.Any(), gomock.Any(), mySubnetID).Return(make(map[ids.NodeID]*validators.GetValidatorOutput), nil)
output, err := state.GetValidatorSet(context.Background(), 10, mySubnetID)
Expand Down