Skip to content

Commit

Permalink
Add P-chain dynamic fees execution (#3251)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Aug 28, 2024
1 parent 0a8acde commit 82bf033
Show file tree
Hide file tree
Showing 14 changed files with 674 additions and 125 deletions.
209 changes: 171 additions & 38 deletions vms/platformvm/block/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import (
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/utils/timer/mockable"
"github.com/ava-labs/avalanchego/utils/units"
"github.com/ava-labs/avalanchego/vms/components/gas"
"github.com/ava-labs/avalanchego/vms/platformvm/block"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/status"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
"github.com/ava-labs/avalanchego/vms/platformvm/txs/fee"
"github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool"

blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor"
Expand Down Expand Up @@ -244,14 +246,30 @@ func (b *builder) PackAllBlockTxs() ([]*txs.Tx, error) {
return nil, fmt.Errorf("%w: %s", errMissingPreferredState, preferredID)
}

return packBlockTxs(
timestamp, _, err := state.NextBlockTime(preferredState, b.txExecutorBackend.Clk)
if err != nil {
return nil, fmt.Errorf("could not calculate next staker change time: %w", err)
}

if !b.txExecutorBackend.Config.UpgradeConfig.IsEtnaActivated(timestamp) {
return packDurangoBlockTxs(
preferredID,
preferredState,
b.Mempool,
b.txExecutorBackend,
b.blkManager,
timestamp,
math.MaxInt,
)
}
return packEtnaBlockTxs(
preferredID,
preferredState,
b.Mempool,
b.txExecutorBackend,
b.blkManager,
b.txExecutorBackend.Clk.Time(),
math.MaxInt,
timestamp,
math.MaxUint64,
)
}

Expand All @@ -264,15 +282,31 @@ func buildBlock(
forceAdvanceTime bool,
parentState state.Chain,
) (block.Block, error) {
blockTxs, err := packBlockTxs(
parentID,
parentState,
builder.Mempool,
builder.txExecutorBackend,
builder.blkManager,
timestamp,
targetBlockSize,
var (
blockTxs []*txs.Tx
err error
)
if builder.txExecutorBackend.Config.UpgradeConfig.IsEtnaActivated(timestamp) {
blockTxs, err = packEtnaBlockTxs(
parentID,
parentState,
builder.Mempool,
builder.txExecutorBackend,
builder.blkManager,
timestamp,
0, // minCapacity is 0 as we want to honor the capacity in state.
)
} else {
blockTxs, err = packDurangoBlockTxs(
parentID,
parentState,
builder.Mempool,
builder.txExecutorBackend,
builder.blkManager,
timestamp,
targetBlockSize,
)
}
if err != nil {
return nil, fmt.Errorf("failed to pack block txs: %w", err)
}
Expand Down Expand Up @@ -314,7 +348,7 @@ func buildBlock(
)
}

func packBlockTxs(
func packDurangoBlockTxs(
parentID ids.ID,
parentState state.Chain,
mempool mempool.Mempool,
Expand Down Expand Up @@ -346,55 +380,154 @@ func packBlockTxs(
if txSize > remainingSize {
break
}
mempool.Remove(tx)

// Invariant: [tx] has already been syntactically verified.

txDiff, err := state.NewDiffOn(stateDiff)
shouldAdd, err := executeTx(
parentID,
stateDiff,
mempool,
backend,
manager,
&inputs,
feeCalculator,
tx,
)
if err != nil {
return nil, err
}
if !shouldAdd {
continue
}

remainingSize -= txSize
blockTxs = append(blockTxs, tx)
}

return blockTxs, nil
}

func packEtnaBlockTxs(
parentID ids.ID,
parentState state.Chain,
mempool mempool.Mempool,
backend *txexecutor.Backend,
manager blockexecutor.Manager,
timestamp time.Time,
minCapacity gas.Gas,
) ([]*txs.Tx, error) {
stateDiff, err := state.NewDiffOn(parentState)
if err != nil {
return nil, err
}

if _, err := txexecutor.AdvanceTimeTo(backend, stateDiff, timestamp); err != nil {
return nil, err
}

feeState := stateDiff.GetFeeState()
capacity := max(feeState.Capacity, minCapacity)

executor := &txexecutor.StandardTxExecutor{
Backend: backend,
State: txDiff,
FeeCalculator: feeCalculator,
Tx: tx,
var (
blockTxs []*txs.Tx
inputs set.Set[ids.ID]
blockComplexity gas.Dimensions
feeCalculator = state.PickFeeCalculator(backend.Config, stateDiff)
)
for {
tx, exists := mempool.Peek()
if !exists {
break
}

err = tx.Unsigned.Visit(executor)
txComplexity, err := fee.TxComplexity(tx.Unsigned)
if err != nil {
txID := tx.ID()
mempool.MarkDropped(txID, err)
continue
return nil, err
}

if inputs.Overlaps(executor.Inputs) {
txID := tx.ID()
mempool.MarkDropped(txID, blockexecutor.ErrConflictingBlockTxs)
continue
newBlockComplexity, err := blockComplexity.Add(&txComplexity)
if err != nil {
return nil, err
}
err = manager.VerifyUniqueInputs(parentID, executor.Inputs)
newBlockGas, err := newBlockComplexity.ToGas(backend.Config.DynamicFeeConfig.Weights)
if err != nil {
txID := tx.ID()
mempool.MarkDropped(txID, err)
continue
return nil, err
}
if newBlockGas > capacity {
break
}
inputs.Union(executor.Inputs)

txDiff.AddTx(tx, status.Committed)
err = txDiff.Apply(stateDiff)
shouldAdd, err := executeTx(
parentID,
stateDiff,
mempool,
backend,
manager,
&inputs,
feeCalculator,
tx,
)
if err != nil {
return nil, err
}
if !shouldAdd {
continue
}

remainingSize -= txSize
blockComplexity = newBlockComplexity
blockTxs = append(blockTxs, tx)
}

return blockTxs, nil
}

func executeTx(
parentID ids.ID,
stateDiff state.Diff,
mempool mempool.Mempool,
backend *txexecutor.Backend,
manager blockexecutor.Manager,
inputs *set.Set[ids.ID],
feeCalculator fee.Calculator,
tx *txs.Tx,
) (bool, error) {
mempool.Remove(tx)

// Invariant: [tx] has already been syntactically verified.

txDiff, err := state.NewDiffOn(stateDiff)
if err != nil {
return false, err
}

executor := &txexecutor.StandardTxExecutor{
Backend: backend,
State: txDiff,
FeeCalculator: feeCalculator,
Tx: tx,
}

err = tx.Unsigned.Visit(executor)
if err != nil {
txID := tx.ID()
mempool.MarkDropped(txID, err)
return false, nil
}

if inputs.Overlaps(executor.Inputs) {
txID := tx.ID()
mempool.MarkDropped(txID, blockexecutor.ErrConflictingBlockTxs)
return false, nil
}
err = manager.VerifyUniqueInputs(parentID, executor.Inputs)
if err != nil {
txID := tx.ID()
mempool.MarkDropped(txID, err)
return false, nil
}
inputs.Union(executor.Inputs)

txDiff.AddTx(tx, status.Committed)
return true, txDiff.Apply(stateDiff)
}

// getNextStakerToReward returns the next staker txID to remove from the staking
// set with a RewardValidatorTx rather than an AdvanceTimeTx. [chainTimestamp]
// is the timestamp of the chain at the time this validator would be getting
Expand Down
36 changes: 36 additions & 0 deletions vms/platformvm/block/executor/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/components/gas"
"github.com/ava-labs/avalanchego/vms/platformvm/block"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/status"
Expand Down Expand Up @@ -460,6 +461,41 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, feeCalculator fee.Calculato
func(),
error,
) {
// Complexity is limited first to avoid processing too large of a block.
if timestamp := state.GetTimestamp(); v.txExecutorBackend.Config.UpgradeConfig.IsEtnaActivated(timestamp) {
var blockComplexity gas.Dimensions
for _, tx := range txs {
txComplexity, err := fee.TxComplexity(tx.Unsigned)
if err != nil {
txID := tx.ID()
v.MarkDropped(txID, err)
return nil, nil, nil, err
}

blockComplexity, err = blockComplexity.Add(&txComplexity)
if err != nil {
return nil, nil, nil, err
}
}

blockGas, err := blockComplexity.ToGas(v.txExecutorBackend.Config.DynamicFeeConfig.Weights)
if err != nil {
return nil, nil, nil, err
}

// If this block exceeds the available capacity, ConsumeGas will return
// an error.
feeState := state.GetFeeState()
feeState, err = feeState.ConsumeGas(blockGas)
if err != nil {
return nil, nil, nil, err
}

// Updating the fee state prior to executing the transactions is fine
// because the fee calculator was already created.
state.SetFeeState(feeState)
}

var (
onAcceptFunc func()
inputs set.Set[ids.ID]
Expand Down
Loading

0 comments on commit 82bf033

Please sign in to comment.