Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
f7bca02
proposervm epoch poc
cam-schultz Feb 25, 2025
46f9d06
verify p-chain epoch height
cam-schultz Mar 3, 2025
5e3941a
continuous epoch numbering scheme
cam-schultz May 6, 2025
d6873df
first epoch block sets start time
cam-schultz May 12, 2025
4e8239d
Merge branch 'master' into proposervm-epochs
cam-schultz May 12, 2025
5ec65ff
handle initial epoch
cam-schultz May 12, 2025
a17f763
sealing block's timestamp is next epoch's start time
cam-schultz May 13, 2025
8bcd2b7
Merge branch 'master' into proposervm-epochs
cam-schultz Jun 11, 2025
6e37eda
expose proposervm API
cam-schultz Jun 23, 2025
e250b85
lint
cam-schultz Jun 23, 2025
463b936
Merge branch 'master' into proposervm-api
cam-schultz Jun 23, 2025
79613f1
lock vm state
cam-schultz Jun 24, 2025
fa1802a
Merge branch 'proposervm-api' of github.com:ava-labs/avalanchego into…
cam-schultz Jun 24, 2025
0e093df
rename json tag
cam-schultz Jun 27, 2025
44dd186
Merge branch 'master' into proposervm-epochs
cam-schultz Jun 30, 2025
43e04c8
Merge branch 'master' into proposervm-api
cam-schultz Jul 3, 2025
0875cb7
proposervm api client
cam-schultz Jul 3, 2025
7ea6ee9
client fixes
cam-schultz Jul 3, 2025
3ecd42f
Merge branch 'proposervm-api' of github.com:ava-labs/avalanchego into…
cam-schultz Jul 3, 2025
dc586f4
specify epoch as duration
cam-schultz Jul 7, 2025
bd2da2c
update mocks
cam-schultz Jul 7, 2025
d1b1e5b
lint
cam-schultz Jul 7, 2025
d7bb8bf
add unit tests
ylg-avalabs Aug 7, 2025
1057ba5
Merge remote-tracking branch 'origin' into proposervm-api
ylg-avalabs Aug 7, 2025
bb9b56d
fix lints
ylg-avalabs Aug 8, 2025
07fdeb9
lints
ylg-avalabs Aug 8, 2025
cc79175
Merge remote-tracking branch 'origin/proposervm-epochs' into proposer…
ylg-avalabs Aug 12, 2025
19edd4d
return signedBlock
ylg-avalabs Aug 13, 2025
a560a1d
Merge remote-tracking branch 'origin' into proposervm-epochs
ylg-avalabs Aug 13, 2025
8c96927
fix lint
ylg-avalabs Aug 13, 2025
908ca7a
Merge branch 'proposervm-epochs' into proposervm-api
ylg-avalabs Aug 13, 2025
28c334b
Merge branch 'master' into proposervm-api
geoff-vball Aug 18, 2025
0fda99f
e2e skeleton
cam-schultz Jun 30, 2025
8984a98
expose proposervm API
cam-schultz Jun 23, 2025
9850881
get epoch method
cam-schultz Jul 3, 2025
37cf23b
observe advancing epoch
cam-schultz Jul 3, 2025
f0a903d
epoch e2e test
cam-schultz Jul 7, 2025
ce3ea8b
cleanup
cam-schultz Jul 7, 2025
a2744e8
lint
geoff-vball Aug 18, 2025
66708ff
Merge branch 'master' into proposervm-api
geoff-vball Aug 18, 2025
642b793
Merge branch 'proposervm-epochs' into proposervm-api
geoff-vball Aug 18, 2025
29ff0a8
Merge with epoching e2e, some fixes, WIP
geoff-vball Aug 20, 2025
09bedab
Merge branch 'proposervm-api' of github.com:ava-labs/avalanche-go int…
geoff-vball Aug 20, 2025
1fa23e8
Merge branch 'master' into proposervm-api
geoff-vball Aug 20, 2025
8de0adc
Fix some unit tests
geoff-vball Aug 20, 2025
c2a2fee
Refactor epoch computation
geoff-vball Aug 20, 2025
ca7bcb5
Refactor epoch computation further
geoff-vball Aug 20, 2025
ca24a37
Fix unit test
geoff-vball Aug 20, 2025
7b5d92a
Fix test
geoff-vball Aug 21, 2025
814f019
Maybe fix test
geoff-vball Aug 21, 2025
429dc30
Fixes
geoff-vball Aug 21, 2025
e23bd2a
Merge branch 'master' into proposervm-api
geoff-vball Aug 21, 2025
fabc63c
Fixes
geoff-vball Aug 21, 2025
4058878
Fixes
geoff-vball Aug 21, 2025
f785e2c
Merge branch 'master' into proposervm-api
geoff-vball Aug 25, 2025
afd5741
Change check to be for epoch 0
geoff-vball Aug 25, 2025
8a6b745
Implement GetProposedHeight API
geoff-vball Aug 27, 2025
e279ae8
lint
geoff-vball Aug 27, 2025
c08c242
Merge branch 'master' into last-accepted-height-api
geoff-vball Aug 27, 2025
70e308b
Review feedback
geoff-vball Aug 27, 2025
65bc851
Merge branch 'last-accepted-height-api' into proposervm-api
geoff-vball Aug 28, 2025
fae179b
Change struct location
geoff-vball Aug 28, 2025
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
6 changes: 6 additions & 0 deletions api/common_args_responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ type GetHeightResponse struct {
Height avajson.Uint64 `json:"height"`
}

type GetEpochResponse struct {
Number avajson.Uint64 `json:"number"`
StartTime avajson.Uint64 `json:"startTime"`
PChainHeight avajson.Uint64 `json:"pChainHeight"`
}

// FormattedBlock defines a JSON formatted struct containing a block in Hex
// format
type FormattedBlock struct {
Expand Down
99 changes: 99 additions & 0 deletions tests/e2e/c/proposervm_epoch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package c

import (
"math/big"
"time"

"github.com/ava-labs/coreth/ethclient"
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core/types"
"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/require"
"go.uber.org/zap"

"github.com/ava-labs/avalanchego/tests/fixture/e2e"
"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/units"
"github.com/ava-labs/avalanchego/vms/proposervm"
)

var _ = e2e.DescribeCChain("[ProposerVM Epoch]", func() {
tc := e2e.NewTestContext()
require := require.New(tc)

const txAmount = 10 * units.Avax // Arbitrary amount to send and transfer

ginkgo.It("should advance the proposervm epoch according to the upgrade config epoch duration", func() {
// TODO: Skip this test if Granite is not activated

env := e2e.GetEnv(tc)
var (
senderKey = env.PreFundedKey
recipientKey = e2e.NewPrivateKey(tc)
)

// Select a random node URI to use for both the eth client and
// the wallet to avoid having to verify that all nodes are at
// the same height before initializing the wallet.
nodeURI := env.GetRandomNodeURI()
ethClient := e2e.NewEthClient(tc, nodeURI)

proposerClient := proposervm.NewClient(nodeURI.URI, "C")

tc.By("issuing C-Chain transactions to advance the epoch", func() {
initialEpoch, err := proposerClient.GetEpoch(tc.DefaultContext())
require.NoError(err)

time.Sleep(5 * time.Second)

issueTransaction(tc, ethClient, senderKey, recipientKey.EthAddress(), int64(txAmount))

epoch, err := proposerClient.GetEpoch(tc.DefaultContext())
require.NoError(err)
tc.Log().Debug(
"epoch",
zap.Uint64("Epoch Number:", epoch.Number),
zap.Int64("Epoch Start Time:", epoch.StartTime.Unix()),
zap.Uint64("P-Chain Height:", epoch.Height),
)

require.Greater(
epoch.Number,
initialEpoch.Number,
"expected epoch number to advance, but it did not",
)
})
})
})

func issueTransaction(
tc *e2e.GinkgoTestContext,
ethClient *ethclient.Client,
senderKey *secp256k1.PrivateKey,
recipientEthAddress common.Address,
txAmount int64,
) {
acceptedNonce, err := ethClient.AcceptedNonceAt(tc.DefaultContext(), senderKey.EthAddress())
require.NoError(tc, err)
gasPrice := e2e.SuggestGasPrice(tc, ethClient)
tx := types.NewTransaction(
acceptedNonce,
recipientEthAddress,
big.NewInt(txAmount),
e2e.DefaultGasLimit,
gasPrice,
nil,
)

cChainID, err := ethClient.ChainID(tc.DefaultContext())
require.NoError(tc, err)
signer := types.NewEIP155Signer(cChainID)
signedTx, err := types.SignTx(tx, signer, senderKey.ToECDSA())
require.NoError(tc, err)

receipt := e2e.SendEthTransaction(tc, ethClient, signedTx)
require.Equal(tc, types.ReceiptStatusSuccessful, receipt.Status)
}
2 changes: 2 additions & 0 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/base64"
"encoding/json"
"testing"
"time"

"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -50,6 +51,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
upgrades := upgrade.Default
if flagVars.ActivateGranite() {
upgrades.GraniteTime = upgrade.InitiallyActiveTime
upgrades.GraniteEpochDuration = 4 * time.Second
} else {
upgrades.GraniteTime = upgrade.UnscheduledActivationTime
}
Expand Down
6 changes: 3 additions & 3 deletions tests/fixture/tmpnet/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ func BootstrapNewNetwork(
}

if err := checkVMBinaries(log, network.Subnets, network.DefaultRuntimeConfig.Process); err != nil {
return err
return fmt.Errorf("failed to check VM binaries: %w", err)
}
if err := network.EnsureDefaultConfig(ctx, log); err != nil {
return err
return fmt.Errorf("failed to ensure default config: %w", err)
}
if err := network.Create(rootNetworkDir); err != nil {
return err
return fmt.Errorf("failed to create network: %w", err)
}
return network.Bootstrap(ctx, log)
}
Expand Down
34 changes: 18 additions & 16 deletions upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,30 @@ var (
EtnaTime: InitiallyActiveTime,
FortunaTime: InitiallyActiveTime,
GraniteTime: UnscheduledActivationTime,
GraniteEpochDuration: 30 * time.Second,
}

ErrInvalidUpgradeTimes = errors.New("invalid upgrade configuration")
)

type Config struct {
ApricotPhase1Time time.Time `json:"apricotPhase1Time"`
ApricotPhase2Time time.Time `json:"apricotPhase2Time"`
ApricotPhase3Time time.Time `json:"apricotPhase3Time"`
ApricotPhase4Time time.Time `json:"apricotPhase4Time"`
ApricotPhase4MinPChainHeight uint64 `json:"apricotPhase4MinPChainHeight"`
ApricotPhase5Time time.Time `json:"apricotPhase5Time"`
ApricotPhasePre6Time time.Time `json:"apricotPhasePre6Time"`
ApricotPhase6Time time.Time `json:"apricotPhase6Time"`
ApricotPhasePost6Time time.Time `json:"apricotPhasePost6Time"`
BanffTime time.Time `json:"banffTime"`
CortinaTime time.Time `json:"cortinaTime"`
CortinaXChainStopVertexID ids.ID `json:"cortinaXChainStopVertexID"`
DurangoTime time.Time `json:"durangoTime"`
EtnaTime time.Time `json:"etnaTime"`
FortunaTime time.Time `json:"fortunaTime"`
GraniteTime time.Time `json:"graniteTime"`
ApricotPhase1Time time.Time `json:"apricotPhase1Time"`
ApricotPhase2Time time.Time `json:"apricotPhase2Time"`
ApricotPhase3Time time.Time `json:"apricotPhase3Time"`
ApricotPhase4Time time.Time `json:"apricotPhase4Time"`
ApricotPhase4MinPChainHeight uint64 `json:"apricotPhase4MinPChainHeight"`
ApricotPhase5Time time.Time `json:"apricotPhase5Time"`
ApricotPhasePre6Time time.Time `json:"apricotPhasePre6Time"`
ApricotPhase6Time time.Time `json:"apricotPhase6Time"`
ApricotPhasePost6Time time.Time `json:"apricotPhasePost6Time"`
BanffTime time.Time `json:"banffTime"`
CortinaTime time.Time `json:"cortinaTime"`
CortinaXChainStopVertexID ids.ID `json:"cortinaXChainStopVertexID"`
DurangoTime time.Time `json:"durangoTime"`
EtnaTime time.Time `json:"etnaTime"`
FortunaTime time.Time `json:"fortunaTime"`
GraniteTime time.Time `json:"graniteTime"`
GraniteEpochDuration time.Duration `json:"graniteEpochDuration"`
}

func (c *Config) Validate() error {
Expand Down
37 changes: 26 additions & 11 deletions vms/proposervm/batched_vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ func TestCoreVMNotRemote(t *testing.T) {
var (
activationTime = time.Unix(0, 0)
durangoTime = activationTime
graniteTime = activationTime
)
_, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0)
_, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, graniteTime, 0)
defer func() {
require.NoError(proVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -70,8 +71,9 @@ func TestGetAncestorsPreForkOnly(t *testing.T) {
var (
activationTime = mockable.MaxTime
durangoTime = activationTime
graniteTime = activationTime
)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime, graniteTime)
defer func() {
require.NoError(proRemoteVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -193,8 +195,9 @@ func TestGetAncestorsPostForkOnly(t *testing.T) {
var (
activationTime = time.Unix(0, 0)
durangoTime = activationTime
graniteTime = activationTime
)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime, graniteTime)
defer func() {
require.NoError(proRemoteVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -222,7 +225,7 @@ func TestGetAncestorsPostForkOnly(t *testing.T) {
// prepare build of next block
require.NoError(builtBlk2.Verify(context.Background()))
require.NoError(proRemoteVM.SetPreference(context.Background(), builtBlk2.ID()))
require.NoError(waitForProposerWindow(proRemoteVM, builtBlk2, 0))
require.NoError(waitForProposerWindow(proRemoteVM, builtBlk2, builtBlk2.(*postForkBlock).PChainHeight()))

coreBlk3 := snowmantest.BuildChild(coreBlk2)
coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
Expand Down Expand Up @@ -327,10 +330,11 @@ func TestGetAncestorsAtSnomanPlusPlusFork(t *testing.T) {
postForkTime = currentTime.Add(15 * time.Minute)

durangoTime = forkTime
graniteTime = forkTime
)

// enable ProBlks in next future
coreVM, proRemoteVM := initTestRemoteProposerVM(t, forkTime, durangoTime)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, forkTime, durangoTime, graniteTime)
defer func() {
require.NoError(proRemoteVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -499,8 +503,9 @@ func TestBatchedParseBlockPreForkOnly(t *testing.T) {
var (
activationTime = mockable.MaxTime
durangoTime = activationTime
graniteTime = activationTime
)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime, graniteTime)
defer func() {
require.NoError(proRemoteVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -596,6 +601,11 @@ func TestBatchedParseBlockParallel(t *testing.T) {
parentID := ids.ID{1}
timestamp := time.Unix(123, 0)
pChainHeight := uint64(2)
pChainEpoch := blockbuilder.PChainEpoch{
Height: uint64(2),
Number: uint64(0),
StartTime: time.Unix(123, 0),
}
chainID := ids.GenerateTestID()

vm := VM{
Expand All @@ -616,10 +626,10 @@ func TestBatchedParseBlockParallel(t *testing.T) {

blockThatCantBeParsed := snowmantest.BuildChild(snowmantest.Genesis)

blocksWithUnparsable := makeParseableBlocks(t, parentID, timestamp, pChainHeight, cert, chainID, key)
blocksWithUnparsable := makeParseableBlocks(t, parentID, timestamp, pChainHeight, pChainEpoch, cert, chainID, key)
blocksWithUnparsable[50] = blockThatCantBeParsed.Bytes()

parsableBlocks := makeParseableBlocks(t, parentID, timestamp, pChainHeight, cert, chainID, key)
parsableBlocks := makeParseableBlocks(t, parentID, timestamp, pChainHeight, pChainEpoch, cert, chainID, key)

for _, testCase := range []struct {
name string
Expand Down Expand Up @@ -663,14 +673,15 @@ func TestBatchedParseBlockParallel(t *testing.T) {
}
}

func makeParseableBlocks(t *testing.T, parentID ids.ID, timestamp time.Time, pChainHeight uint64, cert *staking.Certificate, chainID ids.ID, key crypto.Signer) [][]byte {
func makeParseableBlocks(t *testing.T, parentID ids.ID, timestamp time.Time, pChainHeight uint64, pChainEpoch blockbuilder.PChainEpoch, cert *staking.Certificate, chainID ids.ID, key crypto.Signer) [][]byte {
makeSignedBlock := func(i int) []byte {
buff := binary.AppendVarint(nil, int64(i))

signedBlock, err := blockbuilder.Build(
parentID,
timestamp,
pChainHeight,
pChainEpoch,
cert,
buff,
chainID,
Expand All @@ -693,8 +704,9 @@ func TestBatchedParseBlockPostForkOnly(t *testing.T) {
var (
activationTime = time.Unix(0, 0)
durangoTime = activationTime
graniteTime = activationTime
)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, activationTime, durangoTime, graniteTime)
defer func() {
require.NoError(proRemoteVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -784,10 +796,11 @@ func TestBatchedParseBlockAtSnomanPlusPlusFork(t *testing.T) {
postForkTime = currentTime.Add(15 * time.Minute)

durangoTime = forkTime
graniteTime = forkTime
)

// enable ProBlks in next future
coreVM, proRemoteVM := initTestRemoteProposerVM(t, forkTime, durangoTime)
coreVM, proRemoteVM := initTestRemoteProposerVM(t, forkTime, durangoTime, graniteTime)
defer func() {
require.NoError(proRemoteVM.Shutdown(context.Background()))
}()
Expand Down Expand Up @@ -917,6 +930,7 @@ func initTestRemoteProposerVM(
t *testing.T,
activationTime,
durangoTime time.Time,
graniteTime time.Time,
) (
TestRemoteProposerVM,
*VM,
Expand Down Expand Up @@ -970,6 +984,7 @@ func initTestRemoteProposerVM(
ApricotPhase4Time: activationTime,
ApricotPhase4MinPChainHeight: 0,
DurangoTime: durangoTime,
GraniteTime: graniteTime,
},
MinBlkDelay: DefaultMinBlockDelay,
NumHistoricalBlocks: DefaultNumHistoricalBlocks,
Expand Down
Loading
Loading