Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACP-77: Implement RegisterSubnetValidatorTx #3420

Draft
wants to merge 46 commits into
base: implement-acp-77-update-convert-subnet-tx
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ae9ec6f
wip
StephenButtolph Sep 24, 2024
584b4aa
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Sep 25, 2024
8905432
implement execution logic
StephenButtolph Sep 26, 2024
2618db2
remove duplicate public key
StephenButtolph Sep 26, 2024
322642b
finish e2e RegisterSubnetValidatorTx
StephenButtolph Sep 26, 2024
d68d935
improve error + logs
StephenButtolph Sep 26, 2024
dd41b73
improve doc
StephenButtolph Sep 26, 2024
ac054c7
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 1, 2024
01afe2a
Fix compilation
StephenButtolph Oct 1, 2024
38e8102
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 1, 2024
92f2af9
Update registerSubnetValdiatorTx
StephenButtolph Oct 1, 2024
fa12221
Fix wallet
StephenButtolph Oct 2, 2024
be028f8
merged
StephenButtolph Oct 2, 2024
755ebcb
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 2, 2024
c80e103
nit
StephenButtolph Oct 2, 2024
f1b3b85
Merge branch 'implement-acp-77-register-subnet-validator-tx' of githu…
StephenButtolph Oct 2, 2024
bfb226f
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 2, 2024
9025604
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 2, 2024
efb96b1
merged
StephenButtolph Oct 3, 2024
a25618e
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 3, 2024
80a7cbe
fix lint
StephenButtolph Oct 4, 2024
9ef28a1
revert test change
StephenButtolph Oct 4, 2024
59de74a
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 7, 2024
dda2598
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 7, 2024
2373cf6
nit
StephenButtolph Oct 7, 2024
4ba542a
wip e2e test
StephenButtolph Oct 8, 2024
1936cfc
wip
StephenButtolph Oct 8, 2024
f92b9c5
wip
StephenButtolph Oct 8, 2024
5875418
nit
StephenButtolph Oct 8, 2024
b0c0f0f
fix error message
StephenButtolph Oct 8, 2024
5e7be2b
fix log
StephenButtolph Oct 8, 2024
5ddff5e
merged
StephenButtolph Oct 8, 2024
afeabb6
backport tests
StephenButtolph Oct 8, 2024
9dc7447
merged
StephenButtolph Oct 8, 2024
fb4d8e9
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 8, 2024
ffd6a3a
merge
StephenButtolph Oct 8, 2024
5c86e5c
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 8, 2024
1815f64
Fix diff
StephenButtolph Oct 8, 2024
0dd0041
reduce diff
StephenButtolph Oct 8, 2024
1f168c7
Add RegisterSubnetValidatorTx complexity tests
StephenButtolph Oct 8, 2024
fcdce8c
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 8, 2024
1d4d0fe
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 10, 2024
c778c78
merged
StephenButtolph Oct 11, 2024
e1e04de
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 14, 2024
96625ae
Fix merge
StephenButtolph Oct 14, 2024
f1518a8
Merge branch 'implement-acp-77-update-convert-subnet-tx' into impleme…
StephenButtolph Oct 15, 2024
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
2 changes: 1 addition & 1 deletion upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ var (
DurangoTime: InitiallyActiveTime,
// Etna is left unactivated by default on local networks. It can be configured to
// activate by overriding the activation time in the upgrade file.
EtnaTime: UnscheduledActivationTime,
EtnaTime: InitiallyActiveTime,
}

ErrInvalidUpgradeTimes = errors.New("invalid upgrade configuration")
Expand Down
11 changes: 9 additions & 2 deletions vms/platformvm/metrics/tx_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,23 @@ func (m *txMetrics) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) er
return nil
}

func (m *txMetrics) BaseTx(*txs.BaseTx) error {
m.numTxs.With(prometheus.Labels{
txLabel: "base",
}).Inc()
return nil
}

func (m *txMetrics) ConvertSubnetTx(*txs.ConvertSubnetTx) error {
m.numTxs.With(prometheus.Labels{
txLabel: "convert_subnet",
}).Inc()
return nil
}

func (m *txMetrics) BaseTx(*txs.BaseTx) error {
func (m *txMetrics) RegisterSubnetValidatorTx(*txs.RegisterSubnetValidatorTx) error {
m.numTxs.With(prometheus.Labels{
txLabel: "base",
txLabel: "register_subnet_validator",
}).Inc()
return nil
}
1 change: 1 addition & 0 deletions vms/platformvm/txs/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,6 @@ func RegisterDurangoTypes(targetCodec linearcodec.Codec) error {
func RegisterEtnaTypes(targetCodec linearcodec.Codec) error {
return errors.Join(
targetCodec.RegisterType(&ConvertSubnetTx{}),
targetCodec.RegisterType(&RegisterSubnetValidatorTx{}),
)
}
10 changes: 7 additions & 3 deletions vms/platformvm/txs/executor/atomic_tx_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ func (*AtomicTxExecutor) TransformSubnetTx(*txs.TransformSubnetTx) error {
return ErrWrongTxType
}

func (*AtomicTxExecutor) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error {
func (*AtomicTxExecutor) AddPermissionlessValidatorTx(*txs.AddPermissionlessValidatorTx) error {
return ErrWrongTxType
}

func (*AtomicTxExecutor) AddPermissionlessValidatorTx(*txs.AddPermissionlessValidatorTx) error {
func (*AtomicTxExecutor) AddPermissionlessDelegatorTx(*txs.AddPermissionlessDelegatorTx) error {
return ErrWrongTxType
}

func (*AtomicTxExecutor) AddPermissionlessDelegatorTx(*txs.AddPermissionlessDelegatorTx) error {
func (*AtomicTxExecutor) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error {
return ErrWrongTxType
}

Expand All @@ -86,6 +86,10 @@ func (*AtomicTxExecutor) ConvertSubnetTx(*txs.ConvertSubnetTx) error {
return ErrWrongTxType
}

func (*AtomicTxExecutor) RegisterSubnetValidatorTx(*txs.RegisterSubnetValidatorTx) error {
return ErrWrongTxType
}

func (e *AtomicTxExecutor) ImportTx(tx *txs.ImportTx) error {
return e.atomicTx(tx)
}
Expand Down
4 changes: 4 additions & 0 deletions vms/platformvm/txs/executor/proposal_tx_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func (*ProposalTxExecutor) ConvertSubnetTx(*txs.ConvertSubnetTx) error {
return ErrWrongTxType
}

func (*ProposalTxExecutor) RegisterSubnetValidatorTx(*txs.RegisterSubnetValidatorTx) error {
return ErrWrongTxType
}

func (e *ProposalTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error {
// AddValidatorTx is a proposal transaction until the Banff fork
// activation. Following the activation, AddValidatorTxs must be issued into
Expand Down
176 changes: 176 additions & 0 deletions vms/platformvm/txs/executor/standard_tx_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package executor

import (
"bytes"
"context"
"errors"
"fmt"
Expand All @@ -15,15 +16,27 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/ava-labs/avalanchego/utils/math"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/components/gas"
"github.com/ava-labs/avalanchego/vms/components/verify"
"github.com/ava-labs/avalanchego/vms/platformvm/signer"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
"github.com/ava-labs/avalanchego/vms/platformvm/txs/fee"
"github.com/ava-labs/avalanchego/vms/platformvm/warp"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/message"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/payload"
)

const (
second = 1
minute = 60 * second
hour = 60 * minute
day = 24 * hour
RegisterSubnetValidatorTxExpiryWindow = day
)

var (
Expand Down Expand Up @@ -617,6 +630,169 @@ func (e *StandardTxExecutor) ConvertSubnetTx(tx *txs.ConvertSubnetTx) error {
return nil
}

func (e *StandardTxExecutor) RegisterSubnetValidatorTx(tx *txs.RegisterSubnetValidatorTx) error {
var (
currentTimestamp = e.State.GetTimestamp()
upgrades = e.Backend.Config.UpgradeConfig
)
if !upgrades.IsEtnaActivated(currentTimestamp) {
return errEtnaUpgradeNotActive
}

if err := e.Tx.SyntacticVerify(e.Ctx); err != nil {
return err
}

if err := avax.VerifyMemoFieldLength(tx.Memo, true /*=isDurangoActive*/); err != nil {
return err
}

// Verify the flowcheck
fee, err := e.FeeCalculator.CalculateFee(tx)
if err != nil {
return err
}
fee, err = math.Add(fee, tx.Balance)
if err != nil {
return err
}

if err := e.Backend.FlowChecker.VerifySpend(
tx,
e.State,
tx.Ins,
tx.Outs,
e.Tx.Creds,
map[ids.ID]uint64{
e.Ctx.AVAXAssetID: fee,
},
); err != nil {
return err
}

warpMessage, err := warp.ParseMessage(tx.Message)
if err != nil {
return err
}
if warpMessage.NetworkID != e.Ctx.NetworkID {
return fmt.Errorf("expected networkID %d but got %d", e.Ctx.NetworkID, warpMessage.NetworkID)
}

addressedCall, err := payload.ParseAddressedCall(warpMessage.Payload)
if err != nil {
return err
}

msg, err := message.ParseRegisterSubnetValidator(addressedCall.Payload)
if err != nil {
return err
}
if err := msg.Verify(); err != nil {
return err
}

_, expectedChainID, expectedAddress, err := e.State.GetSubnetConversion(msg.SubnetID)
if err != nil {
return err
}
if warpMessage.SourceChainID != expectedChainID {
return fmt.Errorf("expected chainID %s but got %s", expectedChainID, warpMessage.SourceChainID)
}
if !bytes.Equal(addressedCall.SourceAddress, expectedAddress) {
return fmt.Errorf("expected address %s but got %s", expectedAddress, addressedCall.SourceAddress)
}

currentTimestampUnix := uint64(currentTimestamp.Unix())
if msg.Expiry <= currentTimestampUnix {
return fmt.Errorf("expected expiry to be after %d but got %d", currentTimestampUnix, msg.Expiry)
}
maxAllowedExpiry, err := math.Add(currentTimestampUnix, RegisterSubnetValidatorTxExpiryWindow)
if err != nil {
// This should never happen, as it would imply that either
// currentTimestampUnix or RegisterSubnetValidatorTxExpiryWindow is
// significantly larger than expected.
return err
}
if msg.Expiry > maxAllowedExpiry {
return fmt.Errorf("expected expiry to be before %d but got %d", maxAllowedExpiry, msg.Expiry)
StephenButtolph marked this conversation as resolved.
Show resolved Hide resolved
}

pop := signer.ProofOfPossession{
PublicKey: msg.BLSPublicKey,
ProofOfPossession: tx.ProofOfPossession,
}
if err := pop.Verify(); err != nil {
return err
}

validationID := hashing.ComputeHash256Array(addressedCall.Payload)
expiry := state.ExpiryEntry{
Timestamp: msg.Expiry,
ValidationID: validationID,
}
isDuplicate, err := e.State.HasExpiry(expiry)
if err != nil {
return err
}
if isDuplicate {
return fmt.Errorf("expiry for %s already exists", validationID)
}

nodeID, err := ids.ToNodeID(msg.NodeID)
if err != nil {
return err
}

remainingBalanceOwner, err := txs.Codec.Marshal(txs.CodecVersion, &msg.RemainingBalanceOwner)
if err != nil {
return err
}

deactivationOwner, err := txs.Codec.Marshal(txs.CodecVersion, &msg.DisableOwner)
if err != nil {
return err
}

sov := state.SubnetOnlyValidator{
ValidationID: validationID,
SubnetID: msg.SubnetID,
NodeID: nodeID,
PublicKey: bls.PublicKeyToUncompressedBytes(pop.Key()),
RemainingBalanceOwner: remainingBalanceOwner,
DeactivationOwner: deactivationOwner,
StartTime: currentTimestampUnix,
Weight: msg.Weight,
MinNonce: 0,
EndAccumulatedFee: 0, // If Balance is 0, this is 0
}
if tx.Balance != 0 {
// We are attempting to add an active validator
if gas.Gas(e.State.NumActiveSubnetOnlyValidators()) >= e.Backend.Config.ValidatorFeeCapacity {
return errMaxNumActiveValidators
}

currentFees := e.State.GetAccruedFees()
sov.EndAccumulatedFee, err = math.Add(tx.Balance, currentFees)
if err != nil {
return err
}
}

if err := e.State.PutSubnetOnlyValidator(sov); err != nil {
return err
}

txID := e.Tx.ID()

// Consume the UTXOS
avax.Consume(e.State, tx.Ins)
// Produce the UTXOS
avax.Produce(e.State, txID, tx.Outs)
// Prevent this warp message from being replayed
e.State.PutExpiry(expiry)
return nil
}

func (e *StandardTxExecutor) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error {
if err := verifyAddPermissionlessValidatorTx(
e.Backend,
Expand Down
35 changes: 34 additions & 1 deletion vms/platformvm/txs/fee/complexity.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,19 @@ var (
ids.IDLen + // chainID
wrappers.IntLen + // address length
wrappers.IntLen + // validators length
wrappers.IntLen + // subnetAuth typeID
bls.SignatureLen + // proofOfPossession
wrappers.IntLen, // subnetAuthCredential typeID
gas.DBRead: 2, // subnet auth + manager lookup
gas.DBWrite: 2, // manager + weight
gas.Compute: 0, // TODO: Add compute complexity (and include the PoP compute)
}
IntrinsicRegisterSubnetValidatorTxComplexities = gas.Dimensions{
gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
wrappers.LongLen + // balance
wrappers.IntLen + // signer typeID
wrappers.IntLen, // message length
gas.DBRead: 0, // TODO
gas.DBWrite: 0, // TODO
gas.Compute: 0,
}

Expand Down Expand Up @@ -433,6 +442,14 @@ func SignerComplexity(s signer.Signer) (gas.Dimensions, error) {
}
}

// WarpComplexity returns the complexity a warp message adds to a transaction.
func WarpComplexity(message []byte) (gas.Dimensions, error) {
// TODO: Implement me
return gas.Dimensions{
gas.Bandwidth: uint64(len(message)),
}, nil
}

type complexityVisitor struct {
output gas.Dimensions
}
Expand Down Expand Up @@ -683,6 +700,22 @@ func (c *complexityVisitor) ConvertSubnetTx(tx *txs.ConvertSubnetTx) error {
return err
}

func (c *complexityVisitor) RegisterSubnetValidatorTx(tx *txs.RegisterSubnetValidatorTx) error {
baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
if err != nil {
return err
}
warpComplexity, err := WarpComplexity(tx.Message)
if err != nil {
return err
}
c.output, err = IntrinsicConvertSubnetTxComplexities.Add(
&baseTxComplexity,
&warpComplexity,
)
return err
}

func baseTxComplexity(tx *txs.BaseTx) (gas.Dimensions, error) {
outputsComplexity, err := OutputComplexity(tx.Outs...)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions vms/platformvm/txs/fee/static_calculator.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func (*staticVisitor) ConvertSubnetTx(*txs.ConvertSubnetTx) error {
return ErrUnsupportedTx
}

func (*staticVisitor) RegisterSubnetValidatorTx(*txs.RegisterSubnetValidatorTx) error {
return ErrUnsupportedTx
}

func (c *staticVisitor) AddValidatorTx(*txs.AddValidatorTx) error {
c.fee = c.config.AddPrimaryNetworkValidatorFee
return nil
Expand Down
Loading
Loading