2021-05-19 00:01:30 +00:00
|
|
|
package simulation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2021-06-12 01:39:15 +00:00
|
|
|
"github.com/filecoin-project/lotus/cmd/lotus-sim/simulation/blockbuilder"
|
2021-05-19 00:01:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Step steps the simulation forward one step. This may move forward by more than one epoch.
|
|
|
|
func (sim *Simulation) Step(ctx context.Context) (*types.TipSet, error) {
|
2021-06-12 01:39:15 +00:00
|
|
|
log.Infow("step", "epoch", sim.head.Height()+1)
|
|
|
|
messages, err := sim.popNextMessages(ctx)
|
2021-05-19 00:01:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("failed to select messages for block: %w", err)
|
|
|
|
}
|
2021-06-12 01:39:15 +00:00
|
|
|
head, err := sim.makeTipSet(ctx, messages)
|
2021-05-19 00:01:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("failed to make tipset: %w", err)
|
|
|
|
}
|
2021-06-12 01:39:15 +00:00
|
|
|
if err := sim.SetHead(head); err != nil {
|
2021-05-19 00:01:30 +00:00
|
|
|
return nil, xerrors.Errorf("failed to update head: %w", err)
|
|
|
|
}
|
|
|
|
return head, nil
|
|
|
|
}
|
|
|
|
|
2021-06-08 00:45:53 +00:00
|
|
|
// popNextMessages generates/picks a set of messages to be included in the next block.
|
|
|
|
//
|
|
|
|
// - This function is destructive and should only be called once per epoch.
|
|
|
|
// - This function does not store anything in the repo.
|
|
|
|
// - This function handles all gas estimation. The returned messages should all fit in a single
|
|
|
|
// block.
|
2021-06-12 01:39:15 +00:00
|
|
|
func (sim *Simulation) popNextMessages(ctx context.Context) ([]*types.Message, error) {
|
|
|
|
parentTs := sim.head
|
2021-06-08 00:45:53 +00:00
|
|
|
|
|
|
|
// First we make sure we don't have an upgrade at this epoch. If we do, we return no
|
|
|
|
// messages so we can just create an empty block at that epoch.
|
|
|
|
//
|
|
|
|
// This isn't what the network does, but it makes things easier. Otherwise, we'd need to run
|
|
|
|
// migrations before this epoch and I'd rather not deal with that.
|
2021-05-19 00:01:30 +00:00
|
|
|
nextHeight := parentTs.Height() + 1
|
2021-06-12 01:39:15 +00:00
|
|
|
prevVer := sim.StateManager.GetNtwkVersion(ctx, nextHeight-1)
|
|
|
|
nextVer := sim.StateManager.GetNtwkVersion(ctx, nextHeight)
|
2021-05-19 00:01:30 +00:00
|
|
|
if nextVer != prevVer {
|
|
|
|
log.Warnw("packing no messages for version upgrade block",
|
|
|
|
"old", prevVer,
|
|
|
|
"new", nextVer,
|
|
|
|
"epoch", nextHeight,
|
|
|
|
)
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2021-06-12 01:39:15 +00:00
|
|
|
bb, err := blockbuilder.NewBlockBuilder(
|
|
|
|
ctx, log.With("simulation", sim.name),
|
|
|
|
sim.StateManager, parentTs,
|
|
|
|
)
|
2021-06-08 00:45:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-06-12 01:39:15 +00:00
|
|
|
for _, stage := range sim.stages {
|
2021-06-08 04:36:40 +00:00
|
|
|
// We're intentionally ignoring the "full" signal so we can try to pack a few more
|
|
|
|
// messages.
|
2021-06-12 01:39:15 +00:00
|
|
|
if err := stage.PackMessages(ctx, bb); err != nil && !blockbuilder.IsOutOfGas(err) {
|
|
|
|
return nil, xerrors.Errorf("when packing messages with %s: %w", stage.Name(), err)
|
2021-05-19 00:01:30 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-12 01:39:15 +00:00
|
|
|
return bb.Messages(), nil
|
2021-05-19 00:01:30 +00:00
|
|
|
}
|