Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
47 changes: 24 additions & 23 deletions contracts/generated/NetworkConfig/NetworkConfig.go

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions contracts/src/l1_management/contracts/NetworkConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ contract NetworkConfig is Initializable, UnrenouncableOwnable2Step {
* @param featureName The name of the feature that was upgraded
* @param featureData The data of the feature that was upgraded - to be forwarded to it for initialization.
*/
event Upgraded(string featureName, bytes featureData);
event Upgraded(string featureName, bytes featureData, uint256 validAtBlock);

/**
* @dev Initializes the contract with addresses and owner
Expand Down Expand Up @@ -279,7 +279,8 @@ contract NetworkConfig is Initializable, UnrenouncableOwnable2Step {
* @param featureName The name of the feature that was upgraded
* @param featureData The data of the feature that was upgraded - to be forwarded to it for initialization.
*/
function upgradeFeature(string calldata featureName, bytes calldata featureData) external onlyOwner {
emit Upgraded(featureName, featureData);
function upgradeFeature(string calldata featureName, bytes calldata featureData, uint256 validAtBlock) external onlyOwner {
require(validAtBlock > block.number + 64, "Invalid validAtBlock");
emit Upgraded(featureName, featureData, validAtBlock);
}
}
1 change: 1 addition & 0 deletions go/common/errutil/errors_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
ErrCrossChainBundleNoBatches = errors.New("no batches for cross chain bundle")
ErrCrossChainRootMismatch = errors.New("cross chain root mismatch")
ErrCriticalRollupProcessing = errors.New("critical error during rollup processing")
ErrUpgradeNotSupported = errors.New("upgrade not supported")
)

// BlockRejectError is used as a standard format for error response from enclave for block submission errors
Expand Down
14 changes: 14 additions & 0 deletions go/common/rpc/converters.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package rpc

import (
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/crypto/kzg4844"

"github.com/ten-protocol/go-ten/go/common"
"github.com/ten-protocol/go-ten/go/common/errutil"
"github.com/ten-protocol/go-ten/go/common/rpc/generated"

gethcommon "github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -78,6 +80,17 @@ func ToBlockSubmissionResponseMsg(response *common.BlockSubmissionResponse) (*ge
return msg, nil
}

func FromBlockSubmissionErrorMsg(msg *generated.BlockSubmissionErrorMsg) *errutil.BlockRejectError {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasn't this already merged as a separate pr?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i split it out of this

if msg == nil {
return nil
}

return &errutil.BlockRejectError{
L1Head: gethcommon.BytesToHash(msg.L1Head),
Wrapped: errors.New(msg.Cause),
}
}

func FromBlockSubmissionResponseMsg(msg *generated.BlockSubmissionResponseMsg) (*common.BlockSubmissionResponse, error) {
rollupMetadata := make([]common.ExtRollupMetadata, len(msg.RollupMetadata))
for i, metadata := range msg.RollupMetadata {
Expand All @@ -88,6 +101,7 @@ func FromBlockSubmissionResponseMsg(msg *generated.BlockSubmissionResponseMsg) (
return &common.BlockSubmissionResponse{
ProducedSecretResponses: FromSecretRespMsg(msg.ProducedSecretResponses),
RollupMetadata: rollupMetadata,
RejectError: FromBlockSubmissionErrorMsg(msg.Error),
}, nil
}

Expand Down
5 changes: 1 addition & 4 deletions go/enclave/components/gas_pricer.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import (
)

const (
InitialBaseFee = params.InitialBaseFee / 10 // InitialBaseFee is ETH's base fee.
ComponentName = "gas_pricing"
DynamicPricingTrigger = "dynamic-pricing"
StaticPricingTrigger = "static_pricing"
InitialBaseFee = params.InitialBaseFee / 10 // InitialBaseFee is ETH's base fee.
)

type GasPricer struct {
Expand Down
139 changes: 138 additions & 1 deletion go/enclave/components/upgrade_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package components

import (
"context"
"fmt"

"github.com/ethereum/go-ethereum/core/types"
gethlog "github.com/ethereum/go-ethereum/log"
"github.com/ten-protocol/go-ten/contracts/generated/NetworkConfig"
"github.com/ten-protocol/go-ten/go/common"
"github.com/ten-protocol/go-ten/go/common/errutil"
"github.com/ten-protocol/go-ten/go/enclave/storage"
"github.com/ten-protocol/go-ten/go/enclave/storage/enclavedb"
)

// NetworkUpgradeConfirmationDepth retained for reference
Expand All @@ -33,8 +37,141 @@ func (um *upgradeManager) RegisterUpgradeHandler(featureName string, handler Upg
// keep API no-op
}

func (um *upgradeManager) StoreNetworkUpgrades(ctx context.Context, blockHeader *types.Header, upgrades []NetworkConfig.NetworkConfigUpgraded) error {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be public?

if len(upgrades) == 0 {
return nil
}

for _, upgrade := range upgrades {
um.logger.Info("Upgrade detected", "featureName", upgrade.FeatureName, "featureData", upgrade.FeatureData)
blockHeight := blockHeader.Number.Uint64() + 64
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use NetworkUpgradeConfirmationDepth

blockHeightActive := upgrade.ValidAtBlock.Uint64()

err := um.storage.StoreNetworkUpgrade(ctx, &enclavedb.NetworkUpgrade{
FeatureName: upgrade.FeatureName,
FeatureData: upgrade.FeatureData,
BlockHash: blockHeader.Hash(),
BlockHeightFinal: &blockHeight,
BlockHeightActive: &blockHeightActive,
})
if err != nil {
return fmt.Errorf("failed to store network upgrade. Cause: %w", err)
}
}
um.logger.Info("Stored network upgrades", "upgrades", len(upgrades))
return nil
}

// collectNetworkUpgrades extracts all NetworkConfigUpgraded from L1 data
func (um *upgradeManager) collectNetworkUpgrades(processed *common.ProcessedL1Data) []NetworkConfig.NetworkConfigUpgraded {
upgradeTxs := processed.GetEvents(common.NetworkUpgradedTx)
allUpgrades := make([]NetworkConfig.NetworkConfigUpgraded, 0)
for _, tx := range upgradeTxs {
allUpgrades = append(allUpgrades, tx.NetworkUpgrades...)
}
return allUpgrades
}

// filterSupportedUpgrades filters upgrades to only include supported ones
func (um *upgradeManager) filterSupportedUpgrades(ctx context.Context, allUpgrades []NetworkConfig.NetworkConfigUpgraded) []NetworkConfig.NetworkConfigUpgraded {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method feels too hypothetical.
I have a feeling it will not look like this in practice.
Please leave a comment that this is an indicative implementation

supportedUpgrades := make([]NetworkConfig.NetworkConfigUpgraded, 0)
for _, upgrade := range allUpgrades {
um.logger.Info("Upgrade detected", "featureName", upgrade.FeatureName, "featureData", upgrade.FeatureData)

// Check if handler is registered for this upgrade
handlers, ok := um.handlers[upgrade.FeatureName]
if !ok {
um.logger.Warn("No handler registered for upgrade, filtering out", "featureName", upgrade.FeatureName)
continue
}

// Check if all handlers support this upgrade
upgradeSupported := true
for _, handler := range handlers {
canUpgrade := handler.CanUpgrade(ctx, upgrade.FeatureName, upgrade.FeatureData)
if !canUpgrade {
um.logger.Warn("Upgrade not supported by handler, filtering out", "featureName", upgrade.FeatureName)
upgradeSupported = false
break
}
}

if upgradeSupported {
supportedUpgrades = append(supportedUpgrades, upgrade)
um.logger.Info("Upgrade supported and included", "featureName", upgrade.FeatureName)
}
}

um.logger.Info("Filtered upgrades", "total", len(allUpgrades), "supported", len(supportedUpgrades))
return supportedUpgrades
}

func (um *upgradeManager) getUpgradesFor(blockHeader *types.Header) ([]NetworkConfig.NetworkConfigUpgraded, error) {
ctx := context.Background()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not pass the context?


// Ensure the current block is canonical before proceeding
isCanonical, err := um.storage.IsBlockCanonical(ctx, blockHeader.Hash())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is called from OnL1Block, it means only canonical l1 blocks are sent in. I dont think this check is necessary, maybe just leave a comment

if err != nil {
um.logger.Error("Failed to check block canonicality", "hash", blockHeader.Hash(), "error", err)
return nil, fmt.Errorf("failed to check block canonicality: %w", err)
}
if !isCanonical {
return nil, fmt.Errorf("block %s is not canonical", blockHeader.Hash())
}

// Load activated upgrades up to current block height
currentHeight := blockHeader.Number.Uint64()
stored, err := um.storage.GetActivatedNetworkUpgrades(ctx, currentHeight)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't you have to adjust with the 64 constant?

if err != nil {
um.logger.Error("Failed to load activated network upgrades from storage", "error", err, "height", currentHeight)
return nil, fmt.Errorf("failed to load activated network upgrades: %w", err)
}

// Filter: only upgrades whose saved block hash is canonical
candidates := make([]NetworkConfig.NetworkConfigUpgraded, 0)
for _, u := range stored {
// The upgrade must have been recorded for a canonical block hash
upgradeBlockCanonical, err := um.storage.IsBlockCanonical(ctx, u.BlockHash)
if err != nil {
um.logger.Error("Failed to check canonicality for upgrade's block", "hash", u.BlockHash, "error", err)
return nil, fmt.Errorf("failed to check canonicality for upgrade's block: %w", err)
}
if !upgradeBlockCanonical {
continue
}

candidates = append(candidates, NetworkConfig.NetworkConfigUpgraded{
FeatureName: u.FeatureName,
FeatureData: u.FeatureData,
})
}

// Verify all selected upgrades are supported by registered handlers
supported := um.filterSupportedUpgrades(ctx, candidates)
if len(supported) != len(candidates) {
return nil, fmt.Errorf("unsupported upgrades detected at height %d: total=%d supported=%d", currentHeight, len(candidates), len(supported))
}

return supported, nil
}

func (um *upgradeManager) OnL1Block(ctx context.Context, blockHeader *types.Header, processed *common.ProcessedL1Data) error {
// no-op: upgrades disabled
// Collect all upgrades from L1 data
allUpgrades := um.collectNetworkUpgrades(processed)

// Store all upgrades (both supported and unsupported)
err := um.StoreNetworkUpgrades(ctx, blockHeader, allUpgrades)
if err != nil {
um.logger.Error("Failed to store network upgrades", "error", err)
return err
}

_, err = um.getUpgradesFor(blockHeader)
if err != nil {
um.logger.Error("Failed to get upgrades for block", "error", err)
return errutil.ErrUpgradeNotSupported
}

return nil
}

Expand Down
13 changes: 7 additions & 6 deletions go/enclave/enclave_admin_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ func (e *enclaveAdminService) SubmitL1Block(ctx context.Context, blockData *comm
return nil, e.rejectBlockErr(ctx, fmt.Errorf("could not submit L1 block. Cause: %w", err))
}

// Process network upgrade events when they reach finality
err = e.upgradeManager.OnL1Block(ctx, blockHeader, blockData)
if err != nil {
e.logger.Error("Failed to process network upgrades", "error", err)
return nil, e.rejectBlockErr(ctx, fmt.Errorf("could not process network upgrades. Cause: %w", err))
}

err = e.storage.UpdateProcessed(ctx, blockHeader.Hash())
if err != nil {
return nil, e.rejectBlockErr(ctx, fmt.Errorf("could not submit L1 block. Cause: %w", err))
Expand All @@ -220,12 +227,6 @@ func (e *enclaveAdminService) SubmitL1Block(ctx context.Context, blockData *comm
// doing this after the network secret msgs to make sure we have stored the attestation before promotion.
e.processSequencerPromotions(blockData)

// Process network upgrade events when they reach finality
err = e.upgradeManager.OnL1Block(ctx, blockHeader, blockData)
if err != nil {
return nil, e.rejectBlockErr(ctx, fmt.Errorf("could not process network upgrades. Cause: %w", err))
}

return bsr, nil
}

Expand Down
Loading