2021-06-08 00:45:53 +00:00
|
|
|
package simulation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/binary"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/lotus/build"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const beaconPrefix = "mockbeacon:"
|
|
|
|
|
2021-06-08 00:52:57 +00:00
|
|
|
// nextBeaconEntries returns a fake beacon entries for the next block.
|
2021-06-08 00:45:53 +00:00
|
|
|
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[:],
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2021-06-08 00:52:57 +00:00
|
|
|
// nextTicket returns a fake ticket for the next block.
|
2021-06-08 00:45:53 +00:00
|
|
|
func (sim *Simulation) nextTicket() *types.Ticket {
|
|
|
|
newProof := sha256.Sum256(sim.head.MinTicket().VRFProof)
|
|
|
|
return &types.Ticket{
|
|
|
|
VRFProof: newProof[:],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-08 00:52:57 +00:00
|
|
|
// makeTipSet generates and executes the next tipset from the given messages. This method:
|
|
|
|
//
|
|
|
|
// 1. Stores the given messages in the Chainstore.
|
2021-06-08 21:09:47 +00:00
|
|
|
// 2. Creates and persists a single block mined by the same miner as the parent.
|
2021-06-08 00:52:57 +00:00
|
|
|
// 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).
|
2021-06-08 00:45:53 +00:00
|
|
|
func (sim *Simulation) makeTipSet(ctx context.Context, messages []*types.Message) (*types.TipSet, error) {
|
|
|
|
parentTs := sim.head
|
2021-06-08 18:22:11 +00:00
|
|
|
parentState, parentRec, err := sim.StateManager.TipSetState(ctx, parentTs)
|
2021-06-08 00:45:53 +00:00
|
|
|
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: baseFee,
|
|
|
|
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()
|
2021-06-08 18:22:11 +00:00
|
|
|
_, _, err = sim.StateManager.TipSetState(ctx, newTipSet)
|
2021-06-08 00:45:53 +00:00
|
|
|
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
|
|
|
|
}
|