Skip to content

Commit

Permalink
[PVM] Disable baseFee and feeDistribution proposal before CairoPhase (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
evlekht authored Aug 7, 2024
1 parent 562aff2 commit e00d359
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 39 deletions.
2 changes: 1 addition & 1 deletion vms/platformvm/camino_vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ func TestProposals(t *testing.T) {
VerifyNodeSignature: true,
LockModeBondDeposit: true,
InitialAdmin: test.FundedKeys[0].Address(),
}, test.PhaseLast, []api.UTXO{
}, test.PhaseCairo, []api.UTXO{ // TODO @evlekht replace with PhaseLast when cairo is added
{
Amount: json.Uint64(balance),
Address: proposerAddrStr,
Expand Down
7 changes: 7 additions & 0 deletions vms/platformvm/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ type Config struct {
// Time of the BerlinPhase network upgrade
BerlinPhaseTime time.Time

// Time of the CairoPhase network upgrade
CairoPhaseTime time.Time

// Subnet ID --> Minimum portion of the subnet's stake this node must be
// connected to in order to report healthy.
// [constants.PrimaryNetworkID] is always a key in this map.
Expand Down Expand Up @@ -159,6 +162,10 @@ func (c *Config) IsBerlinPhaseActivated(timestamp time.Time) bool {
return !timestamp.Before(c.BerlinPhaseTime)
}

func (c *Config) IsCairoPhaseActivated(timestamp time.Time) bool {
return !timestamp.Before(c.CairoPhaseTime)
}

func (c *Config) GetCreateBlockchainTxFee(timestamp time.Time) uint64 {
if c.IsApricotPhase3Activated(timestamp) {
return c.CreateBlockchainTxFee
Expand Down
6 changes: 3 additions & 3 deletions vms/platformvm/dac/camino_general_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
const (
generalProposalMaxOptionsCount = 3
generalProposalMaxOptionSize = 256
generalProposalMinDuration = uint64(time.Hour * 24 / time.Second) // 1 day
GeneralProposalMinDuration = uint64(time.Hour * 24 / time.Second) // 1 day
generalProposalMaxDuration = uint64(time.Hour * 24 * 30 / time.Second) // 1 month
)

Expand Down Expand Up @@ -75,8 +75,8 @@ func (p *GeneralProposal) Verify() error {
return fmt.Errorf("%w (expected: no more than %d, actual: %d)", errWrongOptionsCount, generalProposalMaxOptionsCount, len(p.Options))
case p.Start >= p.End:
return errEndNotAfterStart
case p.End-p.Start < generalProposalMinDuration:
return fmt.Errorf("%w (expected: minimum duration %d, actual: %d)", errWrongDuration, generalProposalMinDuration, p.End-p.Start)
case p.End-p.Start < GeneralProposalMinDuration:
return fmt.Errorf("%w (expected: minimum duration %d, actual: %d)", errWrongDuration, GeneralProposalMinDuration, p.End-p.Start)
case p.End-p.Start > generalProposalMaxDuration:
return fmt.Errorf("%w (expected: maximum duration %d, actual: %d)", errWrongDuration, generalProposalMaxDuration, p.End-p.Start)
}
Expand Down
20 changes: 10 additions & 10 deletions vms/platformvm/dac/camino_general_proposal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ func TestGeneralProposalVerify(t *testing.T) {
"To small duration": {
proposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration - 1,
End: 100 + GeneralProposalMinDuration - 1,
Options: [][]byte{{1}, {2}, {3}},
},
expectedProposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration - 1,
End: 100 + GeneralProposalMinDuration - 1,
Options: [][]byte{{1}, {2}, {3}},
},
expectedErr: errWrongDuration,
Expand All @@ -97,50 +97,50 @@ func TestGeneralProposalVerify(t *testing.T) {
"Option is bigger than allowed": {
proposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{make([]byte, generalProposalMaxOptionSize+1)},
},
expectedProposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{make([]byte, generalProposalMaxOptionSize+1)},
},
expectedErr: errGeneralProposalOptionIsToBig,
},
"Not unique option": {
proposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{{1}, {2}, {1}},
},
expectedProposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{{1}, {2}, {1}},
},
expectedErr: errNotUniqueOption,
},
"OK: 1 option": {
proposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{make([]byte, generalProposalMaxOptionSize)},
},
expectedProposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{make([]byte, generalProposalMaxOptionSize)},
},
},
"OK: 3 options": {
proposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{{1}, {2}, {3}},
},
expectedProposal: &GeneralProposal{
Start: 100,
End: 100 + generalProposalMinDuration,
End: 100 + GeneralProposalMinDuration,
Options: [][]byte{{1}, {2}, {3}},
},
},
Expand Down
5 changes: 5 additions & 0 deletions vms/platformvm/test/camino_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,15 @@ func Config(t *testing.T, phase Phase) *config.Config {
athensTime = mockable.MaxTime
cortinaTime = mockable.MaxTime
berlinTime = mockable.MaxTime
cairoTime = mockable.MaxTime
)

// always reset LatestForkTime (a package level variable)
// to ensure test independence
switch phase {
case PhaseCairo:
cairoTime = LatestPhaseTime
fallthrough
case PhaseBerlin: // same time, as PhaseCortina
berlinTime = LatestPhaseTime
fallthrough
Expand Down Expand Up @@ -119,6 +123,7 @@ func Config(t *testing.T, phase Phase) *config.Config {
AthensPhaseTime: athensTime,
CortinaTime: cortinaTime,
BerlinPhaseTime: berlinTime,
CairoPhaseTime: cairoTime,
CaminoConfig: caminoconfig.Config{
DACProposalBondAmount: 100 * units.Avax,
},
Expand Down
5 changes: 5 additions & 0 deletions vms/platformvm/test/camino_phase.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
PhaseAthens Phase = 2
PhaseCortina Phase = 3 // avax, included into Berlin phase
PhaseBerlin Phase = 3
PhaseCairo Phase = 4
)

// TODO @evlekht we might want to clean up sunrise/banff timestamps/relations later
Expand All @@ -37,6 +38,8 @@ func PhaseTime(t *testing.T, phase Phase, cfg *config.Config) time.Time {
return cfg.AthensPhaseTime
case PhaseBerlin:
return cfg.BerlinPhaseTime
case PhaseCairo:
return cfg.CairoPhaseTime
}
require.FailNow(t, "unknown phase")
return time.Time{}
Expand All @@ -50,6 +53,8 @@ func PhaseName(t *testing.T, phase Phase) string {
return "AthensPhase"
case PhaseBerlin:
return "BerlinPhase"
case PhaseCairo:
return "CairoPhase"
}
require.FailNow(t, "unknown phase")
return ""
Expand Down
3 changes: 1 addition & 2 deletions vms/platformvm/txs/executor/camino_tx_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,7 @@ func (e *CaminoStandardTxExecutor) AddProposalTx(tx *txs.AddProposalTx) error {
return fmt.Errorf("%w: %s", errProposerCredentialMismatch, err)
}

if err := txProposal.VerifyWith(dac.NewProposalVerifier(e.State, tx, isAdminProposal)); err != nil {
if err := txProposal.VerifyWith(dac.NewProposalVerifier(e.Config, e.State, tx, isAdminProposal)); err != nil {
return fmt.Errorf("%w: %s", errInvalidProposal, err)
}

Expand Down Expand Up @@ -1799,7 +1799,6 @@ func (e *CaminoStandardTxExecutor) AddProposalTx(tx *txs.AddProposalTx) error {
var proposalState dacProposals.ProposalState

if isAdminProposal {
// currently we only have addMember and excludeMember proposals, and their option 0 is "success" option
proposalState, err = txProposal.CreateFinishedProposalState(adminProposal.OptionIndex)
if err != nil {
// should never happen
Expand Down
19 changes: 9 additions & 10 deletions vms/platformvm/txs/executor/camino_tx_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5907,9 +5907,10 @@ func TestCaminoStandardTxExecutorAddProposalTx(t *testing.T) {
bondUTXO := generate.UTXO(ids.ID{1, 2, 3, 4, 6}, ctx.AVAXAssetID, proposalBondAmt, bondOwner, ids.Empty, ids.Empty, true)

applicantAddress := ids.ShortID{1, 1, 1}
proposerNodeShortID := ids.ShortID{2, 2, 2}

proposalWrapper := &txs.ProposalWrapper{Proposal: &dac.BaseFeeProposal{
Start: 100, End: 101, Options: []uint64{1},
proposalWrapper := &txs.ProposalWrapper{Proposal: &dac.GeneralProposal{
Start: 100, End: 100 + dac.GeneralProposalMinDuration, Options: [][]byte{{}},
}}
proposalBytes, err := txs.Codec.Marshal(txs.Version, proposalWrapper)
require.NoError(t, err)
Expand Down Expand Up @@ -6149,7 +6150,7 @@ func TestCaminoStandardTxExecutorAddProposalTx(t *testing.T) {
s.EXPECT().CaminoConfig().Return(caminoStateConf, nil)
s.EXPECT().GetTimestamp().Return(cfg.BerlinPhaseTime)
expect.VerifyMultisigPermission(t, s, []ids.ShortID{utx.ProposerAddress}, nil)
s.EXPECT().GetAddressStates(utx.ProposerAddress).Return(as.AddressStateEmpty, nil) // not AddressStateCaminoProposer
s.EXPECT().GetAddressStates(utx.ProposerAddress).Return(as.AddressStateEmpty, nil) // not AddressStateConsortium
return s
},
utx: func(cfg *config.Config) *txs.AddProposalTx {
Expand Down Expand Up @@ -6190,13 +6191,11 @@ func TestCaminoStandardTxExecutorAddProposalTx(t *testing.T) {
expect.VerifyMultisigPermission(t, s, []ids.ShortID{utx.ProposerAddress}, nil)

// * proposal verifier
proposalsIterator := state.NewMockProposalsIterator(c)
proposalsIterator.EXPECT().Next().Return(false)
proposalsIterator.EXPECT().Release()
proposalsIterator.EXPECT().Error().Return(nil)

s.EXPECT().GetAddressStates(utx.ProposerAddress).Return(as.AddressStateCaminoProposer, nil)
s.EXPECT().GetProposalIterator().Return(proposalsIterator, nil)
s.EXPECT().GetAddressStates(utx.ProposerAddress).Return(as.AddressStateConsortium, nil)
s.EXPECT().GetShortIDLink(utx.ProposerAddress, state.ShortLinkKeyRegisterNode).
Return(proposerNodeShortID, nil)
s.EXPECT().GetCurrentValidator(constants.PrimaryNetworkID, ids.NodeID(proposerNodeShortID)).
Return(&state.Staker{}, nil)
// *

s.EXPECT().GetBaseFee().Return(test.TxFee, nil)
Expand Down
14 changes: 13 additions & 1 deletion vms/platformvm/txs/executor/dac/camino_dac.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
as "github.com/ava-labs/avalanchego/vms/platformvm/addrstate"
"github.com/ava-labs/avalanchego/vms/platformvm/config"
"github.com/ava-labs/avalanchego/vms/platformvm/dac"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
Expand All @@ -27,9 +28,11 @@ var (
errNotPermittedToCreateProposal = errors.New("don't have permission to create proposal of this type")
errAlreadyActiveProposal = errors.New("there is already active proposal of this type")
errNoActiveValidator = errors.New("no active validator")
errNotCairoPhase = errors.New("not allowed before CairoPhase")
)

type proposalVerifier struct {
config *config.Config
state state.Chain
addProposalTx *txs.AddProposalTx
isAdminProposal bool
Expand All @@ -52,8 +55,9 @@ type proposalBondTxIDsGetter struct {
state state.Chain
}

func NewProposalVerifier(state state.Chain, tx *txs.AddProposalTx, isAdminProposal bool) dac.Verifier {
func NewProposalVerifier(config *config.Config, state state.Chain, tx *txs.AddProposalTx, isAdminProposal bool) dac.Verifier {
return &proposalVerifier{
config: config,
state: state,
addProposalTx: tx,
isAdminProposal: isAdminProposal,
Expand Down Expand Up @@ -89,6 +93,10 @@ func getBondTxIDs(bondTxIDsGetter dac.BondTxIDsGetter, state state.Chain, tx *tx
// BaseFeeProposal

func (e *proposalVerifier) BaseFeeProposal(*dac.BaseFeeProposal) error {
if !e.config.IsCairoPhaseActivated(e.state.GetTimestamp()) {
return errNotCairoPhase
}

// verify address state (role)
proposerAddressState, err := e.state.GetAddressStates(e.addProposalTx.ProposerAddress)
if err != nil {
Expand Down Expand Up @@ -354,6 +362,10 @@ func (*proposalBondTxIDsGetter) GeneralProposal(*dac.GeneralProposalState) ([]id
// FeeDistributionProposal

func (e *proposalVerifier) FeeDistributionProposal(*dac.FeeDistributionProposal) error {
if !e.config.IsCairoPhaseActivated(e.state.GetTimestamp()) {
return errNotCairoPhase
}

// verify address state (role)
proposerAddressState, err := e.state.GetAddressStates(e.addProposalTx.ProposerAddress)
if err != nil {
Expand Down
Loading

0 comments on commit e00d359

Please sign in to comment.