52261fb814
While the previous version "worked", this version nicely separates out the state for the separate stages. Hopefully, we'll be able to use this to build different pipelines with different configs.
94 lines
3.0 KiB
Go
94 lines
3.0 KiB
Go
package simulation
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"time"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
"github.com/filecoin-project/lotus/build"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
)
|
|
|
|
const beaconPrefix = "mockbeacon:"
|
|
|
|
// nextBeaconEntries returns a fake beacon entries for the next block.
|
|
func (sim *Simulation) nextBeaconEntries() []types.BeaconEntry {
|
|
parentBeacons := sim.head.Blocks()[0].BeaconEntries
|
|
lastBeacon := parentBeacons[len(parentBeacons)-1]
|
|
beaconRound := lastBeacon.Round + 1
|
|
|
|
buf := make([]byte, len(beaconPrefix)+8)
|
|
copy(buf, beaconPrefix)
|
|
binary.BigEndian.PutUint64(buf[len(beaconPrefix):], beaconRound)
|
|
beaconRand := sha256.Sum256(buf)
|
|
return []types.BeaconEntry{{
|
|
Round: beaconRound,
|
|
Data: beaconRand[:],
|
|
}}
|
|
}
|
|
|
|
// nextTicket returns a fake ticket for the next block.
|
|
func (sim *Simulation) nextTicket() *types.Ticket {
|
|
newProof := sha256.Sum256(sim.head.MinTicket().VRFProof)
|
|
return &types.Ticket{
|
|
VRFProof: newProof[:],
|
|
}
|
|
}
|
|
|
|
// makeTipSet generates and executes the next tipset from the given messages. This method:
|
|
//
|
|
// 1. Stores the given messages in the Chainstore.
|
|
// 2. Creates and persists a single block mined by the same miner as the parent.
|
|
// 3. Creates a tipset from this block and executes it.
|
|
// 4. Returns the resulting tipset.
|
|
//
|
|
// This method does _not_ mutate local state (although it does add blocks to the datastore).
|
|
func (sim *Simulation) makeTipSet(ctx context.Context, messages []*types.Message) (*types.TipSet, error) {
|
|
parentTs := sim.head
|
|
parentState, parentRec, err := sim.StateManager.TipSetState(ctx, parentTs)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to compute parent tipset: %w", err)
|
|
}
|
|
msgsCid, err := sim.storeMessages(ctx, messages)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to store block messages: %w", err)
|
|
}
|
|
|
|
uts := parentTs.MinTimestamp() + build.BlockDelaySecs
|
|
|
|
blks := []*types.BlockHeader{{
|
|
Miner: parentTs.MinTicketBlock().Miner, // keep reusing the same miner.
|
|
Ticket: sim.nextTicket(),
|
|
BeaconEntries: sim.nextBeaconEntries(),
|
|
Parents: parentTs.Cids(),
|
|
Height: parentTs.Height() + 1,
|
|
ParentStateRoot: parentState,
|
|
ParentMessageReceipts: parentRec,
|
|
Messages: msgsCid,
|
|
ParentBaseFee: abi.NewTokenAmount(0),
|
|
Timestamp: uts,
|
|
ElectionProof: &types.ElectionProof{WinCount: 1},
|
|
}}
|
|
err = sim.Chainstore.PersistBlockHeaders(blks...)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to persist block headers: %w", err)
|
|
}
|
|
newTipSet, err := types.NewTipSet(blks)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to create new tipset: %w", err)
|
|
}
|
|
now := time.Now()
|
|
_, _, err = sim.StateManager.TipSetState(ctx, newTipSet)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to compute new tipset: %w", err)
|
|
}
|
|
duration := time.Since(now)
|
|
log.Infow("computed tipset", "duration", duration, "height", newTipSet.Height())
|
|
|
|
return newTipSet, nil
|
|
}
|