Skip to content

Commit

Permalink
vms/platformvm: Add TestBuildBlockForceAdvanceTime test (#2472)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephen Buttolph <[email protected]>
  • Loading branch information
dhrubabasu and StephenButtolph authored Dec 12, 2023
1 parent dc472ec commit 7963115
Showing 1 changed file with 54 additions and 185 deletions.
239 changes: 54 additions & 185 deletions vms/platformvm/block/builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/ava-labs/avalanchego/vms/platformvm/reward"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
"github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool"

blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor"
txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor"
Expand Down Expand Up @@ -235,6 +234,60 @@ func TestBuildBlockAdvanceTime(t *testing.T) {
require.Equal(nextTime.Unix(), standardBlk.Timestamp().Unix())
}

func TestBuildBlockForceAdvanceTime(t *testing.T) {
require := require.New(t)

env := newEnvironment(t)
env.ctx.Lock.Lock()
defer func() {
require.NoError(shutdownEnvironment(env))
env.ctx.Lock.Unlock()
}()

// Create a valid transaction
tx, err := env.txBuilder.NewCreateChainTx(
testSubnet1.ID(),
nil,
constants.AVMID,
nil,
"chain name",
[]*secp256k1.PrivateKey{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
ids.ShortEmpty,
)
require.NoError(err)
txID := tx.ID()

// Issue the transaction
require.NoError(env.network.IssueTx(context.Background(), tx))
require.True(env.mempool.Has(txID))

var (
now = env.backend.Clk.Time()
nextTime = now.Add(2 * txexecutor.SyncBound)
)

// Add a staker to [env.state]
env.state.PutCurrentValidator(&state.Staker{
NextTime: nextTime,
Priority: txs.PrimaryNetworkValidatorCurrentPriority,
})

// Advance wall clock to [nextTime] + [txexecutor.SyncBound]
env.backend.Clk.Set(nextTime.Add(txexecutor.SyncBound))

// [BuildBlock] should build a block advancing the time to [nextTime],
// not the current wall clock.
blkIntf, err := env.Builder.BuildBlock(context.Background())
require.NoError(err)

require.IsType(&blockexecutor.Block{}, blkIntf)
blk := blkIntf.(*blockexecutor.Block)
require.Equal([]*txs.Tx{tx}, blk.Txs())
require.IsType(&block.BanffStandardBlock{}, blk.Block)
standardBlk := blk.Block.(*block.BanffStandardBlock)
require.Equal(nextTime.Unix(), standardBlk.Timestamp().Unix())
}

func TestPreviouslyDroppedTxsCanBeReAddedToMempool(t *testing.T) {
require := require.New(t)

Expand Down Expand Up @@ -482,187 +535,3 @@ func TestGetNextStakerToReward(t *testing.T) {
})
}
}

func TestBuildBlock(t *testing.T) {
env := newEnvironment(t)
env.ctx.Lock.Lock()
defer func() {
require.NoError(t, shutdownEnvironment(env))
env.ctx.Lock.Unlock()
}()

var (
now = env.backend.Clk.Time()
parentID = ids.GenerateTestID()
height = uint64(1337)
parentTimestamp = now.Add(-2 * time.Second)

defaultValidatorStake = 100 * units.MilliAvax
validatorStartTime = now.Add(2 * txexecutor.SyncBound)
validatorEndTime = validatorStartTime.Add(360 * 24 * time.Hour)
)

tx, err := env.txBuilder.NewAddValidatorTx(
defaultValidatorStake,
uint64(validatorStartTime.Unix()),
uint64(validatorEndTime.Unix()),
ids.GenerateTestNodeID(),
preFundedKeys[0].PublicKey().Address(),
reward.PercentDenominator,
[]*secp256k1.PrivateKey{preFundedKeys[0]},
preFundedKeys[0].PublicKey().Address(),
)
require.NoError(t, err)

type test struct {
name string
builderF func(*gomock.Controller) *builder
timestamp time.Time
forceAdvanceTime bool
parentStateF func(*gomock.Controller) state.Chain
expectedBlkF func(*require.Assertions) block.Block
expectedErr error
}

tests := []test{
{
name: "has a staker tx no force",
builderF: func(ctrl *gomock.Controller) *builder {
mempool := mempool.NewMockMempool(ctrl)

// There is a tx.
mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{})

gomock.InOrder(
mempool.EXPECT().Peek().Return(tx, true),
mempool.EXPECT().Remove([]*txs.Tx{tx}),
// Second loop iteration
mempool.EXPECT().Peek().Return(nil, false),
)

clk := &mockable.Clock{}
clk.Set(now)
return &builder{
Mempool: mempool,
txExecutorBackend: &txexecutor.Backend{
Clk: clk,
},
}
},
timestamp: parentTimestamp,
forceAdvanceTime: false,
parentStateF: func(ctrl *gomock.Controller) state.Chain {
s := state.NewMockChain(ctrl)

// Handle calls in [getNextStakerToReward]
// and [GetNextStakerChangeTime].
// Next validator change time is in the future.
currentStakerIter := state.NewMockStakerIterator(ctrl)
gomock.InOrder(
// expect calls from [getNextStakerToReward]
currentStakerIter.EXPECT().Next().Return(true),
currentStakerIter.EXPECT().Value().Return(&state.Staker{
NextTime: now.Add(time.Second),
Priority: txs.PrimaryNetworkDelegatorCurrentPriority,
}),
currentStakerIter.EXPECT().Release(),
)

s.EXPECT().GetCurrentStakerIterator().Return(currentStakerIter, nil).Times(1)
return s
},
expectedBlkF: func(require *require.Assertions) block.Block {
expectedBlk, err := block.NewBanffStandardBlock(
parentTimestamp,
parentID,
height,
[]*txs.Tx{tx},
)
require.NoError(err)
return expectedBlk
},
expectedErr: nil,
},
{
name: "has a staker tx with force",
builderF: func(ctrl *gomock.Controller) *builder {
mempool := mempool.NewMockMempool(ctrl)

// There are no decision txs
// There is a staker tx.
mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{})

gomock.InOrder(
mempool.EXPECT().Peek().Return(tx, true),
mempool.EXPECT().Remove([]*txs.Tx{tx}),
// Second loop iteration
mempool.EXPECT().Peek().Return(nil, false),
)

clk := &mockable.Clock{}
clk.Set(now)
return &builder{
Mempool: mempool,
txExecutorBackend: &txexecutor.Backend{
Clk: clk,
},
}
},
timestamp: parentTimestamp,
forceAdvanceTime: true,
parentStateF: func(ctrl *gomock.Controller) state.Chain {
s := state.NewMockChain(ctrl)

// Handle calls in [getNextStakerToReward]
// and [GetNextStakerChangeTime].
// Next validator change time is in the future.
currentStakerIter := state.NewMockStakerIterator(ctrl)
gomock.InOrder(
// expect calls from [getNextStakerToReward]
currentStakerIter.EXPECT().Next().Return(true),
currentStakerIter.EXPECT().Value().Return(&state.Staker{
NextTime: now.Add(time.Second),
Priority: txs.PrimaryNetworkDelegatorCurrentPriority,
}),
currentStakerIter.EXPECT().Release(),
)

s.EXPECT().GetCurrentStakerIterator().Return(currentStakerIter, nil).Times(1)
return s
},
expectedBlkF: func(require *require.Assertions) block.Block {
expectedBlk, err := block.NewBanffStandardBlock(
parentTimestamp,
parentID,
height,
[]*txs.Tx{tx},
)
require.NoError(err)
return expectedBlk
},
expectedErr: nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
ctrl := gomock.NewController(t)

gotBlk, err := buildBlock(
tt.builderF(ctrl),
parentID,
height,
tt.timestamp,
tt.forceAdvanceTime,
tt.parentStateF(ctrl),
)
if tt.expectedErr != nil {
require.ErrorIs(err, tt.expectedErr)
return
}
require.NoError(err)
require.Equal(tt.expectedBlkF(require), gotBlk)
})
}
}

0 comments on commit 7963115

Please sign in to comment.