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

vms/platformvm: Remove double block building logic #2380

Merged
merged 41 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b237933
`vms/platformvm`: Move `toEngine` channel to mempool
dhrubabasu Nov 17, 2023
cb81c85
nit
dhrubabasu Nov 17, 2023
03efd7e
short-circuit
dhrubabasu Nov 17, 2023
7ba8155
Merge branch 'dev' into move-engine-to-mempool
dhrubabasu Nov 17, 2023
df70afb
Merge branch 'dev' into move-engine-to-mempool
dhrubabasu Nov 17, 2023
86a559b
merge
dhrubabasu Nov 22, 2023
1a2431f
Merge branch 'dev' into move-engine-to-mempool
dhrubabasu Nov 25, 2023
a55ce38
Merge branch 'dev' into move-engine-to-mempool
dhrubabasu Nov 27, 2023
8c794eb
Merge branch 'dev' into move-engine-to-mempool
dhrubabasu Nov 27, 2023
f3f2fbb
`vms/platformvm`: Remove double block building logic
dhrubabasu Nov 28, 2023
776db3e
nits
dhrubabasu Nov 28, 2023
eeb97d9
nits
dhrubabasu Nov 28, 2023
5624df8
merged
dhrubabasu Nov 28, 2023
efbb751
pr review
dhrubabasu Nov 28, 2023
903d83b
nit
dhrubabasu Nov 28, 2023
cd669b2
nit
dhrubabasu Nov 28, 2023
a25ef67
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Nov 28, 2023
1d30f2b
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Nov 29, 2023
58f08ee
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Nov 29, 2023
ff0f319
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Nov 30, 2023
df125d5
pr review
dhrubabasu Nov 30, 2023
06b1bdc
cleanup
dhrubabasu Nov 30, 2023
240867b
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Dec 2, 2023
980bd4d
wip
dhrubabasu Dec 3, 2023
cbb3868
nit
dhrubabasu Dec 3, 2023
9cd31a3
nit
dhrubabasu Dec 3, 2023
2266e7c
nit
dhrubabasu Dec 3, 2023
645b989
merged
dhrubabasu Dec 4, 2023
16160b7
reduce diff
dhrubabasu Dec 4, 2023
5b70127
nits
dhrubabasu Dec 4, 2023
c1cff7a
wip
dhrubabasu Dec 4, 2023
5520c3e
wip
dhrubabasu Dec 4, 2023
8e19e4e
wip
dhrubabasu Dec 4, 2023
6361267
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Dec 4, 2023
6970836
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Dec 6, 2023
75de1aa
reduce diff
dhrubabasu Dec 6, 2023
a3b7670
remove logs;
dhrubabasu Dec 6, 2023
1a94ee0
Remove usage of timer.Timer in block building (#2447)
StephenButtolph Dec 7, 2023
58594db
Update vms/platformvm/block/builder/builder.go
StephenButtolph Dec 7, 2023
7114174
improve handling around closure
StephenButtolph Dec 7, 2023
c3dee45
Merge branch 'dev' into stop-building-block-twice
dhrubabasu Dec 8, 2023
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
101 changes: 38 additions & 63 deletions vms/platformvm/block/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,11 @@ var (
type Builder interface {
mempool.Mempool

// ResetBlockTimer schedules a timer to notify the consensus engine once
// there is a block ready to be built. If a block is ready to be built when
// this function is called, the engine will be notified directly.
// ResetBlockTimer schedules a timer to notify the consensus engine once a
// block needs to be built to process a staker change.
ResetBlockTimer()

// BuildBlock is called on timer clock to attempt to create
// next block
// BuildBlock can be called to attempt to create a new block
BuildBlock(context.Context) (snowman.Block, error)

// Shutdown cleanly shuts Builder down
Expand All @@ -61,10 +59,11 @@ type builder struct {
txExecutorBackend *txexecutor.Backend
blkManager blockexecutor.Manager

// This timer goes off when it is time for the next validator to add/leave
// the validator set. When it goes off ResetTimer() is called, potentially
// triggering creation of a new block.
timer *timer.Timer
// This timer goes off when it is time for the next staker to add/leave
// the staking set. When it goes off, [maybeAdvanceTime()] is called,
// potentially triggering creation of a new block.
timer *timer.Timer
nextStakerChangeTime time.Time
}

func New(
Expand All @@ -80,7 +79,7 @@ func New(
blkManager: blkManager,
}

builder.timer = timer.NewTimer(builder.setNextBuildBlockTime)
builder.timer = timer.NewTimer(builder.maybeAdvanceTime)

go txExecutorBackend.Ctx.Log.RecoverAndPanic(builder.timer.Dispatch)
return builder
Expand All @@ -93,27 +92,12 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) {
b.Mempool.DisableAdding()
defer func() {
b.Mempool.EnableAdding()
b.ResetBlockTimer()
b.Mempool.RequestBuildBlock(false /*=emptyBlockPermitted*/)
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. The timer previously fired to advance the chain time
  2. The next staker change time is to move a staker from pending to current
  3. There is an invalid tx in the mempool

I think we can end up building an invalid block and not scheduling to build another block to advance the timestamp.

Copy link
Contributor

Choose a reason for hiding this comment

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

Addressed in #2447

}()

ctx := b.txExecutorBackend.Ctx
ctx.Log.Debug("starting to attempt to build a block")

statelessBlk, err := b.buildBlock()
if err != nil {
return nil, err
}

// Remove selected txs from mempool now that we are returning the block to
// the consensus engine.
txs := statelessBlk.Txs()
b.Mempool.Remove(txs)
return b.blkManager.NewBlock(statelessBlk), nil
}

// Returns the block we want to build and issue.
// Only modifies state to remove expired proposal txs.
func (b *builder) buildBlock() (block.Block, error) {
// Get the block to build on top of and retrieve the new block's context.
preferredID := b.blkManager.Preferred()
preferred, err := b.blkManager.GetBlock(preferredID)
Expand All @@ -126,7 +110,8 @@ func (b *builder) buildBlock() (block.Block, error) {
return nil, fmt.Errorf("%w: %s", state.ErrMissingParentState, preferredID)
}

timestamp := b.txExecutorBackend.Clk.Time()
now := b.txExecutorBackend.Clk.Time()
timestamp := now
if parentTime := preferred.Timestamp(); parentTime.After(timestamp) {
timestamp = parentTime
}
Expand All @@ -137,6 +122,16 @@ func (b *builder) buildBlock() (block.Block, error) {
return nil, fmt.Errorf("could not calculate next staker change time: %w", err)
}

waitTime := nextStakerChangeTime.Sub(now)
ctx.Log.Debug("setting next scheduled event",
zap.Time("nextEventTime", nextStakerChangeTime),
zap.Duration("timeUntil", waitTime),
)

// Wake up when it's time to add/remove the next validator
b.nextStakerChangeTime = nextStakerChangeTime
b.timer.SetTimeoutIn(waitTime)

// timeWasCapped means that [timestamp] was reduced to
// [nextStakerChangeTime]. It is used as a flag for [buildApricotBlock] to
// be willing to issue an advanceTimeTx. It is also used as a flag for
Expand All @@ -148,14 +143,23 @@ func (b *builder) buildBlock() (block.Block, error) {
}
// [timestamp] = min(max(now, parentTime), nextStakerChangeTime)

return buildBlock(
statelessBlk, err := buildBlock(
b,
preferredID,
nextHeight,
timestamp,
timeWasCapped,
preferredState,
)
if err != nil {
return nil, err
}

// Remove selected txs from mempool now that we are returning the block to
// the consensus engine.
txs := statelessBlk.Txs()
b.Mempool.Remove(txs)
return b.blkManager.NewBlock(statelessBlk), nil
}

func (b *builder) Shutdown() {
Expand All @@ -173,7 +177,7 @@ func (b *builder) ResetBlockTimer() {
b.timer.SetTimeoutIn(0)
}

func (b *builder) setNextBuildBlockTime() {
func (b *builder) maybeAdvanceTime() {
StephenButtolph marked this conversation as resolved.
Show resolved Hide resolved
StephenButtolph marked this conversation as resolved.
Show resolved Hide resolved
ctx := b.txExecutorBackend.Ctx

// Grabbing the lock here enforces that this function is not called mid-way
Expand All @@ -188,43 +192,14 @@ func (b *builder) setNextBuildBlockTime() {
return
}

if _, err := b.buildBlock(); err == nil {
// We can build a block now
b.Mempool.RequestBuildBlock(true /*=emptyBlockPermitted*/)
return
}

// Wake up when it's time to add/remove the next validator/delegator
preferredID := b.blkManager.Preferred()
preferredState, ok := b.blkManager.GetState(preferredID)
if !ok {
// The preferred block should always be a decision block
ctx.Log.Error("couldn't get preferred block state",
zap.Stringer("preferredID", preferredID),
zap.Stringer("lastAcceptedID", b.blkManager.LastAccepted()),
)
return
}

nextStakerChangeTime, err := txexecutor.GetNextStakerChangeTime(preferredState)
if err != nil {
ctx.Log.Error("couldn't get next staker change time",
zap.Stringer("preferredID", preferredID),
zap.Stringer("lastAcceptedID", b.blkManager.LastAccepted()),
zap.Error(err),
)
now := b.txExecutorBackend.Clk.Time()
if b.nextStakerChangeTime.After(now) {
// [nextStakerChangeTime] is in the future, no need to advance time.
return
dhrubabasu marked this conversation as resolved.
Show resolved Hide resolved
}

now := b.txExecutorBackend.Clk.Time()
waitTime := nextStakerChangeTime.Sub(now)
ctx.Log.Debug("setting next scheduled event",
zap.Time("nextEventTime", nextStakerChangeTime),
zap.Duration("timeUntil", waitTime),
)

// Wake up when it's time to add/remove the next validator
b.timer.SetTimeoutIn(waitTime)
// Block needs to be issued to advance time.
b.Mempool.RequestBuildBlock(true /*=emptyBlockPermitted*/)
}

// [timestamp] is min(max(now, parent timestamp), next staker change time)
Expand Down
2 changes: 1 addition & 1 deletion vms/platformvm/block/executor/rejector.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (r *rejector) rejectBlock(b block.Block, blockType string) error {
}
}

r.Mempool.RequestBuildBlock(false)
r.Mempool.RequestBuildBlock(false /*=emptyBlockPermitted*/)

return nil
}
2 changes: 1 addition & 1 deletion vms/platformvm/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (n *network) issueTx(tx *txs.Tx) error {
return err
}

n.mempool.RequestBuildBlock(false)
n.mempool.RequestBuildBlock(false /*=emptyBlockPermitted*/)

return nil
}
Expand Down
Loading