chain: Cleanup consensus logic
This commit is contained in:
parent
5831a6ba4a
commit
95b128b7bc
@ -177,6 +177,11 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr
|
|||||||
// TODO handle genesis better
|
// TODO handle genesis better
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if curr.Round != prev.Round+1 {
|
||||||
|
return xerrors.Errorf("invalid beacon entry: cur (%d) != prev (%d) + 1", curr.Round, prev.Round)
|
||||||
|
}
|
||||||
|
|
||||||
if be := db.getCachedValue(curr.Round); be != nil {
|
if be := db.getCachedValue(curr.Round); be != nil {
|
||||||
if !bytes.Equal(curr.Data, be.Data) {
|
if !bytes.Equal(curr.Data, be.Data) {
|
||||||
return xerrors.New("invalid beacon value, does not match cached good value")
|
return xerrors.New("invalid beacon value, does not match cached good value")
|
||||||
|
302
chain/consensus/filcns/compute_state.go
Normal file
302
chain/consensus/filcns/compute_state.go
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
package filcns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"go.opencensus.io/stats"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
|
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||||
|
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
||||||
|
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
|
||||||
|
exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported"
|
||||||
|
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/cron"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// todo this is a hack, should fix the cli deps, and drop the map in stmgr
|
||||||
|
stmgr.MethodsMap = NewActorRegistry().Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewActorRegistry() *vm.ActorRegistry {
|
||||||
|
inv := vm.NewActorRegistry()
|
||||||
|
|
||||||
|
// TODO: define all these properties on the actors themselves, in specs-actors.
|
||||||
|
|
||||||
|
inv.Register(vm.ActorsVersionPredicate(actors.Version0), exported0.BuiltinActors()...)
|
||||||
|
inv.Register(vm.ActorsVersionPredicate(actors.Version2), exported2.BuiltinActors()...)
|
||||||
|
inv.Register(vm.ActorsVersionPredicate(actors.Version3), exported3.BuiltinActors()...)
|
||||||
|
inv.Register(vm.ActorsVersionPredicate(actors.Version4), exported4.BuiltinActors()...)
|
||||||
|
inv.Register(vm.ActorsVersionPredicate(actors.Version5), exported5.BuiltinActors()...)
|
||||||
|
|
||||||
|
return inv
|
||||||
|
}
|
||||||
|
|
||||||
|
type tipSetExecutor struct{}
|
||||||
|
|
||||||
|
func TipSetExecutor() *tipSetExecutor {
|
||||||
|
return &tipSetExecutor{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tipSetExecutor) NewActorRegistry() *vm.ActorRegistry {
|
||||||
|
return NewActorRegistry()
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilecoinBlockMessages struct {
|
||||||
|
store.BlockMessages
|
||||||
|
|
||||||
|
WinCount int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tipSetExecutor) ApplyBlocks(ctx context.Context, sm *stmgr.StateManager, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []FilecoinBlockMessages, epoch abi.ChainEpoch, r vm.Rand, em stmgr.ExecMonitor, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) {
|
||||||
|
done := metrics.Timer(ctx, metrics.VMApplyBlocksTotal)
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
partDone := metrics.Timer(ctx, metrics.VMApplyEarly)
|
||||||
|
defer func() {
|
||||||
|
partDone()
|
||||||
|
}()
|
||||||
|
|
||||||
|
makeVmWithBaseState := func(base cid.Cid) (*vm.VM, error) {
|
||||||
|
vmopt := &vm.VMOpts{
|
||||||
|
StateBase: base,
|
||||||
|
Epoch: epoch,
|
||||||
|
Rand: r,
|
||||||
|
Bstore: sm.ChainStore().StateBlockstore(),
|
||||||
|
Actors: NewActorRegistry(),
|
||||||
|
Syscalls: sm.Syscalls,
|
||||||
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
|
BaseFee: baseFee,
|
||||||
|
LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts),
|
||||||
|
}
|
||||||
|
|
||||||
|
return sm.VMConstructor()(ctx, vmopt)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmi, err := makeVmWithBaseState(pstate)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
runCron := func(epoch abi.ChainEpoch) error {
|
||||||
|
cronMsg := &types.Message{
|
||||||
|
To: cron.Address,
|
||||||
|
From: builtin.SystemActorAddr,
|
||||||
|
Nonce: uint64(epoch),
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
GasFeeCap: types.NewInt(0),
|
||||||
|
GasPremium: types.NewInt(0),
|
||||||
|
GasLimit: build.BlockGasLimit * 10000, // Make super sure this is never too little
|
||||||
|
Method: cron.Methods.EpochTick,
|
||||||
|
Params: nil,
|
||||||
|
}
|
||||||
|
ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if em != nil {
|
||||||
|
if err := em.MessageApplied(ctx, ts, cronMsg.Cid(), cronMsg, ret, true); err != nil {
|
||||||
|
return xerrors.Errorf("callback failed on cron message: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ret.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := parentEpoch; i < epoch; i++ {
|
||||||
|
if i > parentEpoch {
|
||||||
|
// run cron for null rounds if any
|
||||||
|
if err := runCron(i); err != nil {
|
||||||
|
return cid.Undef, cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pstate, err = vmi.Flush(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle state forks
|
||||||
|
// XXX: The state tree
|
||||||
|
newState, err := sm.HandleStateForks(ctx, pstate, i, em, ts)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pstate != newState {
|
||||||
|
vmi, err = makeVmWithBaseState(newState)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vmi.SetBlockHeight(i + 1)
|
||||||
|
pstate = newState
|
||||||
|
}
|
||||||
|
|
||||||
|
partDone()
|
||||||
|
partDone = metrics.Timer(ctx, metrics.VMApplyMessages)
|
||||||
|
|
||||||
|
var receipts []cbg.CBORMarshaler
|
||||||
|
processedMsgs := make(map[cid.Cid]struct{})
|
||||||
|
for _, b := range bms {
|
||||||
|
penalty := types.NewInt(0)
|
||||||
|
gasReward := big.Zero()
|
||||||
|
|
||||||
|
for _, cm := range append(b.BlsMessages, b.SecpkMessages...) {
|
||||||
|
m := cm.VMMessage()
|
||||||
|
if _, found := processedMsgs[m.Cid()]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, err := vmi.ApplyMessage(ctx, cm)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receipts = append(receipts, &r.MessageReceipt)
|
||||||
|
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
|
||||||
|
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
|
||||||
|
|
||||||
|
if em != nil {
|
||||||
|
if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil {
|
||||||
|
return cid.Undef, cid.Undef, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processedMsgs[m.Cid()] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
||||||
|
Miner: b.Miner,
|
||||||
|
Penalty: penalty,
|
||||||
|
GasReward: gasReward,
|
||||||
|
WinCount: b.WinCount,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rwMsg := &types.Message{
|
||||||
|
From: builtin.SystemActorAddr,
|
||||||
|
To: reward.Address,
|
||||||
|
Nonce: uint64(epoch),
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
GasFeeCap: types.NewInt(0),
|
||||||
|
GasPremium: types.NewInt(0),
|
||||||
|
GasLimit: 1 << 30,
|
||||||
|
Method: reward.Methods.AwardBlockReward,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
||||||
|
if actErr != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr)
|
||||||
|
}
|
||||||
|
if em != nil {
|
||||||
|
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on reward message: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.ExitCode != 0 {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partDone()
|
||||||
|
partDone = metrics.Timer(ctx, metrics.VMApplyCron)
|
||||||
|
|
||||||
|
if err := runCron(epoch); err != nil {
|
||||||
|
return cid.Cid{}, cid.Cid{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
partDone()
|
||||||
|
partDone = metrics.Timer(ctx, metrics.VMApplyFlush)
|
||||||
|
|
||||||
|
rectarr := blockadt.MakeEmptyArray(sm.ChainStore().ActorStore(ctx))
|
||||||
|
for i, receipt := range receipts {
|
||||||
|
if err := rectarr.Set(uint64(i), receipt); err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rectroot, err := rectarr.Root()
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := vmi.Flush(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("vm flush failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.Record(ctx, metrics.VMSends.M(int64(atomic.LoadUint64(&vm.StatSends))),
|
||||||
|
metrics.VMApplied.M(int64(atomic.LoadUint64(&vm.StatApplied))))
|
||||||
|
|
||||||
|
return st, rectroot, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tipSetExecutor) ExecuteTipSet(ctx context.Context, sm *stmgr.StateManager, ts *types.TipSet, em stmgr.ExecMonitor) (stateroot cid.Cid, rectsroot cid.Cid, err error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "computeTipSetState")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
blks := ts.Blocks()
|
||||||
|
|
||||||
|
for i := 0; i < len(blks); i++ {
|
||||||
|
for j := i + 1; j < len(blks); j++ {
|
||||||
|
if blks[i].Miner == blks[j].Miner {
|
||||||
|
return cid.Undef, cid.Undef,
|
||||||
|
xerrors.Errorf("duplicate miner in a tipset (%s %s)",
|
||||||
|
blks[i].Miner, blks[j].Miner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentEpoch abi.ChainEpoch
|
||||||
|
pstate := blks[0].ParentStateRoot
|
||||||
|
if blks[0].Height > 0 {
|
||||||
|
parent, err := sm.ChainStore().GetBlock(blks[0].Parents[0])
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("getting parent block: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentEpoch = parent.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
r := store.NewChainRand(sm.ChainStore(), ts.Cids())
|
||||||
|
|
||||||
|
blkmsgs, err := sm.ChainStore().BlockMsgsForTipset(ts)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, cid.Undef, xerrors.Errorf("getting block messages for tipset: %w", err)
|
||||||
|
}
|
||||||
|
fbmsgs := make([]FilecoinBlockMessages, len(blkmsgs))
|
||||||
|
for i := range fbmsgs {
|
||||||
|
fbmsgs[i].BlockMessages = blkmsgs[i]
|
||||||
|
fbmsgs[i].WinCount = ts.Blocks()[i].ElectionProof.WinCount
|
||||||
|
}
|
||||||
|
baseFee := blks[0].ParentBaseFee
|
||||||
|
|
||||||
|
return t.ApplyBlocks(ctx, sm, parentEpoch, pstate, fbmsgs, blks[0].Height, r, em, baseFee, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ stmgr.Executor = &tipSetExecutor{}
|
847
chain/consensus/filcns/filecoin.go
Normal file
847
chain/consensus/filcns/filecoin.go
Normal file
@ -0,0 +1,847 @@
|
|||||||
|
package filcns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
logging "github.com/ipfs/go-log/v2"
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"go.opencensus.io/stats"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof"
|
||||||
|
|
||||||
|
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||||
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||||
|
"github.com/filecoin-project/lotus/lib/async"
|
||||||
|
"github.com/filecoin-project/lotus/lib/sigs"
|
||||||
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("fil-consensus")
|
||||||
|
|
||||||
|
type FilecoinEC struct {
|
||||||
|
// The interface for accessing and putting tipsets into local storage
|
||||||
|
store *store.ChainStore
|
||||||
|
|
||||||
|
// handle to the random beacon for verification
|
||||||
|
beacon beacon.Schedule
|
||||||
|
|
||||||
|
// the state manager handles making state queries
|
||||||
|
sm *stmgr.StateManager
|
||||||
|
|
||||||
|
verifier ffiwrapper.Verifier
|
||||||
|
|
||||||
|
genesis *types.TipSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocks that are more than MaxHeightDrift epochs above
|
||||||
|
// the theoretical max height based on systime are quickly rejected
|
||||||
|
const MaxHeightDrift = 5
|
||||||
|
|
||||||
|
func NewFilecoinExpectedConsensus(sm *stmgr.StateManager, beacon beacon.Schedule, verifier ffiwrapper.Verifier, genesis chain.Genesis) consensus.Consensus {
|
||||||
|
if build.InsecurePoStValidation {
|
||||||
|
log.Warn("*********************************************************************************************")
|
||||||
|
log.Warn(" [INSECURE-POST-VALIDATION] Insecure test validation is enabled. If you see this outside of a test, it is a severe bug! ")
|
||||||
|
log.Warn("*********************************************************************************************")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &FilecoinEC{
|
||||||
|
store: sm.ChainStore(),
|
||||||
|
beacon: beacon,
|
||||||
|
sm: sm,
|
||||||
|
verifier: verifier,
|
||||||
|
genesis: genesis,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) {
|
||||||
|
if err := blockSanityChecks(b.Header); err != nil {
|
||||||
|
return xerrors.Errorf("incoming header failed basic sanity checks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h := b.Header
|
||||||
|
|
||||||
|
baseTs, err := filec.store.LoadTipSet(types.NewTipSetKey(h.Parents...))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("load parent tipset failed (%s): %w", h.Parents, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
winPoStNv := filec.sm.GetNtwkVersion(ctx, baseTs.Height())
|
||||||
|
|
||||||
|
lbts, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, filec.sm, baseTs, h.Height)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get lookback tipset for block: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prevBeacon, err := filec.store.GetLatestBeaconEntry(baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get latest beacon entry: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fast checks first
|
||||||
|
if h.Height <= baseTs.Height() {
|
||||||
|
return xerrors.Errorf("block height not greater than parent height: %d != %d", h.Height, baseTs.Height())
|
||||||
|
}
|
||||||
|
|
||||||
|
nulls := h.Height - (baseTs.Height() + 1)
|
||||||
|
if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
|
||||||
|
return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := uint64(build.Clock.Now().Unix())
|
||||||
|
if h.Timestamp > now+build.AllowableClockDriftSecs {
|
||||||
|
return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, consensus.ErrTemporal)
|
||||||
|
}
|
||||||
|
if h.Timestamp > now {
|
||||||
|
log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
msgsCheck := async.Err(func() error {
|
||||||
|
if b.Cid() == build.WhitelistedBlock {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := filec.checkBlockMessages(ctx, b, baseTs); err != nil {
|
||||||
|
return xerrors.Errorf("block had invalid messages: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
minerCheck := async.Err(func() error {
|
||||||
|
if err := filec.minerIsValid(ctx, h.Miner, baseTs); err != nil {
|
||||||
|
return xerrors.Errorf("minerIsValid failed: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
baseFeeCheck := async.Err(func() error {
|
||||||
|
baseFee, err := filec.store.ComputeBaseFee(ctx, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("computing base fee: %w", err)
|
||||||
|
}
|
||||||
|
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
|
||||||
|
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
|
||||||
|
b.Header.ParentBaseFee, baseFee)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
pweight, err := filec.store.Weight(ctx, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting parent weight: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if types.BigCmp(pweight, b.Header.ParentWeight) != 0 {
|
||||||
|
return xerrors.Errorf("parrent weight different: %s (header) != %s (computed)",
|
||||||
|
b.Header.ParentWeight, pweight)
|
||||||
|
}
|
||||||
|
|
||||||
|
stateRootCheck := async.Err(func() error {
|
||||||
|
stateroot, precp, err := filec.sm.TipSetState(ctx, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stateroot != h.ParentStateRoot {
|
||||||
|
msgs, err := filec.store.MessagesForTipset(baseTs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
|
||||||
|
} else {
|
||||||
|
log.Warn("Messages for tipset with mismatching state:")
|
||||||
|
for i, m := range msgs {
|
||||||
|
mm := m.VMMessage()
|
||||||
|
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", stateroot, h.ParentStateRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
if precp != h.ParentMessageReceipts {
|
||||||
|
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// Stuff that needs worker address
|
||||||
|
waddr, err := stmgr.GetMinerWorkerRaw(ctx, filec.sm, lbst, h.Miner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
winnerCheck := async.Err(func() error {
|
||||||
|
if h.ElectionProof.WinCount < 1 {
|
||||||
|
return xerrors.Errorf("block is not claiming to be a winner")
|
||||||
|
}
|
||||||
|
|
||||||
|
eligible, err := stmgr.MinerEligibleToMine(ctx, filec.sm, h.Miner, baseTs, lbts)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !eligible {
|
||||||
|
return xerrors.New("block's miner is ineligible to mine")
|
||||||
|
}
|
||||||
|
|
||||||
|
rBeacon := *prevBeacon
|
||||||
|
if len(h.BeaconEntries) != 0 {
|
||||||
|
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
||||||
|
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vrfBase, err := store.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("could not draw randomness: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
|
||||||
|
return xerrors.Errorf("validating block election proof failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
slashed, err := stmgr.GetMinerSlashed(ctx, filec.sm, baseTs, h.Miner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to check if block miner was slashed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if slashed {
|
||||||
|
return xerrors.Errorf("received block was from slashed or invalid miner")
|
||||||
|
}
|
||||||
|
|
||||||
|
mpow, tpow, _, err := stmgr.GetPowerRaw(ctx, filec.sm, lbst, h.Miner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed getting power: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
j := h.ElectionProof.ComputeWinCount(mpow.QualityAdjPower, tpow.QualityAdjPower)
|
||||||
|
if h.ElectionProof.WinCount != j {
|
||||||
|
return xerrors.Errorf("miner claims wrong number of wins: miner: %d, computed: %d", h.ElectionProof.WinCount, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
blockSigCheck := async.Err(func() error {
|
||||||
|
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil {
|
||||||
|
return xerrors.Errorf("check block signature failed: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
beaconValuesCheck := async.Err(func() error {
|
||||||
|
if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := beacon.ValidateBlockValues(filec.beacon, h, baseTs.Height(), *prevBeacon); err != nil {
|
||||||
|
return xerrors.Errorf("failed to validate blocks random beacon values: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
tktsCheck := async.Err(func() error {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
||||||
|
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Height > build.UpgradeSmokeHeight {
|
||||||
|
buf.Write(baseTs.MinTicket().VRFProof)
|
||||||
|
}
|
||||||
|
|
||||||
|
beaconBase := *prevBeacon
|
||||||
|
if len(h.BeaconEntries) != 0 {
|
||||||
|
beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
vrfBase, err := store.DrawRandomness(beaconBase.Data, crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("validating block tickets failed: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
wproofCheck := async.Err(func() error {
|
||||||
|
if err := filec.VerifyWinningPoStProof(ctx, winPoStNv, h, *prevBeacon, lbst, waddr); err != nil {
|
||||||
|
return xerrors.Errorf("invalid election post: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
await := []async.ErrorFuture{
|
||||||
|
minerCheck,
|
||||||
|
tktsCheck,
|
||||||
|
blockSigCheck,
|
||||||
|
beaconValuesCheck,
|
||||||
|
wproofCheck,
|
||||||
|
winnerCheck,
|
||||||
|
msgsCheck,
|
||||||
|
baseFeeCheck,
|
||||||
|
stateRootCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
var merr error
|
||||||
|
for _, fut := range await {
|
||||||
|
if err := fut.AwaitContext(ctx); err != nil {
|
||||||
|
merr = multierror.Append(merr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if merr != nil {
|
||||||
|
mulErr := merr.(*multierror.Error)
|
||||||
|
mulErr.ErrorFormat = func(es []error) string {
|
||||||
|
if len(es) == 1 {
|
||||||
|
return fmt.Sprintf("1 error occurred:\n\t* %+v\n\n", es[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
points := make([]string, len(es))
|
||||||
|
for i, err := range es {
|
||||||
|
points[i] = fmt.Sprintf("* %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%d errors occurred:\n\t%s\n\n",
|
||||||
|
len(es), strings.Join(points, "\n\t"))
|
||||||
|
}
|
||||||
|
return mulErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockSanityChecks(h *types.BlockHeader) error {
|
||||||
|
if h.ElectionProof == nil {
|
||||||
|
return xerrors.Errorf("block cannot have nil election proof")
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Ticket == nil {
|
||||||
|
return xerrors.Errorf("block cannot have nil ticket")
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.BlockSig == nil {
|
||||||
|
return xerrors.Errorf("block had nil signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.BLSAggregate == nil {
|
||||||
|
return xerrors.Errorf("block had nil bls aggregate signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Miner.Protocol() != address.ID {
|
||||||
|
return xerrors.Errorf("block had non-ID miner address")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.Version, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
|
||||||
|
if build.InsecurePoStValidation {
|
||||||
|
if len(h.WinPoStProof) == 0 {
|
||||||
|
return xerrors.Errorf("[INSECURE-POST-VALIDATION] No winning post proof given")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(h.WinPoStProof[0].ProofBytes) == "valid proof" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("[INSECURE-POST-VALIDATION] winning post was invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
||||||
|
return xerrors.Errorf("failed to marshal miner address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rbase := prevBeacon
|
||||||
|
if len(h.BeaconEntries) > 0 {
|
||||||
|
rbase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mid, err := address.IDFromAddress(h.Miner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get ID from miner address %s: %w", h.Miner, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sectors, err := stmgr.GetSectorsForWinningPoSt(ctx, nv, filec.verifier, filec.sm, lbst, h.Miner, rand)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting winning post sector set: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, proof2.WinningPoStVerifyInfo{
|
||||||
|
Randomness: rand,
|
||||||
|
Proofs: h.WinPoStProof,
|
||||||
|
ChallengedSectors: sectors,
|
||||||
|
Prover: abi.ActorID(mid),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to verify election post: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("invalid winning post (block: %s, %x; %v)", h.Cid(), rand, sectors)
|
||||||
|
return xerrors.Errorf("winning post was invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We should extract this somewhere else and make the message pool and miner use the same logic
|
||||||
|
func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error {
|
||||||
|
{
|
||||||
|
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
|
||||||
|
var pubks [][]byte
|
||||||
|
|
||||||
|
for _, m := range b.BlsMessages {
|
||||||
|
sigCids = append(sigCids, m.Cid())
|
||||||
|
|
||||||
|
pubk, err := filec.sm.GetBlsPublicKey(ctx, m.From, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pubks = append(pubks, pubk)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := consensus.VerifyBlsAggregate(ctx, b.Header.BLSAggregate, sigCids, pubks); err != nil {
|
||||||
|
return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonces := make(map[address.Address]uint64)
|
||||||
|
|
||||||
|
stateroot, _, err := filec.sm.TipSetState(ctx, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := state.LoadStateTree(filec.store.ActorStore(ctx), stateroot)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to load base state tree: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nv := filec.sm.GetNtwkVersion(ctx, b.Header.Height)
|
||||||
|
pl := vm.PricelistByEpoch(baseTs.Height())
|
||||||
|
var sumGasLimit int64
|
||||||
|
checkMsg := func(msg types.ChainMsg) error {
|
||||||
|
m := msg.VMMessage()
|
||||||
|
|
||||||
|
// Phase 1: syntactic validation, as defined in the spec
|
||||||
|
minGas := pl.OnChainMessage(msg.ChainLength())
|
||||||
|
if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
|
||||||
|
// So below is overflow safe
|
||||||
|
sumGasLimit += m.GasLimit
|
||||||
|
if sumGasLimit > build.BlockGasLimit {
|
||||||
|
return xerrors.Errorf("block gas limit exceeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2: (Partial) semantic validation:
|
||||||
|
// the sender exists and is an account actor, and the nonces make sense
|
||||||
|
var sender address.Address
|
||||||
|
if filec.sm.GetNtwkVersion(ctx, b.Header.Height) >= network.Version13 {
|
||||||
|
sender, err = st.LookupID(m.From)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender = m.From
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := nonces[sender]; !ok {
|
||||||
|
// `GetActor` does not validate that this is an account actor.
|
||||||
|
act, err := st.GetActor(sender)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !builtin.IsAccountActor(act.Code) {
|
||||||
|
return xerrors.New("Sender must be an account actor")
|
||||||
|
}
|
||||||
|
nonces[sender] = act.Nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
if nonces[sender] != m.Nonce {
|
||||||
|
return xerrors.Errorf("wrong nonce (exp: %d, got: %d)", nonces[sender], m.Nonce)
|
||||||
|
}
|
||||||
|
nonces[sender]++
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate message arrays in a temporary blockstore.
|
||||||
|
tmpbs := bstore.NewMemory()
|
||||||
|
tmpstore := blockadt.WrapStore(ctx, cbor.NewCborStore(tmpbs))
|
||||||
|
|
||||||
|
bmArr := blockadt.MakeEmptyArray(tmpstore)
|
||||||
|
for i, m := range b.BlsMessages {
|
||||||
|
if err := checkMsg(m); err != nil {
|
||||||
|
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := store.PutMessage(tmpbs, m)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
k := cbg.CborCid(c)
|
||||||
|
if err := bmArr.Set(uint64(i), &k); err != nil {
|
||||||
|
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
smArr := blockadt.MakeEmptyArray(tmpstore)
|
||||||
|
for i, m := range b.SecpkMessages {
|
||||||
|
if err := checkMsg(m); err != nil {
|
||||||
|
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// `From` being an account actor is only validated inside the `vm.ResolveToKeyAddr` call
|
||||||
|
// in `StateManager.ResolveToKeyAddress` here (and not in `checkMsg`).
|
||||||
|
kaddr, err := filec.sm.ResolveToKeyAddress(ctx, m.Message.From, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil {
|
||||||
|
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := store.PutMessage(tmpbs, m)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||||
|
}
|
||||||
|
k := cbg.CborCid(c)
|
||||||
|
if err := smArr.Set(uint64(i), &k); err != nil {
|
||||||
|
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bmroot, err := bmArr.Root()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
smroot, err := smArr.Root()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
|
||||||
|
BlsMessages: bmroot,
|
||||||
|
SecpkMessages: smroot,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Header.Messages != mrcid {
|
||||||
|
return fmt.Errorf("messages didnt match message root in header")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, flush.
|
||||||
|
return vm.Copy(ctx, tmpbs, filec.store.ChainBlockstore(), mrcid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
||||||
|
if filec.genesis == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
now := uint64(build.Clock.Now().Unix())
|
||||||
|
return epoch > (abi.ChainEpoch((now-filec.genesis.MinTimestamp())/build.BlockDelaySecs) + MaxHeightDrift)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) minerIsValid(ctx context.Context, maddr address.Address, baseTs *types.TipSet) error {
|
||||||
|
act, err := filec.sm.LoadActor(ctx, power.Address, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to load power actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
powState, err := power.Load(filec.store.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to load power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, exist, err := powState.MinerPower(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to look up miner's claim: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
|
return xerrors.New("miner isn't valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []byte, evrf []byte) error {
|
||||||
|
return VerifyVRF(ctx, worker, rand, evrf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyVRF(ctx context.Context, worker address.Address, vrfBase, vrfproof []byte) error {
|
||||||
|
_, span := trace.StartSpan(ctx, "VerifyVRF")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
sig := &crypto.Signature{
|
||||||
|
Type: crypto.SigTypeBLS,
|
||||||
|
Data: vrfproof,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sigs.Verify(sig, worker, vrfBase); err != nil {
|
||||||
|
return xerrors.Errorf("vrf was invalid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrSoftFailure = errors.New("soft validation failure")
|
||||||
|
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) ValidateBlockPubsub(ctx context.Context, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string) {
|
||||||
|
if self {
|
||||||
|
return filec.validateLocalBlock(ctx, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// track validation time
|
||||||
|
begin := build.Clock.Now()
|
||||||
|
defer func() {
|
||||||
|
log.Debugf("block validation time: %s", build.Clock.Since(begin))
|
||||||
|
}()
|
||||||
|
|
||||||
|
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||||
|
|
||||||
|
recordFailureFlagPeer := func(what string) {
|
||||||
|
// bv.Validate will flag the peer in that case
|
||||||
|
panic(what)
|
||||||
|
}
|
||||||
|
|
||||||
|
blk, what, err := filec.decodeAndCheckBlock(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("got invalid block over pubsub: ", err)
|
||||||
|
recordFailureFlagPeer(what)
|
||||||
|
return pubsub.ValidationReject, what
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate the block meta: the Message CID in the header must match the included messages
|
||||||
|
err = filec.validateMsgMeta(ctx, blk)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("error validating message metadata: %s", err)
|
||||||
|
recordFailureFlagPeer("invalid_block_meta")
|
||||||
|
return pubsub.ValidationReject, "invalid_block_meta"
|
||||||
|
}
|
||||||
|
|
||||||
|
reject, err := filec.validateBlockHeader(ctx, blk.Header)
|
||||||
|
if err != nil {
|
||||||
|
if reject == "" {
|
||||||
|
log.Warn("ignoring block msg: ", err)
|
||||||
|
return pubsub.ValidationIgnore, reject
|
||||||
|
}
|
||||||
|
recordFailureFlagPeer(reject)
|
||||||
|
return pubsub.ValidationReject, reject
|
||||||
|
}
|
||||||
|
|
||||||
|
// all good, accept the block
|
||||||
|
msg.ValidatorData = blk
|
||||||
|
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||||
|
return pubsub.ValidationAccept, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) validateLocalBlock(ctx context.Context, msg *pubsub.Message) (pubsub.ValidationResult, string) {
|
||||||
|
stats.Record(ctx, metrics.BlockPublished.M(1))
|
||||||
|
|
||||||
|
if size := msg.Size(); size > 1<<20-1<<15 {
|
||||||
|
log.Errorf("ignoring oversize block (%dB)", size)
|
||||||
|
return pubsub.ValidationIgnore, "oversize_block"
|
||||||
|
}
|
||||||
|
|
||||||
|
blk, what, err := filec.decodeAndCheckBlock(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("got invalid local block: %s", err)
|
||||||
|
return pubsub.ValidationIgnore, what
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.ValidatorData = blk
|
||||||
|
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||||
|
return pubsub.ValidationAccept, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
|
||||||
|
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||||
|
if err != nil {
|
||||||
|
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
|
||||||
|
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we have a signature
|
||||||
|
if blk.Header.BlockSig == nil {
|
||||||
|
return nil, "missing_signature", fmt.Errorf("block without a signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
return blk, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||||
|
// TODO there has to be a simpler way to do this without the blockstore dance
|
||||||
|
// block headers use adt0
|
||||||
|
store := blockadt.WrapStore(ctx, cbor.NewCborStore(bstore.NewMemory()))
|
||||||
|
bmArr := blockadt.MakeEmptyArray(store)
|
||||||
|
smArr := blockadt.MakeEmptyArray(store)
|
||||||
|
|
||||||
|
for i, m := range msg.BlsMessages {
|
||||||
|
c := cbg.CborCid(m)
|
||||||
|
if err := bmArr.Set(uint64(i), &c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, m := range msg.SecpkMessages {
|
||||||
|
c := cbg.CborCid(m)
|
||||||
|
if err := smArr.Set(uint64(i), &c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bmroot, err := bmArr.Root()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
smroot, err := smArr.Root()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mrcid, err := store.Put(store.Context(), &types.MsgMeta{
|
||||||
|
BlsMessages: bmroot,
|
||||||
|
SecpkMessages: smroot,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.Header.Messages != mrcid {
|
||||||
|
return fmt.Errorf("messages didn't match root cid in header")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) validateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error) {
|
||||||
|
|
||||||
|
// we want to ensure that it is a block from a known miner; we reject blocks from unknown miners
|
||||||
|
// to prevent spam attacks.
|
||||||
|
// the logic works as follows: we lookup the miner in the chain for its key.
|
||||||
|
// if we can find it then it's a known miner and we can validate the signature.
|
||||||
|
// if we can't find it, we check whether we are (near) synced in the chain.
|
||||||
|
// if we are not synced we cannot validate the block and we must ignore it.
|
||||||
|
// if we are synced and the miner is unknown, then the block is rejcected.
|
||||||
|
key, err := filec.checkPowerAndGetWorkerKey(ctx, b)
|
||||||
|
if err != nil {
|
||||||
|
if err != ErrSoftFailure && filec.isChainNearSynced() {
|
||||||
|
log.Warnf("received block from unknown miner or miner that doesn't meet min power over pubsub; rejecting message")
|
||||||
|
return "unknown_miner", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain: %s", b.Cid())
|
||||||
|
return "", err // ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.ElectionProof.WinCount < 1 {
|
||||||
|
log.Errorf("block is not claiming to be winning")
|
||||||
|
return "not_winning", xerrors.Errorf("block not winning")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sigs.CheckBlockSignature(ctx, b, key)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("block signature verification failed: %s", err)
|
||||||
|
return "signature_verification_failed", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) checkPowerAndGetWorkerKey(ctx context.Context, bh *types.BlockHeader) (address.Address, error) {
|
||||||
|
// we check that the miner met the minimum power at the lookback tipset
|
||||||
|
|
||||||
|
baseTs := filec.store.GetHeaviestTipSet()
|
||||||
|
lbts, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, filec.sm, baseTs, bh.Height)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to load lookback tipset for incoming block: %s", err)
|
||||||
|
return address.Undef, ErrSoftFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := stmgr.GetMinerWorkerRaw(ctx, filec.sm, lbst, bh.Miner)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to resolve worker key for miner %s: %s", bh.Miner, err)
|
||||||
|
return address.Undef, ErrSoftFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we check to see if the miner was eligible in the lookback
|
||||||
|
// tipset - 1 for historical reasons. DO NOT use the lookback state
|
||||||
|
// returned by GetLookbackTipSetForRound.
|
||||||
|
|
||||||
|
eligible, err := stmgr.MinerEligibleToMine(ctx, filec.sm, bh.Miner, baseTs, lbts)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
|
||||||
|
return address.Undef, ErrSoftFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
if !eligible {
|
||||||
|
log.Warnf("incoming block's miner is ineligible")
|
||||||
|
return address.Undef, ErrInsufficientPower
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (filec *FilecoinEC) isChainNearSynced() bool {
|
||||||
|
ts := filec.store.GetHeaviestTipSet()
|
||||||
|
timestamp := ts.MinTimestamp()
|
||||||
|
timestampTime := time.Unix(int64(timestamp), 0)
|
||||||
|
return build.Clock.Since(timestampTime) < 6*time.Hour
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ consensus.Consensus = &FilecoinEC{}
|
@ -1,38 +1,35 @@
|
|||||||
package gen
|
package filcns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/ipfs/go-cid"
|
||||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
cid "github.com/ipfs/go-cid"
|
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
||||||
|
pts, err := filec.sm.ChainStore().LoadTipSet(bt.Parents)
|
||||||
pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to load parent tipset: %w", err)
|
return nil, xerrors.Errorf("failed to load parent tipset: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
st, recpts, err := sm.TipSetState(ctx, pts)
|
st, recpts, err := filec.sm.TipSetState(ctx, pts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to load tipset state: %w", err)
|
return nil, xerrors.Errorf("failed to load tipset state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, sm, pts, bt.Epoch)
|
_, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, filec.sm, pts, bt.Epoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, lbst, bt.Miner)
|
worker, err := stmgr.GetMinerWorkerRaw(ctx, filec.sm, lbst, bt.Miner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||||
}
|
}
|
||||||
@ -61,14 +58,14 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.Wallet,
|
|||||||
blsSigs = append(blsSigs, msg.Signature)
|
blsSigs = append(blsSigs, msg.Signature)
|
||||||
blsMessages = append(blsMessages, &msg.Message)
|
blsMessages = append(blsMessages, &msg.Message)
|
||||||
|
|
||||||
c, err := sm.ChainStore().PutMessage(&msg.Message)
|
c, err := filec.sm.ChainStore().PutMessage(&msg.Message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blsMsgCids = append(blsMsgCids, c)
|
blsMsgCids = append(blsMsgCids, c)
|
||||||
} else {
|
} else {
|
||||||
c, err := sm.ChainStore().PutMessage(msg)
|
c, err := filec.sm.ChainStore().PutMessage(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -79,12 +76,12 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.Wallet,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store := sm.ChainStore().ActorStore(ctx)
|
store := filec.sm.ChainStore().ActorStore(ctx)
|
||||||
blsmsgroot, err := toArray(store, blsMsgCids)
|
blsmsgroot, err := consensus.ToMessagesArray(store, blsMsgCids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("building bls amt: %w", err)
|
return nil, xerrors.Errorf("building bls amt: %w", err)
|
||||||
}
|
}
|
||||||
secpkmsgroot, err := toArray(store, secpkMsgCids)
|
secpkmsgroot, err := consensus.ToMessagesArray(store, secpkMsgCids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("building secpk amt: %w", err)
|
return nil, xerrors.Errorf("building secpk amt: %w", err)
|
||||||
}
|
}
|
||||||
@ -98,19 +95,19 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.Wallet,
|
|||||||
}
|
}
|
||||||
next.Messages = mmcid
|
next.Messages = mmcid
|
||||||
|
|
||||||
aggSig, err := aggregateSignatures(blsSigs)
|
aggSig, err := consensus.AggregateSignatures(blsSigs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
next.BLSAggregate = aggSig
|
next.BLSAggregate = aggSig
|
||||||
pweight, err := sm.ChainStore().Weight(ctx, pts)
|
pweight, err := filec.sm.ChainStore().Weight(ctx, pts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
next.ParentWeight = pweight
|
next.ParentWeight = pweight
|
||||||
|
|
||||||
baseFee, err := sm.ChainStore().ComputeBaseFee(ctx, pts)
|
baseFee, err := filec.sm.ChainStore().ComputeBaseFee(ctx, pts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("computing base fee: %w", err)
|
return nil, xerrors.Errorf("computing base fee: %w", err)
|
||||||
}
|
}
|
||||||
@ -138,41 +135,3 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.Wallet,
|
|||||||
|
|
||||||
return fullBlock, nil
|
return fullBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
|
|
||||||
sigsS := make([]ffi.Signature, len(sigs))
|
|
||||||
for i := 0; i < len(sigs); i++ {
|
|
||||||
copy(sigsS[i][:], sigs[i].Data[:ffi.SignatureBytes])
|
|
||||||
}
|
|
||||||
|
|
||||||
aggSig := ffi.Aggregate(sigsS)
|
|
||||||
if aggSig == nil {
|
|
||||||
if len(sigs) > 0 {
|
|
||||||
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
|
|
||||||
}
|
|
||||||
|
|
||||||
zeroSig := ffi.CreateZeroSignature()
|
|
||||||
|
|
||||||
// Note: for blst this condition should not happen - nil should not
|
|
||||||
// be returned
|
|
||||||
return &crypto.Signature{
|
|
||||||
Type: crypto.SigTypeBLS,
|
|
||||||
Data: zeroSig[:],
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return &crypto.Signature{
|
|
||||||
Type: crypto.SigTypeBLS,
|
|
||||||
Data: aggSig[:],
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func toArray(store blockadt.Store, cids []cid.Cid) (cid.Cid, error) {
|
|
||||||
arr := blockadt.MakeEmptyArray(store)
|
|
||||||
for i, c := range cids {
|
|
||||||
oc := cbg.CborCid(c)
|
|
||||||
if err := arr.Set(uint64(i), &oc); err != nil {
|
|
||||||
return cid.Undef, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arr.Root()
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package stmgr
|
package filcns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
"github.com/filecoin-project/go-state-types/rt"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
@ -31,15 +32,16 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DefaultUpgradeSchedule() UpgradeSchedule {
|
func DefaultUpgradeSchedule() stmgr.UpgradeSchedule {
|
||||||
var us UpgradeSchedule
|
var us stmgr.UpgradeSchedule
|
||||||
|
|
||||||
updates := []Upgrade{{
|
updates := []stmgr.Upgrade{{
|
||||||
Height: build.UpgradeBreezeHeight,
|
Height: build.UpgradeBreezeHeight,
|
||||||
Network: network.Version1,
|
Network: network.Version1,
|
||||||
Migration: UpgradeFaucetBurnRecovery,
|
Migration: UpgradeFaucetBurnRecovery,
|
||||||
@ -88,7 +90,7 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
|||||||
Height: build.UpgradeTrustHeight,
|
Height: build.UpgradeTrustHeight,
|
||||||
Network: network.Version10,
|
Network: network.Version10,
|
||||||
Migration: UpgradeActorsV3,
|
Migration: UpgradeActorsV3,
|
||||||
PreMigrations: []PreMigration{{
|
PreMigrations: []stmgr.PreMigration{{
|
||||||
PreMigration: PreUpgradeActorsV3,
|
PreMigration: PreUpgradeActorsV3,
|
||||||
StartWithin: 120,
|
StartWithin: 120,
|
||||||
DontStartWithin: 60,
|
DontStartWithin: 60,
|
||||||
@ -108,7 +110,7 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
|||||||
Height: build.UpgradeTurboHeight,
|
Height: build.UpgradeTurboHeight,
|
||||||
Network: network.Version12,
|
Network: network.Version12,
|
||||||
Migration: UpgradeActorsV4,
|
Migration: UpgradeActorsV4,
|
||||||
PreMigrations: []PreMigration{{
|
PreMigrations: []stmgr.PreMigration{{
|
||||||
PreMigration: PreUpgradeActorsV4,
|
PreMigration: PreUpgradeActorsV4,
|
||||||
StartWithin: 120,
|
StartWithin: 120,
|
||||||
DontStartWithin: 60,
|
DontStartWithin: 60,
|
||||||
@ -124,7 +126,7 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
|||||||
Height: build.UpgradeHyperdriveHeight,
|
Height: build.UpgradeHyperdriveHeight,
|
||||||
Network: network.Version13,
|
Network: network.Version13,
|
||||||
Migration: UpgradeActorsV5,
|
Migration: UpgradeActorsV5,
|
||||||
PreMigrations: []PreMigration{{
|
PreMigrations: []stmgr.PreMigration{{
|
||||||
PreMigration: PreUpgradeActorsV5,
|
PreMigration: PreUpgradeActorsV5,
|
||||||
StartWithin: 120,
|
StartWithin: 120,
|
||||||
DontStartWithin: 60,
|
DontStartWithin: 60,
|
||||||
@ -147,7 +149,7 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
|||||||
return us
|
return us
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ MigrationCache, em ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, em stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
// Some initial parameters
|
// Some initial parameters
|
||||||
FundsForMiners := types.FromFil(1_000_000)
|
FundsForMiners := types.FromFil(1_000_000)
|
||||||
LookbackEpoch := abi.ChainEpoch(32000)
|
LookbackEpoch := abi.ChainEpoch(32000)
|
||||||
@ -249,7 +251,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ Migratio
|
|||||||
|
|
||||||
// Execute transfers from previous step
|
// Execute transfers from previous step
|
||||||
for _, t := range transfers {
|
for _, t := range transfers {
|
||||||
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
if err := stmgr.DoTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,7 +354,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ Migratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range transfersBack {
|
for _, t := range transfersBack {
|
||||||
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
if err := stmgr.DoTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,7 +364,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ Migratio
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||||
}
|
}
|
||||||
if err := doTransfer(tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance, transferCb); err != nil {
|
if err := stmgr.DoTransfer(tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance, transferCb); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +380,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ Migratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
||||||
if err := doTransfer(tree, builtin.ReserveAddress, reimbAddr, difference, transferCb); err != nil {
|
if err := stmgr.DoTransfer(tree, builtin.ReserveAddress, reimbAddr, difference, transferCb); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,14 +402,14 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ Migratio
|
|||||||
if em != nil {
|
if em != nil {
|
||||||
// record the transfer in execution traces
|
// record the transfer in execution traces
|
||||||
|
|
||||||
fakeMsg := makeFakeMsg(builtin.SystemActorAddr, builtin.SystemActorAddr, big.Zero(), uint64(epoch))
|
fakeMsg := stmgr.MakeFakeMsg(builtin.SystemActorAddr, builtin.SystemActorAddr, big.Zero(), uint64(epoch))
|
||||||
|
|
||||||
if err := em.MessageApplied(ctx, ts, fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
if err := em.MessageApplied(ctx, ts, fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||||
MessageReceipt: *makeFakeRct(),
|
MessageReceipt: *stmgr.MakeFakeRct(),
|
||||||
ActorErr: nil,
|
ActorErr: nil,
|
||||||
ExecutionTrace: types.ExecutionTrace{
|
ExecutionTrace: types.ExecutionTrace{
|
||||||
Msg: fakeMsg,
|
Msg: fakeMsg,
|
||||||
MsgRct: makeFakeRct(),
|
MsgRct: stmgr.MakeFakeRct(),
|
||||||
Error: "",
|
Error: "",
|
||||||
Duration: 0,
|
Duration: 0,
|
||||||
GasCharges: nil,
|
GasCharges: nil,
|
||||||
@ -423,8 +425,8 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, _ Migratio
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeIgnition(ctx context.Context, sm *StateManager, _ MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeIgnition(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
store := sm.cs.ActorStore(ctx)
|
store := sm.ChainStore().ActorStore(ctx)
|
||||||
|
|
||||||
if build.UpgradeLiftoffHeight <= epoch {
|
if build.UpgradeLiftoffHeight <= epoch {
|
||||||
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
||||||
@ -440,7 +442,7 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, _ MigrationCache, cb
|
|||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setNetworkName(ctx, store, tree, "ignition")
|
err = stmgr.SetNetworkName(ctx, store, tree, "ignition")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("setting network name: %w", err)
|
return cid.Undef, xerrors.Errorf("setting network name: %w", err)
|
||||||
}
|
}
|
||||||
@ -478,7 +480,7 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, _ MigrationCache, cb
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitGenesisMultisig0(ctx context.Context, em ExecMonitor, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
func splitGenesisMultisig0(ctx context.Context, em stmgr.ExecMonitor, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
||||||
if portions < 1 {
|
if portions < 1 {
|
||||||
return xerrors.Errorf("cannot split into 0 portions")
|
return xerrors.Errorf("cannot split into 0 portions")
|
||||||
}
|
}
|
||||||
@ -553,7 +555,7 @@ func splitGenesisMultisig0(ctx context.Context, em ExecMonitor, addr address.Add
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i < portions {
|
for i < portions {
|
||||||
keyAddr, err := makeKeyAddr(addr, i)
|
keyAddr, err := stmgr.MakeKeyAddr(addr, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("creating key address: %w", err)
|
return xerrors.Errorf("creating key address: %w", err)
|
||||||
}
|
}
|
||||||
@ -568,7 +570,7 @@ func splitGenesisMultisig0(ctx context.Context, em ExecMonitor, addr address.Add
|
|||||||
return xerrors.Errorf("setting new msig actor state: %w", err)
|
return xerrors.Errorf("setting new msig actor state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := doTransfer(tree, addr, idAddr, newIbal, transferCb); err != nil {
|
if err := stmgr.DoTransfer(tree, addr, idAddr, newIbal, transferCb); err != nil {
|
||||||
return xerrors.Errorf("transferring split msig balance: %w", err)
|
return xerrors.Errorf("transferring split msig balance: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,14 +580,14 @@ func splitGenesisMultisig0(ctx context.Context, em ExecMonitor, addr address.Add
|
|||||||
if em != nil {
|
if em != nil {
|
||||||
// record the transfer in execution traces
|
// record the transfer in execution traces
|
||||||
|
|
||||||
fakeMsg := makeFakeMsg(builtin.SystemActorAddr, addr, big.Zero(), uint64(epoch))
|
fakeMsg := stmgr.MakeFakeMsg(builtin.SystemActorAddr, addr, big.Zero(), uint64(epoch))
|
||||||
|
|
||||||
if err := em.MessageApplied(ctx, ts, fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
if err := em.MessageApplied(ctx, ts, fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||||
MessageReceipt: *makeFakeRct(),
|
MessageReceipt: *stmgr.MakeFakeRct(),
|
||||||
ActorErr: nil,
|
ActorErr: nil,
|
||||||
ExecutionTrace: types.ExecutionTrace{
|
ExecutionTrace: types.ExecutionTrace{
|
||||||
Msg: fakeMsg,
|
Msg: fakeMsg,
|
||||||
MsgRct: makeFakeRct(),
|
MsgRct: stmgr.MakeFakeRct(),
|
||||||
Error: "",
|
Error: "",
|
||||||
Duration: 0,
|
Duration: 0,
|
||||||
GasCharges: nil,
|
GasCharges: nil,
|
||||||
@ -602,8 +604,8 @@ func splitGenesisMultisig0(ctx context.Context, em ExecMonitor, addr address.Add
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
|
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
|
||||||
func resetGenesisMsigs0(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
|
func resetGenesisMsigs0(ctx context.Context, sm *stmgr.StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
|
||||||
gb, err := sm.cs.GetGenesis()
|
gb, err := sm.ChainStore().GetGenesis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting genesis block: %w", err)
|
return xerrors.Errorf("getting genesis block: %w", err)
|
||||||
}
|
}
|
||||||
@ -613,7 +615,7 @@ func resetGenesisMsigs0(ctx context.Context, sm *StateManager, store adt0.Store,
|
|||||||
return xerrors.Errorf("getting genesis tipset: %w", err)
|
return xerrors.Errorf("getting genesis tipset: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cst := cbor.NewCborStore(sm.cs.StateBlockstore())
|
cst := cbor.NewCborStore(sm.ChainStore().StateBlockstore())
|
||||||
genesisTree, err := state.LoadStateTree(cst, gts.ParentState())
|
genesisTree, err := state.LoadStateTree(cst, gts.ParentState())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("loading state tree: %w", err)
|
return xerrors.Errorf("loading state tree: %w", err)
|
||||||
@ -683,9 +685,9 @@ func resetMultisigVesting0(ctx context.Context, store adt0.Store, tree *state.St
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeRefuel(ctx context.Context, sm *StateManager, _ MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeRefuel(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
|
|
||||||
store := sm.cs.ActorStore(ctx)
|
store := sm.ChainStore().ActorStore(ctx)
|
||||||
tree, err := sm.StateTree(root)
|
tree, err := sm.StateTree(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
@ -709,8 +711,8 @@ func UpgradeRefuel(ctx context.Context, sm *StateManager, _ MigrationCache, cb E
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeActorsV2(ctx context.Context, sm *StateManager, _ MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeActorsV2(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
buf := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync())
|
buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync())
|
||||||
store := store.ActorStore(ctx, buf)
|
store := store.ActorStore(ctx, buf)
|
||||||
|
|
||||||
info, err := store.Put(ctx, new(types.StateInfo0))
|
info, err := store.Put(ctx, new(types.StateInfo0))
|
||||||
@ -755,13 +757,13 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, _ MigrationCache, cb
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeLiftoff(ctx context.Context, sm *StateManager, _ MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeLiftoff(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
tree, err := sm.StateTree(root)
|
tree, err := sm.StateTree(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setNetworkName(ctx, sm.cs.ActorStore(ctx), tree, "mainnet")
|
err = stmgr.SetNetworkName(ctx, sm.ChainStore().ActorStore(ctx), tree, "mainnet")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("setting network name: %w", err)
|
return cid.Undef, xerrors.Errorf("setting network name: %w", err)
|
||||||
}
|
}
|
||||||
@ -769,12 +771,12 @@ func UpgradeLiftoff(ctx context.Context, sm *StateManager, _ MigrationCache, cb
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeCalico(ctx context.Context, sm *StateManager, _ MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeCalico(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
if build.BuildType != build.BuildMainnet {
|
if build.BuildType != build.BuildMainnet {
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
store := sm.cs.ActorStore(ctx)
|
store := sm.ChainStore().ActorStore(ctx)
|
||||||
var stateRoot types.StateRoot
|
var stateRoot types.StateRoot
|
||||||
if err := store.Get(ctx, root, &stateRoot); err != nil {
|
if err := store.Get(ctx, root, &stateRoot); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err)
|
||||||
@ -815,7 +817,7 @@ func UpgradeCalico(ctx context.Context, sm *StateManager, _ MigrationCache, cb E
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeActorsV3(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeActorsV3(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
// Use all the CPUs except 3.
|
// Use all the CPUs except 3.
|
||||||
workerCount := runtime.NumCPU() - 3
|
workerCount := runtime.NumCPU() - 3
|
||||||
if workerCount <= 0 {
|
if workerCount <= 0 {
|
||||||
@ -839,7 +841,7 @@ func UpgradeActorsV3(ctx context.Context, sm *StateManager, cache MigrationCache
|
|||||||
}
|
}
|
||||||
|
|
||||||
if build.BuildType == build.BuildMainnet {
|
if build.BuildType == build.BuildMainnet {
|
||||||
err := terminateActor(ctx, tree, build.ZeroAddress, cb, epoch, ts)
|
err := stmgr.TerminateActor(ctx, tree, build.ZeroAddress, cb, epoch, ts)
|
||||||
if err != nil && !xerrors.Is(err, types.ErrActorNotFound) {
|
if err != nil && !xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
return cid.Undef, xerrors.Errorf("deleting zero bls actor: %w", err)
|
return cid.Undef, xerrors.Errorf("deleting zero bls actor: %w", err)
|
||||||
}
|
}
|
||||||
@ -853,7 +855,7 @@ func UpgradeActorsV3(ctx context.Context, sm *StateManager, cache MigrationCache
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreUpgradeActorsV3(ctx context.Context, sm *StateManager, cache MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
func PreUpgradeActorsV3(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
||||||
// Use half the CPUs for pre-migration, but leave at least 3.
|
// Use half the CPUs for pre-migration, but leave at least 3.
|
||||||
workerCount := runtime.NumCPU()
|
workerCount := runtime.NumCPU()
|
||||||
if workerCount <= 4 {
|
if workerCount <= 4 {
|
||||||
@ -867,11 +869,11 @@ func PreUpgradeActorsV3(ctx context.Context, sm *StateManager, cache MigrationCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upgradeActorsV3Common(
|
func upgradeActorsV3Common(
|
||||||
ctx context.Context, sm *StateManager, cache MigrationCache,
|
ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache,
|
||||||
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
||||||
config nv10.Config,
|
config nv10.Config,
|
||||||
) (cid.Cid, error) {
|
) (cid.Cid, error) {
|
||||||
buf := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync())
|
buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync())
|
||||||
store := store.ActorStore(ctx, buf)
|
store := store.ActorStore(ctx, buf)
|
||||||
|
|
||||||
// Load the state root.
|
// Load the state root.
|
||||||
@ -917,7 +919,7 @@ func upgradeActorsV3Common(
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeActorsV4(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeActorsV4(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
// Use all the CPUs except 3.
|
// Use all the CPUs except 3.
|
||||||
workerCount := runtime.NumCPU() - 3
|
workerCount := runtime.NumCPU() - 3
|
||||||
if workerCount <= 0 {
|
if workerCount <= 0 {
|
||||||
@ -939,7 +941,7 @@ func UpgradeActorsV4(ctx context.Context, sm *StateManager, cache MigrationCache
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreUpgradeActorsV4(ctx context.Context, sm *StateManager, cache MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
func PreUpgradeActorsV4(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
||||||
// Use half the CPUs for pre-migration, but leave at least 3.
|
// Use half the CPUs for pre-migration, but leave at least 3.
|
||||||
workerCount := runtime.NumCPU()
|
workerCount := runtime.NumCPU()
|
||||||
if workerCount <= 4 {
|
if workerCount <= 4 {
|
||||||
@ -953,11 +955,11 @@ func PreUpgradeActorsV4(ctx context.Context, sm *StateManager, cache MigrationCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upgradeActorsV4Common(
|
func upgradeActorsV4Common(
|
||||||
ctx context.Context, sm *StateManager, cache MigrationCache,
|
ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache,
|
||||||
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
||||||
config nv12.Config,
|
config nv12.Config,
|
||||||
) (cid.Cid, error) {
|
) (cid.Cid, error) {
|
||||||
buf := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync())
|
buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync())
|
||||||
store := store.ActorStore(ctx, buf)
|
store := store.ActorStore(ctx, buf)
|
||||||
|
|
||||||
// Load the state root.
|
// Load the state root.
|
||||||
@ -1003,7 +1005,7 @@ func upgradeActorsV4Common(
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeActorsV5(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeActorsV5(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
// Use all the CPUs except 3.
|
// Use all the CPUs except 3.
|
||||||
workerCount := runtime.NumCPU() - 3
|
workerCount := runtime.NumCPU() - 3
|
||||||
if workerCount <= 0 {
|
if workerCount <= 0 {
|
||||||
@ -1025,7 +1027,7 @@ func UpgradeActorsV5(ctx context.Context, sm *StateManager, cache MigrationCache
|
|||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreUpgradeActorsV5(ctx context.Context, sm *StateManager, cache MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
func PreUpgradeActorsV5(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
||||||
// Use half the CPUs for pre-migration, but leave at least 3.
|
// Use half the CPUs for pre-migration, but leave at least 3.
|
||||||
workerCount := runtime.NumCPU()
|
workerCount := runtime.NumCPU()
|
||||||
if workerCount <= 4 {
|
if workerCount <= 4 {
|
||||||
@ -1039,11 +1041,11 @@ func PreUpgradeActorsV5(ctx context.Context, sm *StateManager, cache MigrationCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upgradeActorsV5Common(
|
func upgradeActorsV5Common(
|
||||||
ctx context.Context, sm *StateManager, cache MigrationCache,
|
ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache,
|
||||||
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
||||||
config nv13.Config,
|
config nv13.Config,
|
||||||
) (cid.Cid, error) {
|
) (cid.Cid, error) {
|
||||||
buf := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync())
|
buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync())
|
||||||
store := store.ActorStore(ctx, buf)
|
store := store.ActorStore(ctx, buf)
|
||||||
|
|
||||||
// Load the state root.
|
// Load the state root.
|
||||||
@ -1088,3 +1090,18 @@ func upgradeActorsV5Common(
|
|||||||
|
|
||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type migrationLogger struct{}
|
||||||
|
|
||||||
|
func (ml migrationLogger) Log(level rt.LogLevel, msg string, args ...interface{}) {
|
||||||
|
switch level {
|
||||||
|
case rt.DEBUG:
|
||||||
|
log.Debugf(msg, args...)
|
||||||
|
case rt.INFO:
|
||||||
|
log.Infof(msg, args...)
|
||||||
|
case rt.WARN:
|
||||||
|
log.Warnf(msg, args...)
|
||||||
|
case rt.ERROR:
|
||||||
|
log.Errorf(msg, args...)
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,25 @@
|
|||||||
package store
|
package filcns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
|
||||||
|
|
||||||
big2 "github.com/filecoin-project/go-state-types/big"
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
big2 "github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
|
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||||
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var zero = types.NewInt(0)
|
var zero = types.NewInt(0)
|
||||||
|
|
||||||
func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
func Weight(ctx context.Context, stateBs bstore.Blockstore, ts *types.TipSet) (types.BigInt, error) {
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
return types.NewInt(0), nil
|
return types.NewInt(0), nil
|
||||||
}
|
}
|
||||||
@ -28,7 +31,7 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
|||||||
|
|
||||||
tpow := big2.Zero()
|
tpow := big2.Zero()
|
||||||
{
|
{
|
||||||
cst := cbor.NewCborStore(cs.StateBlockstore())
|
cst := cbor.NewCborStore(stateBs)
|
||||||
state, err := state.LoadStateTree(cst, ts.ParentState())
|
state, err := state.LoadStateTree(cst, ts.ParentState())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.NewInt(0), xerrors.Errorf("load state tree: %w", err)
|
return types.NewInt(0), xerrors.Errorf("load state tree: %w", err)
|
||||||
@ -39,7 +42,7 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
|||||||
return types.NewInt(0), xerrors.Errorf("get power actor: %w", err)
|
return types.NewInt(0), xerrors.Errorf("get power actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
powState, err := power.Load(cs.ActorStore(ctx), act)
|
powState, err := power.Load(store.ActorStore(ctx, stateBs), act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.NewInt(0), xerrors.Errorf("failed to load power actor state: %w", err)
|
return types.NewInt(0), xerrors.Errorf("failed to load power actor state: %w", err)
|
||||||
}
|
}
|
19
chain/consensus/iface.go
Normal file
19
chain/consensus/iface.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package consensus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Consensus interface {
|
||||||
|
ValidateBlock(ctx context.Context, b *types.FullBlock) (err error)
|
||||||
|
ValidateBlockPubsub(ctx context.Context, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string)
|
||||||
|
IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool
|
||||||
|
|
||||||
|
CreateBlock(ctx context.Context, w api.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error)
|
||||||
|
}
|
86
chain/consensus/utils.go
Normal file
86
chain/consensus/utils.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package consensus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
logging "github.com/ipfs/go-log/v2"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("consensus")
|
||||||
|
|
||||||
|
var ErrTemporal = errors.New("temporal error")
|
||||||
|
|
||||||
|
func VerifyBlsAggregate(ctx context.Context, sig *crypto.Signature, msgs []cid.Cid, pubks [][]byte) error {
|
||||||
|
_, span := trace.StartSpan(ctx, "syncer.VerifyBlsAggregate")
|
||||||
|
defer span.End()
|
||||||
|
span.AddAttributes(
|
||||||
|
trace.Int64Attribute("msgCount", int64(len(msgs))),
|
||||||
|
)
|
||||||
|
|
||||||
|
msgsS := make([]ffi.Message, len(msgs))
|
||||||
|
pubksS := make([]ffi.PublicKey, len(msgs))
|
||||||
|
for i := 0; i < len(msgs); i++ {
|
||||||
|
msgsS[i] = msgs[i].Bytes()
|
||||||
|
copy(pubksS[i][:], pubks[i][:ffi.PublicKeyBytes])
|
||||||
|
}
|
||||||
|
|
||||||
|
sigS := new(ffi.Signature)
|
||||||
|
copy(sigS[:], sig.Data[:ffi.SignatureBytes])
|
||||||
|
|
||||||
|
if len(msgs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
valid := ffi.HashVerify(sigS, msgsS, pubksS)
|
||||||
|
if !valid {
|
||||||
|
return xerrors.New("bls aggregate signature failed to verify")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
|
||||||
|
sigsS := make([]ffi.Signature, len(sigs))
|
||||||
|
for i := 0; i < len(sigs); i++ {
|
||||||
|
copy(sigsS[i][:], sigs[i].Data[:ffi.SignatureBytes])
|
||||||
|
}
|
||||||
|
|
||||||
|
aggSig := ffi.Aggregate(sigsS)
|
||||||
|
if aggSig == nil {
|
||||||
|
if len(sigs) > 0 {
|
||||||
|
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
|
||||||
|
}
|
||||||
|
|
||||||
|
zeroSig := ffi.CreateZeroSignature()
|
||||||
|
|
||||||
|
// Note: for blst this condition should not happen - nil should not
|
||||||
|
// be returned
|
||||||
|
return &crypto.Signature{
|
||||||
|
Type: crypto.SigTypeBLS,
|
||||||
|
Data: zeroSig[:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return &crypto.Signature{
|
||||||
|
Type: crypto.SigTypeBLS,
|
||||||
|
Data: aggSig[:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToMessagesArray(store blockadt.Store, cids []cid.Cid) (cid.Cid, error) {
|
||||||
|
arr := blockadt.MakeEmptyArray(store)
|
||||||
|
for i, c := range cids {
|
||||||
|
oc := cbg.CborCid(c)
|
||||||
|
if err := arr.Set(uint64(i), &oc); err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr.Root()
|
||||||
|
}
|
@ -151,12 +151,20 @@ func (c *client) doRequest(
|
|||||||
// errors. Peer penalization should happen here then, before returning, so
|
// errors. Peer penalization should happen here then, before returning, so
|
||||||
// we can apply the correct penalties depending on the cause of the error.
|
// we can apply the correct penalties depending on the cause of the error.
|
||||||
// FIXME: Add the `peer` as argument once we implement penalties.
|
// FIXME: Add the `peer` as argument once we implement penalties.
|
||||||
func (c *client) processResponse(req *Request, res *Response, tipsets []*types.TipSet) (*validatedResponse, error) {
|
func (c *client) processResponse(req *Request, res *Response, tipsets []*types.TipSet) (r *validatedResponse, err error) {
|
||||||
err := res.statusToError()
|
err = res.statusToError()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("status error: %s", err)
|
return nil, xerrors.Errorf("status error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if rerr := recover(); rerr != nil {
|
||||||
|
log.Errorf("process response error: %s", rerr)
|
||||||
|
err = xerrors.Errorf("process response error: %s", rerr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
options := parseOptions(req.Options)
|
options := parseOptions(req.Options)
|
||||||
if options.noOptionsSet() {
|
if options.noOptionsSet() {
|
||||||
// Safety check: this shouldn't have been sent, and even if it did
|
// Safety check: this shouldn't have been sent, and even if it did
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
"github.com/ipfs/go-merkledag"
|
"github.com/ipfs/go-merkledag"
|
||||||
"github.com/ipld/go-car"
|
"github.com/ipld/go-car"
|
||||||
"go.opencensus.io/trace"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof"
|
proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof"
|
||||||
@ -33,6 +32,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -43,7 +43,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||||
"github.com/filecoin-project/lotus/genesis"
|
"github.com/filecoin-project/lotus/genesis"
|
||||||
"github.com/filecoin-project/lotus/journal"
|
"github.com/filecoin-project/lotus/journal"
|
||||||
"github.com/filecoin-project/lotus/lib/sigs"
|
|
||||||
"github.com/filecoin-project/lotus/node/repo"
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -233,7 +232,7 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
|||||||
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, ds, j)
|
cs := store.NewChainStore(bs, bs, ds, filcns.Weight, j)
|
||||||
|
|
||||||
genfb := &types.FullBlock{Header: genb.Genesis}
|
genfb := &types.FullBlock{Header: genb.Genesis}
|
||||||
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
||||||
@ -247,7 +246,7 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
|||||||
mgen[genesis2.MinerAddress(uint64(i))] = &wppProvider{}
|
mgen[genesis2.MinerAddress(uint64(i))] = &wppProvider{}
|
||||||
}
|
}
|
||||||
|
|
||||||
sm, err := stmgr.NewStateManagerWithUpgradeSchedule(cs, sys, us)
|
sm, err := stmgr.NewStateManager(cs, filcns.TipSetExecutor(), sys, us)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("initing stmgr: %w", err)
|
return nil, xerrors.Errorf("initing stmgr: %w", err)
|
||||||
}
|
}
|
||||||
@ -289,7 +288,7 @@ func NewGenerator() (*ChainGen, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||||
return NewGeneratorWithSectorsAndUpgradeSchedule(numSectors, stmgr.DefaultUpgradeSchedule())
|
return NewGeneratorWithSectorsAndUpgradeSchedule(numSectors, filcns.DefaultUpgradeSchedule())
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGeneratorWithUpgradeSchedule(us stmgr.UpgradeSchedule) (*ChainGen, error) {
|
func NewGeneratorWithUpgradeSchedule(us stmgr.UpgradeSchedule) (*ChainGen, error) {
|
||||||
@ -487,7 +486,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
|||||||
ts = parents.MinTimestamp() + uint64(height-parents.Height())*build.BlockDelaySecs
|
ts = parents.MinTimestamp() + uint64(height-parents.Height())*build.BlockDelaySecs
|
||||||
}
|
}
|
||||||
|
|
||||||
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{
|
fblk, err := filcns.NewFilecoinExpectedConsensus(cg.sm, nil, nil, nil).CreateBlock(context.TODO(), cg.w, &api.BlockTemplate{
|
||||||
Miner: m,
|
Miner: m,
|
||||||
Parents: parents.Key(),
|
Parents: parents.Key(),
|
||||||
Ticket: vrfticket,
|
Ticket: vrfticket,
|
||||||
@ -667,22 +666,6 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
|||||||
|
|
||||||
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
||||||
|
|
||||||
func VerifyVRF(ctx context.Context, worker address.Address, vrfBase, vrfproof []byte) error {
|
|
||||||
_, span := trace.StartSpan(ctx, "VerifyVRF")
|
|
||||||
defer span.End()
|
|
||||||
|
|
||||||
sig := &crypto.Signature{
|
|
||||||
Type: crypto.SigTypeBLS,
|
|
||||||
Data: vrfproof,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sigs.Verify(sig, worker, vrfBase); err != nil {
|
|
||||||
return xerrors.Errorf("vrf was invalid: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ComputeVRF(ctx context.Context, sign SignFunc, worker address.Address, sigInput []byte) ([]byte, error) {
|
func ComputeVRF(ctx context.Context, sign SignFunc, worker address.Address, sigInput []byte) ([]byte, error) {
|
||||||
sig, err := sign(ctx, worker, sigInput)
|
sig, err := sign(ctx, worker, sigInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
@ -222,7 +223,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, xerrors.Errorf("set verified registry actor: %w", err)
|
return nil, nil, xerrors.Errorf("set verified registry actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bact, err := makeAccountActor(ctx, cst, av, builtin.BurntFundsActorAddr, big.Zero())
|
bact, err := MakeAccountActor(ctx, cst, av, builtin.BurntFundsActorAddr, big.Zero())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("setup burnt funds actor state: %w", err)
|
return nil, nil, xerrors.Errorf("setup burnt funds actor state: %w", err)
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
|
|
||||||
switch info.Type {
|
switch info.Type {
|
||||||
case genesis.TAccount:
|
case genesis.TAccount:
|
||||||
if err := createAccountActor(ctx, cst, state, info, keyIDs, av); err != nil {
|
if err := CreateAccountActor(ctx, cst, state, info, keyIDs, av); err != nil {
|
||||||
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
|
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +248,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
}
|
}
|
||||||
idStart++
|
idStart++
|
||||||
|
|
||||||
if err := createMultisigAccount(ctx, cst, state, ida, info, keyIDs, av); err != nil {
|
if err := CreateMultisigAccount(ctx, cst, state, ida, info, keyIDs, av); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -268,7 +269,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, fmt.Errorf("rootkey account has already been declared, cannot be assigned 80: %s", ainfo.Owner)
|
return nil, nil, fmt.Errorf("rootkey account has already been declared, cannot be assigned 80: %s", ainfo.Owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
vact, err := makeAccountActor(ctx, cst, av, ainfo.Owner, template.VerifregRootKey.Balance)
|
vact, err := MakeAccountActor(ctx, cst, av, ainfo.Owner, template.VerifregRootKey.Balance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("setup verifreg rootkey account state: %w", err)
|
return nil, nil, xerrors.Errorf("setup verifreg rootkey account state: %w", err)
|
||||||
}
|
}
|
||||||
@ -276,7 +277,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, xerrors.Errorf("set verifreg rootkey account actor: %w", err)
|
return nil, nil, xerrors.Errorf("set verifreg rootkey account actor: %w", err)
|
||||||
}
|
}
|
||||||
case genesis.TMultisig:
|
case genesis.TMultisig:
|
||||||
if err = createMultisigAccount(ctx, cst, state, builtin.RootVerifierAddress, template.VerifregRootKey, keyIDs, av); err != nil {
|
if err = CreateMultisigAccount(ctx, cst, state, builtin.RootVerifierAddress, template.VerifregRootKey, keyIDs, av); err != nil {
|
||||||
return nil, nil, xerrors.Errorf("failed to set up verified registry signer: %w", err)
|
return nil, nil, xerrors.Errorf("failed to set up verified registry signer: %w", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -305,7 +306,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
verifierAct, err := makeAccountActor(ctx, cst, av, verifierAd, big.Zero())
|
verifierAct, err := MakeAccountActor(ctx, cst, av, verifierAd, big.Zero())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("setup first verifier state: %w", err)
|
return nil, nil, xerrors.Errorf("setup first verifier state: %w", err)
|
||||||
}
|
}
|
||||||
@ -348,13 +349,13 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyIDs[ainfo.Owner] = builtin.ReserveAddress
|
keyIDs[ainfo.Owner] = builtin.ReserveAddress
|
||||||
err = createAccountActor(ctx, cst, state, template.RemainderAccount, keyIDs, av)
|
err = CreateAccountActor(ctx, cst, state, template.RemainderAccount, keyIDs, av)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("creating remainder acct: %w", err)
|
return nil, nil, xerrors.Errorf("creating remainder acct: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
case genesis.TMultisig:
|
case genesis.TMultisig:
|
||||||
if err = createMultisigAccount(ctx, cst, state, builtin.ReserveAddress, template.RemainderAccount, keyIDs, av); err != nil {
|
if err = CreateMultisigAccount(ctx, cst, state, builtin.ReserveAddress, template.RemainderAccount, keyIDs, av); err != nil {
|
||||||
return nil, nil, xerrors.Errorf("failed to set up remainder: %w", err)
|
return nil, nil, xerrors.Errorf("failed to set up remainder: %w", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -364,7 +365,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return state, keyIDs, nil
|
return state, keyIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAccountActor(ctx context.Context, cst cbor.IpldStore, av actors.Version, addr address.Address, bal types.BigInt) (*types.Actor, error) {
|
func MakeAccountActor(ctx context.Context, cst cbor.IpldStore, av actors.Version, addr address.Address, bal types.BigInt) (*types.Actor, error) {
|
||||||
ast, err := account.MakeState(adt.WrapStore(ctx, cst), av, addr)
|
ast, err := account.MakeState(adt.WrapStore(ctx, cst), av, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -389,13 +390,13 @@ func makeAccountActor(ctx context.Context, cst cbor.IpldStore, av actors.Version
|
|||||||
return act, nil
|
return act, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, info genesis.Actor, keyIDs map[address.Address]address.Address, av actors.Version) error {
|
func CreateAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, info genesis.Actor, keyIDs map[address.Address]address.Address, av actors.Version) error {
|
||||||
var ainfo genesis.AccountMeta
|
var ainfo genesis.AccountMeta
|
||||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||||
return xerrors.Errorf("unmarshaling account meta: %w", err)
|
return xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
aa, err := makeAccountActor(ctx, cst, av, ainfo.Owner, info.Balance)
|
aa, err := MakeAccountActor(ctx, cst, av, ainfo.Owner, info.Balance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -412,9 +413,9 @@ func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.St
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMultisigAccount(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address, av actors.Version) error {
|
func CreateMultisigAccount(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address, av actors.Version) error {
|
||||||
if info.Type != genesis.TMultisig {
|
if info.Type != genesis.TMultisig {
|
||||||
return fmt.Errorf("can only call createMultisigAccount with multisig Actor info")
|
return fmt.Errorf("can only call CreateMultisigAccount with multisig Actor info")
|
||||||
}
|
}
|
||||||
var ainfo genesis.MultisigMeta
|
var ainfo genesis.MultisigMeta
|
||||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||||
@ -436,7 +437,7 @@ func createMultisigAccount(ctx context.Context, cst cbor.IpldStore, state *state
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
aa, err := makeAccountActor(ctx, cst, av, e, big.Zero())
|
aa, err := MakeAccountActor(ctx, cst, av, e, big.Zero())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -483,6 +484,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.Sysca
|
|||||||
Epoch: 0,
|
Epoch: 0,
|
||||||
Rand: &fakeRand{},
|
Rand: &fakeRand{},
|
||||||
Bstore: cs.StateBlockstore(),
|
Bstore: cs.StateBlockstore(),
|
||||||
|
Actors: filcns.NewActorRegistry(),
|
||||||
Syscalls: mkFakedSigSyscalls(sys),
|
Syscalls: mkFakedSigSyscalls(sys),
|
||||||
CircSupplyCalc: nil,
|
CircSupplyCalc: nil,
|
||||||
NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version {
|
NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version {
|
||||||
@ -562,7 +564,7 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto
|
|||||||
}
|
}
|
||||||
|
|
||||||
// temp chainstore
|
// temp chainstore
|
||||||
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), j)
|
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), nil, j)
|
||||||
|
|
||||||
// Verify PreSealed Data
|
// Verify PreSealed Data
|
||||||
stateroot, err = VerifyPreSealedData(ctx, cs, sys, stateroot, template, keyIDs, template.NetworkVersion)
|
stateroot, err = VerifyPreSealedData(ctx, cs, sys, stateroot, template, keyIDs, template.NetworkVersion)
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -87,6 +88,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal
|
|||||||
Epoch: 0,
|
Epoch: 0,
|
||||||
Rand: &fakeRand{},
|
Rand: &fakeRand{},
|
||||||
Bstore: cs.StateBlockstore(),
|
Bstore: cs.StateBlockstore(),
|
||||||
|
Actors: filcns.NewActorRegistry(),
|
||||||
Syscalls: mkFakedSigSyscalls(sys),
|
Syscalls: mkFakedSigSyscalls(sys),
|
||||||
CircSupplyCalc: csc,
|
CircSupplyCalc: csc,
|
||||||
NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version {
|
NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version {
|
||||||
|
@ -354,7 +354,7 @@ func (ms *msgSet) toSlice() []*types.SignedMessage {
|
|||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journal.Journal) (*MessagePool, error) {
|
func New(api Provider, ds dtypes.MetadataDS, us stmgr.UpgradeSchedule, netName dtypes.NetworkName, j journal.Journal) (*MessagePool, error) {
|
||||||
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
||||||
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
||||||
|
|
||||||
@ -366,7 +366,6 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journ
|
|||||||
if j == nil {
|
if j == nil {
|
||||||
j = journal.NilJournal()
|
j = journal.NilJournal()
|
||||||
}
|
}
|
||||||
us := stmgr.DefaultUpgradeSchedule()
|
|
||||||
|
|
||||||
mp := &MessagePool{
|
mp := &MessagePool{
|
||||||
ds: ds,
|
ds: ds,
|
||||||
|
@ -11,17 +11,18 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -232,7 +233,7 @@ func TestMessagePool(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -276,7 +277,7 @@ func TestCheckMessageBig(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
to := mock.Address(1001)
|
to := mock.Address(1001)
|
||||||
@ -339,7 +340,7 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -388,7 +389,7 @@ func TestRevertMessages(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -451,7 +452,7 @@ func TestPruningSimple(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -495,7 +496,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -538,7 +539,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mp, err = New(tma, ds, "mptest", nil)
|
mp, err = New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -567,7 +568,7 @@ func TestClearAll(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -621,7 +622,7 @@ func TestClearNonLocal(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -682,7 +683,7 @@ func TestUpdates(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
@ -24,7 +25,7 @@ func TestRepubMessages(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@ import (
|
|||||||
|
|
||||||
var bigBlockGasLimit = big.NewInt(build.BlockGasLimit)
|
var bigBlockGasLimit = big.NewInt(build.BlockGasLimit)
|
||||||
|
|
||||||
var MaxBlockMessages = 16000
|
|
||||||
|
|
||||||
const MaxBlocks = 15
|
const MaxBlocks = 15
|
||||||
|
|
||||||
type msgChain struct {
|
type msgChain struct {
|
||||||
@ -58,8 +56,8 @@ func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(msgs) > MaxBlockMessages {
|
if len(msgs) > build.BlockMessageLimit {
|
||||||
msgs = msgs[:MaxBlockMessages]
|
msgs = msgs[:build.BlockMessageLimit]
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs, nil
|
return msgs, nil
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||||
@ -60,7 +61,7 @@ func makeTestMessage(w *wallet.LocalWallet, from, to address.Address, nonce uint
|
|||||||
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
|
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
|
||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
mp, err := New(tma, ds, "test", nil)
|
mp, err := New(tma, ds, filcns.DefaultUpgradeSchedule(), "test", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
|||||||
bstate := ts.ParentState()
|
bstate := ts.ParentState()
|
||||||
|
|
||||||
// Run the (not expensive) migration.
|
// Run the (not expensive) migration.
|
||||||
bstate, err := sm.handleStateForks(ctx, bstate, pheight, nil, ts)
|
bstate, err := sm.HandleStateForks(ctx, bstate, pheight, nil, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||||
}
|
}
|
||||||
@ -76,7 +76,8 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
|||||||
Epoch: pheight + 1,
|
Epoch: pheight + 1,
|
||||||
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||||
Bstore: sm.cs.StateBlockstore(),
|
Bstore: sm.cs.StateBlockstore(),
|
||||||
Syscalls: sm.syscalls,
|
Actors: sm.tsExec.NewActorRegistry(),
|
||||||
|
Syscalls: sm.Syscalls,
|
||||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: types.NewInt(0),
|
BaseFee: types.NewInt(0),
|
||||||
@ -179,7 +180,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Technically, the tipset we're passing in here should be ts+1, but that may not exist.
|
// Technically, the tipset we're passing in here should be ts+1, but that may not exist.
|
||||||
state, err = sm.handleStateForks(ctx, state, ts.Height(), nil, ts)
|
state, err = sm.HandleStateForks(ctx, state, ts.Height(), nil, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||||
}
|
}
|
||||||
@ -199,7 +200,8 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
Epoch: ts.Height() + 1,
|
Epoch: ts.Height() + 1,
|
||||||
Rand: r,
|
Rand: r,
|
||||||
Bstore: sm.cs.StateBlockstore(),
|
Bstore: sm.cs.StateBlockstore(),
|
||||||
Syscalls: sm.syscalls,
|
Actors: sm.tsExec.NewActorRegistry(),
|
||||||
|
Syscalls: sm.Syscalls,
|
||||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
@ -272,7 +274,7 @@ func (sm *StateManager) Replay(ctx context.Context, ts *types.TipSet, mcid cid.C
|
|||||||
// message to find
|
// message to find
|
||||||
finder.mcid = mcid
|
finder.mcid = mcid
|
||||||
|
|
||||||
_, _, err := sm.computeTipSetState(ctx, ts, &finder)
|
_, _, err := sm.tsExec.ExecuteTipSet(ctx, sm, ts, &finder)
|
||||||
if err != nil && !xerrors.Is(err, errHaltExecution) {
|
if err != nil && !xerrors.Is(err, errHaltExecution) {
|
||||||
return nil, nil, xerrors.Errorf("unexpected error during execution: %w", err)
|
return nil, nil, xerrors.Errorf("unexpected error during execution: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -3,217 +3,14 @@ package stmgr
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
"go.opencensus.io/stats"
|
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
|
||||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/cron"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
|
||||||
"github.com/filecoin-project/lotus/metrics"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, em ExecMonitor, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) {
|
|
||||||
done := metrics.Timer(ctx, metrics.VMApplyBlocksTotal)
|
|
||||||
defer done()
|
|
||||||
|
|
||||||
partDone := metrics.Timer(ctx, metrics.VMApplyEarly)
|
|
||||||
defer func() {
|
|
||||||
partDone()
|
|
||||||
}()
|
|
||||||
|
|
||||||
makeVmWithBaseState := func(base cid.Cid) (*vm.VM, error) {
|
|
||||||
vmopt := &vm.VMOpts{
|
|
||||||
StateBase: base,
|
|
||||||
Epoch: epoch,
|
|
||||||
Rand: r,
|
|
||||||
Bstore: sm.cs.StateBlockstore(),
|
|
||||||
Syscalls: sm.syscalls,
|
|
||||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
|
||||||
BaseFee: baseFee,
|
|
||||||
LookbackState: LookbackStateGetterForTipset(sm, ts),
|
|
||||||
}
|
|
||||||
|
|
||||||
return sm.newVM(ctx, vmopt)
|
|
||||||
}
|
|
||||||
|
|
||||||
vmi, err := makeVmWithBaseState(pstate)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
runCron := func(epoch abi.ChainEpoch) error {
|
|
||||||
cronMsg := &types.Message{
|
|
||||||
To: cron.Address,
|
|
||||||
From: builtin.SystemActorAddr,
|
|
||||||
Nonce: uint64(epoch),
|
|
||||||
Value: types.NewInt(0),
|
|
||||||
GasFeeCap: types.NewInt(0),
|
|
||||||
GasPremium: types.NewInt(0),
|
|
||||||
GasLimit: build.BlockGasLimit * 10000, // Make super sure this is never too little
|
|
||||||
Method: cron.Methods.EpochTick,
|
|
||||||
Params: nil,
|
|
||||||
}
|
|
||||||
ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if em != nil {
|
|
||||||
if err := em.MessageApplied(ctx, ts, cronMsg.Cid(), cronMsg, ret, true); err != nil {
|
|
||||||
return xerrors.Errorf("callback failed on cron message: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ret.ExitCode != 0 {
|
|
||||||
return xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := parentEpoch; i < epoch; i++ {
|
|
||||||
if i > parentEpoch {
|
|
||||||
// run cron for null rounds if any
|
|
||||||
if err := runCron(i); err != nil {
|
|
||||||
return cid.Undef, cid.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pstate, err = vmi.Flush(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle state forks
|
|
||||||
newState, err := sm.handleStateForks(ctx, pstate, i, em, ts)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pstate != newState {
|
|
||||||
vmi, err = makeVmWithBaseState(newState)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vmi.SetBlockHeight(i + 1)
|
|
||||||
pstate = newState
|
|
||||||
}
|
|
||||||
|
|
||||||
partDone()
|
|
||||||
partDone = metrics.Timer(ctx, metrics.VMApplyMessages)
|
|
||||||
|
|
||||||
var receipts []cbg.CBORMarshaler
|
|
||||||
processedMsgs := make(map[cid.Cid]struct{})
|
|
||||||
for _, b := range bms {
|
|
||||||
penalty := types.NewInt(0)
|
|
||||||
gasReward := big.Zero()
|
|
||||||
|
|
||||||
for _, cm := range append(b.BlsMessages, b.SecpkMessages...) {
|
|
||||||
m := cm.VMMessage()
|
|
||||||
if _, found := processedMsgs[m.Cid()]; found {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r, err := vmi.ApplyMessage(ctx, cm)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
receipts = append(receipts, &r.MessageReceipt)
|
|
||||||
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
|
|
||||||
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
|
|
||||||
|
|
||||||
if em != nil {
|
|
||||||
if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil {
|
|
||||||
return cid.Undef, cid.Undef, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processedMsgs[m.Cid()] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
|
||||||
Miner: b.Miner,
|
|
||||||
Penalty: penalty,
|
|
||||||
GasReward: gasReward,
|
|
||||||
WinCount: b.WinCount,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rwMsg := &types.Message{
|
|
||||||
From: builtin.SystemActorAddr,
|
|
||||||
To: reward.Address,
|
|
||||||
Nonce: uint64(epoch),
|
|
||||||
Value: types.NewInt(0),
|
|
||||||
GasFeeCap: types.NewInt(0),
|
|
||||||
GasPremium: types.NewInt(0),
|
|
||||||
GasLimit: 1 << 30,
|
|
||||||
Method: reward.Methods.AwardBlockReward,
|
|
||||||
Params: params,
|
|
||||||
}
|
|
||||||
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
|
||||||
if actErr != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr)
|
|
||||||
}
|
|
||||||
if em != nil {
|
|
||||||
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on reward message: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ret.ExitCode != 0 {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
partDone()
|
|
||||||
partDone = metrics.Timer(ctx, metrics.VMApplyCron)
|
|
||||||
|
|
||||||
if err := runCron(epoch); err != nil {
|
|
||||||
return cid.Cid{}, cid.Cid{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
partDone()
|
|
||||||
partDone = metrics.Timer(ctx, metrics.VMApplyFlush)
|
|
||||||
|
|
||||||
rectarr := blockadt.MakeEmptyArray(sm.cs.ActorStore(ctx))
|
|
||||||
for i, receipt := range receipts {
|
|
||||||
if err := rectarr.Set(uint64(i), receipt); err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rectroot, err := rectarr.Root()
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
st, err := vmi.Flush(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("vm flush failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stats.Record(ctx, metrics.VMSends.M(int64(atomic.LoadUint64(&vm.StatSends))),
|
|
||||||
metrics.VMApplied.M(int64(atomic.LoadUint64(&vm.StatApplied))))
|
|
||||||
|
|
||||||
return st, rectroot, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st cid.Cid, rec cid.Cid, err error) {
|
func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st cid.Cid, rec cid.Cid, err error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "tipSetState")
|
ctx, span := trace.StartSpan(ctx, "tipSetState")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@ -263,7 +60,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
|
|||||||
return ts.Blocks()[0].ParentStateRoot, ts.Blocks()[0].ParentMessageReceipts, nil
|
return ts.Blocks()[0].ParentStateRoot, ts.Blocks()[0].ParentMessageReceipts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
st, rec, err = sm.computeTipSetState(ctx, ts, sm.tsExecMonitor)
|
st, rec, err = sm.tsExec.ExecuteTipSet(ctx, sm, ts, sm.tsExecMonitor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, cid.Undef, err
|
return cid.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
@ -272,7 +69,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) ExecutionTraceWithMonitor(ctx context.Context, ts *types.TipSet, em ExecMonitor) (cid.Cid, error) {
|
func (sm *StateManager) ExecutionTraceWithMonitor(ctx context.Context, ts *types.TipSet, em ExecMonitor) (cid.Cid, error) {
|
||||||
st, _, err := sm.computeTipSetState(ctx, ts, em)
|
st, _, err := sm.tsExec.ExecuteTipSet(ctx, sm, ts, em)
|
||||||
return st, err
|
return st, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,42 +81,3 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
|
|||||||
}
|
}
|
||||||
return st, invocTrace, nil
|
return st, invocTrace, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet, em ExecMonitor) (cid.Cid, cid.Cid, error) {
|
|
||||||
ctx, span := trace.StartSpan(ctx, "computeTipSetState")
|
|
||||||
defer span.End()
|
|
||||||
|
|
||||||
blks := ts.Blocks()
|
|
||||||
|
|
||||||
for i := 0; i < len(blks); i++ {
|
|
||||||
for j := i + 1; j < len(blks); j++ {
|
|
||||||
if blks[i].Miner == blks[j].Miner {
|
|
||||||
return cid.Undef, cid.Undef,
|
|
||||||
xerrors.Errorf("duplicate miner in a tipset (%s %s)",
|
|
||||||
blks[i].Miner, blks[j].Miner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var parentEpoch abi.ChainEpoch
|
|
||||||
pstate := blks[0].ParentStateRoot
|
|
||||||
if blks[0].Height > 0 {
|
|
||||||
parent, err := sm.cs.GetBlock(blks[0].Parents[0])
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("getting parent block: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentEpoch = parent.Height
|
|
||||||
}
|
|
||||||
|
|
||||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
|
||||||
|
|
||||||
blkmsgs, err := sm.cs.BlockMsgsForTipset(ts)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, cid.Undef, xerrors.Errorf("getting block messages for tipset: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
baseFee := blks[0].ParentBaseFee
|
|
||||||
|
|
||||||
return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, em, baseFee, ts)
|
|
||||||
}
|
|
||||||
|
@ -15,8 +15,6 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/filecoin-project/go-state-types/rt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/v3/actors/migration/nv10"
|
"github.com/filecoin-project/specs-actors/v3/actors/migration/nv10"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
@ -98,21 +96,6 @@ type Upgrade struct {
|
|||||||
|
|
||||||
type UpgradeSchedule []Upgrade
|
type UpgradeSchedule []Upgrade
|
||||||
|
|
||||||
type migrationLogger struct{}
|
|
||||||
|
|
||||||
func (ml migrationLogger) Log(level rt.LogLevel, msg string, args ...interface{}) {
|
|
||||||
switch level {
|
|
||||||
case rt.DEBUG:
|
|
||||||
log.Debugf(msg, args...)
|
|
||||||
case rt.INFO:
|
|
||||||
log.Infof(msg, args...)
|
|
||||||
case rt.WARN:
|
|
||||||
log.Warnf(msg, args...)
|
|
||||||
case rt.ERROR:
|
|
||||||
log.Errorf(msg, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (us UpgradeSchedule) Validate() error {
|
func (us UpgradeSchedule) Validate() error {
|
||||||
// Make sure each upgrade is valid.
|
// Make sure each upgrade is valid.
|
||||||
for _, u := range us {
|
for _, u := range us {
|
||||||
@ -181,7 +164,7 @@ func (us UpgradeSchedule) GetNtwkVersion(e abi.ChainEpoch) (network.Version, err
|
|||||||
return network.Version0, xerrors.Errorf("Epoch %d has no defined network version", e)
|
return network.Version0, xerrors.Errorf("Epoch %d has no defined network version", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecMonitor, ts *types.TipSet) (cid.Cid, error) {
|
func (sm *StateManager) HandleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecMonitor, ts *types.TipSet) (cid.Cid, error) {
|
||||||
retCid := root
|
retCid := root
|
||||||
var err error
|
var err error
|
||||||
u := sm.stateMigrations[height]
|
u := sm.stateMigrations[height]
|
||||||
@ -331,7 +314,7 @@ func (sm *StateManager) preMigrationWorker(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount, cb func(trace types.ExecutionTrace)) error {
|
func DoTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount, cb func(trace types.ExecutionTrace)) error {
|
||||||
fromAct, err := tree.GetActor(from)
|
fromAct, err := tree.GetActor(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
|
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
|
||||||
@ -361,8 +344,8 @@ func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmo
|
|||||||
// record the transfer in execution traces
|
// record the transfer in execution traces
|
||||||
|
|
||||||
cb(types.ExecutionTrace{
|
cb(types.ExecutionTrace{
|
||||||
Msg: makeFakeMsg(from, to, amt, 0),
|
Msg: MakeFakeMsg(from, to, amt, 0),
|
||||||
MsgRct: makeFakeRct(),
|
MsgRct: MakeFakeRct(),
|
||||||
Error: "",
|
Error: "",
|
||||||
Duration: 0,
|
Duration: 0,
|
||||||
GasCharges: nil,
|
GasCharges: nil,
|
||||||
@ -373,7 +356,7 @@ func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func terminateActor(ctx context.Context, tree *state.StateTree, addr address.Address, em ExecMonitor, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
func TerminateActor(ctx context.Context, tree *state.StateTree, addr address.Address, em ExecMonitor, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
||||||
a, err := tree.GetActor(addr)
|
a, err := tree.GetActor(addr)
|
||||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
return types.ErrActorNotFound
|
return types.ErrActorNotFound
|
||||||
@ -382,7 +365,7 @@ func terminateActor(ctx context.Context, tree *state.StateTree, addr address.Add
|
|||||||
}
|
}
|
||||||
|
|
||||||
var trace types.ExecutionTrace
|
var trace types.ExecutionTrace
|
||||||
if err := doTransfer(tree, addr, builtin.BurntFundsActorAddr, a.Balance, func(t types.ExecutionTrace) {
|
if err := DoTransfer(tree, addr, builtin.BurntFundsActorAddr, a.Balance, func(t types.ExecutionTrace) {
|
||||||
trace = t
|
trace = t
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return xerrors.Errorf("transferring terminated actor's balance: %w", err)
|
return xerrors.Errorf("transferring terminated actor's balance: %w", err)
|
||||||
@ -391,10 +374,10 @@ func terminateActor(ctx context.Context, tree *state.StateTree, addr address.Add
|
|||||||
if em != nil {
|
if em != nil {
|
||||||
// record the transfer in execution traces
|
// record the transfer in execution traces
|
||||||
|
|
||||||
fakeMsg := makeFakeMsg(builtin.SystemActorAddr, addr, big.Zero(), uint64(epoch))
|
fakeMsg := MakeFakeMsg(builtin.SystemActorAddr, addr, big.Zero(), uint64(epoch))
|
||||||
|
|
||||||
if err := em.MessageApplied(ctx, ts, fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
if err := em.MessageApplied(ctx, ts, fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||||
MessageReceipt: *makeFakeRct(),
|
MessageReceipt: *MakeFakeRct(),
|
||||||
ActorErr: nil,
|
ActorErr: nil,
|
||||||
ExecutionTrace: trace,
|
ExecutionTrace: trace,
|
||||||
Duration: 0,
|
Duration: 0,
|
||||||
@ -433,7 +416,7 @@ func terminateActor(ctx context.Context, tree *state.StateTree, addr address.Add
|
|||||||
return tree.SetActor(init_.Address, ia)
|
return tree.SetActor(init_.Address, ia)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree, name string) error {
|
func SetNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree, name string) error {
|
||||||
ia, err := tree.GetActor(init_.Address)
|
ia, err := tree.GetActor(init_.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting init actor: %w", err)
|
return xerrors.Errorf("getting init actor: %w", err)
|
||||||
@ -460,7 +443,7 @@ func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, error) {
|
func MakeKeyAddr(splitAddr address.Address, count uint64) (address.Address, error) {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := splitAddr.MarshalCBOR(&b); err != nil {
|
if err := splitAddr.MarshalCBOR(&b); err != nil {
|
||||||
return address.Undef, xerrors.Errorf("marshalling split address: %w", err)
|
return address.Undef, xerrors.Errorf("marshalling split address: %w", err)
|
||||||
@ -482,7 +465,7 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
|
|||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeFakeMsg(from address.Address, to address.Address, amt abi.TokenAmount, nonce uint64) *types.Message {
|
func MakeFakeMsg(from address.Address, to address.Address, amt abi.TokenAmount, nonce uint64) *types.Message {
|
||||||
return &types.Message{
|
return &types.Message{
|
||||||
From: from,
|
From: from,
|
||||||
To: to,
|
To: to,
|
||||||
@ -491,7 +474,7 @@ func makeFakeMsg(from address.Address, to address.Address, amt abi.TokenAmount,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeFakeRct() *types.MessageReceipt {
|
func MakeFakeRct() *types.MessageReceipt {
|
||||||
return &types.MessageReceipt{
|
return &types.MessageReceipt{
|
||||||
ExitCode: 0,
|
ExitCode: 0,
|
||||||
Return: nil,
|
Return: nil,
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
. "github.com/filecoin-project/lotus/chain/stmgr"
|
. "github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -120,8 +121,8 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
sm, err := NewStateManager(
|
||||||
cg.ChainStore(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
cg.ChainStore(), filcns.TipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||||
Network: network.Version1,
|
Network: network.Version1,
|
||||||
Height: testForkHeight,
|
Height: testForkHeight,
|
||||||
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
||||||
@ -162,7 +163,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inv := vm.NewActorRegistry()
|
inv := filcns.NewActorRegistry()
|
||||||
inv.Register(nil, testActor{})
|
inv.Register(nil, testActor{})
|
||||||
|
|
||||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||||
@ -263,8 +264,8 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var migrationCount int
|
var migrationCount int
|
||||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
sm, err := NewStateManager(
|
||||||
cg.ChainStore(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
cg.ChainStore(), filcns.TipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||||
Network: network.Version1,
|
Network: network.Version1,
|
||||||
Expensive: true,
|
Expensive: true,
|
||||||
Height: testForkHeight,
|
Height: testForkHeight,
|
||||||
@ -277,7 +278,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inv := vm.NewActorRegistry()
|
inv := filcns.NewActorRegistry()
|
||||||
inv.Register(nil, testActor{})
|
inv.Register(nil, testActor{})
|
||||||
|
|
||||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||||
@ -398,8 +399,8 @@ func TestForkPreMigration(t *testing.T) {
|
|||||||
|
|
||||||
counter := make(chan struct{}, 10)
|
counter := make(chan struct{}, 10)
|
||||||
|
|
||||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
sm, err := NewStateManager(
|
||||||
cg.ChainStore(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
cg.ChainStore(), filcns.TipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||||
Network: network.Version1,
|
Network: network.Version1,
|
||||||
Height: testForkHeight,
|
Height: testForkHeight,
|
||||||
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
||||||
@ -496,7 +497,7 @@ func TestForkPreMigration(t *testing.T) {
|
|||||||
require.NoError(t, sm.Stop(context.Background()))
|
require.NoError(t, sm.Stop(context.Background()))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
inv := vm.NewActorRegistry()
|
inv := filcns.NewActorRegistry()
|
||||||
inv.Register(nil, testActor{})
|
inv.Register(nil, testActor{})
|
||||||
|
|
||||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||||
|
@ -2,7 +2,6 @@ package stmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
@ -52,6 +51,11 @@ type migration struct {
|
|||||||
cache *nv10.MemMigrationCache
|
cache *nv10.MemMigrationCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Executor interface {
|
||||||
|
NewActorRegistry() *vm.ActorRegistry
|
||||||
|
ExecuteTipSet(ctx context.Context, sm *StateManager, ts *types.TipSet, em ExecMonitor) (stateroot cid.Cid, rectsroot cid.Cid, err error)
|
||||||
|
}
|
||||||
|
|
||||||
type StateManager struct {
|
type StateManager struct {
|
||||||
cs *store.ChainStore
|
cs *store.ChainStore
|
||||||
|
|
||||||
@ -75,7 +79,7 @@ type StateManager struct {
|
|||||||
stlk sync.Mutex
|
stlk sync.Mutex
|
||||||
genesisMsigLk sync.Mutex
|
genesisMsigLk sync.Mutex
|
||||||
newVM func(context.Context, *vm.VMOpts) (*vm.VM, error)
|
newVM func(context.Context, *vm.VMOpts) (*vm.VM, error)
|
||||||
syscalls vm.SyscallBuilder
|
Syscalls vm.SyscallBuilder
|
||||||
preIgnitionVesting []msig0.State
|
preIgnitionVesting []msig0.State
|
||||||
postIgnitionVesting []msig0.State
|
postIgnitionVesting []msig0.State
|
||||||
postCalicoVesting []msig0.State
|
postCalicoVesting []msig0.State
|
||||||
@ -83,6 +87,7 @@ type StateManager struct {
|
|||||||
genesisPledge abi.TokenAmount
|
genesisPledge abi.TokenAmount
|
||||||
genesisMarketFunds abi.TokenAmount
|
genesisMarketFunds abi.TokenAmount
|
||||||
|
|
||||||
|
tsExec Executor
|
||||||
tsExecMonitor ExecMonitor
|
tsExecMonitor ExecMonitor
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,15 +97,7 @@ type treeCache struct {
|
|||||||
tree *state.StateTree
|
tree *state.StateTree
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateManager(cs *store.ChainStore, sys vm.SyscallBuilder) *StateManager {
|
func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule) (*StateManager, error) {
|
||||||
sm, err := NewStateManagerWithUpgradeSchedule(cs, sys, DefaultUpgradeSchedule())
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("default upgrade schedule is invalid: %s", err))
|
|
||||||
}
|
|
||||||
return sm
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, sys vm.SyscallBuilder, us UpgradeSchedule) (*StateManager, error) {
|
|
||||||
// If we have upgrades, make sure they're in-order and make sense.
|
// If we have upgrades, make sure they're in-order and make sense.
|
||||||
if err := us.Validate(); err != nil {
|
if err := us.Validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -142,8 +139,9 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, sys vm.SyscallBuil
|
|||||||
stateMigrations: stateMigrations,
|
stateMigrations: stateMigrations,
|
||||||
expensiveUpgrades: expensiveUpgrades,
|
expensiveUpgrades: expensiveUpgrades,
|
||||||
newVM: vm.NewVM,
|
newVM: vm.NewVM,
|
||||||
syscalls: sys,
|
Syscalls: sys,
|
||||||
cs: cs,
|
cs: cs,
|
||||||
|
tsExec: exec,
|
||||||
stCache: make(map[string][]cid.Cid),
|
stCache: make(map[string][]cid.Cid),
|
||||||
tCache: treeCache{
|
tCache: treeCache{
|
||||||
root: cid.Undef,
|
root: cid.Undef,
|
||||||
@ -153,8 +151,8 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, sys vm.SyscallBuil
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateManagerWithUpgradeScheduleAndMonitor(cs *store.ChainStore, sys vm.SyscallBuilder, us UpgradeSchedule, em ExecMonitor) (*StateManager, error) {
|
func NewStateManagerWithUpgradeScheduleAndMonitor(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, em ExecMonitor) (*StateManager, error) {
|
||||||
sm, err := NewStateManagerWithUpgradeSchedule(cs, sys, us)
|
sm, err := NewStateManager(cs, exec, sys, us)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -344,6 +342,12 @@ func (sm *StateManager) SetVMConstructor(nvm func(context.Context, *vm.VMOpts) (
|
|||||||
sm.newVM = nvm
|
sm.newVM = nvm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) VMConstructor() func(context.Context, *vm.VMOpts) (*vm.VM, error) {
|
||||||
|
return func(ctx context.Context, opts *vm.VMOpts) (*vm.VM, error) {
|
||||||
|
return sm.newVM(ctx, opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||||
// The epochs here are the _last_ epoch for every version, or -1 if the
|
// The epochs here are the _last_ epoch for every version, or -1 if the
|
||||||
// version is disabled.
|
// version is disabled.
|
||||||
@ -356,5 +360,5 @@ func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) VMSys() vm.SyscallBuilder {
|
func (sm *StateManager) VMSys() vm.SyscallBuilder {
|
||||||
return sm.syscalls
|
return sm.Syscalls
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
@ -14,16 +12,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/rt"
|
|
||||||
|
|
||||||
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
|
||||||
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
|
||||||
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
|
|
||||||
exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported"
|
|
||||||
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
|
||||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
@ -33,70 +22,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MethodMeta struct {
|
var MethodsMap map[cid.Cid]map[abi.MethodNum]vm.MethodMeta
|
||||||
Name string
|
|
||||||
|
|
||||||
Params reflect.Type
|
|
||||||
Ret reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// TODO: combine with the runtime actor registry.
|
|
||||||
var actors []rt.VMActor
|
|
||||||
actors = append(actors, exported0.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported2.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported3.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported4.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported5.BuiltinActors()...)
|
|
||||||
|
|
||||||
for _, actor := range actors {
|
|
||||||
exports := actor.Exports()
|
|
||||||
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
|
||||||
|
|
||||||
// Explicitly add send, it's special.
|
|
||||||
methods[builtin.MethodSend] = MethodMeta{
|
|
||||||
Name: "Send",
|
|
||||||
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
|
||||||
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate over exported methods. Some of these _may_ be nil and
|
|
||||||
// must be skipped.
|
|
||||||
for number, export := range exports {
|
|
||||||
if export == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ev := reflect.ValueOf(export)
|
|
||||||
et := ev.Type()
|
|
||||||
|
|
||||||
// Extract the method names using reflection. These
|
|
||||||
// method names always match the field names in the
|
|
||||||
// `builtin.Method*` structs (tested in the specs-actors
|
|
||||||
// tests).
|
|
||||||
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
|
||||||
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
|
||||||
|
|
||||||
switch abi.MethodNum(number) {
|
|
||||||
case builtin.MethodSend:
|
|
||||||
panic("method 0 is reserved for Send")
|
|
||||||
case builtin.MethodConstructor:
|
|
||||||
if fnName != "Constructor" {
|
|
||||||
panic("method 1 is reserved for Constructor")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
methods[abi.MethodNum(number)] = MethodMeta{
|
|
||||||
Name: fnName,
|
|
||||||
Params: et.In(1),
|
|
||||||
Ret: et.Out(0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MethodsMap[actor.Code()] = methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
||||||
act, err := sm.LoadActor(ctx, to, ts)
|
act, err := sm.LoadActor(ctx, to, ts)
|
||||||
@ -104,15 +30,15 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
|||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, found := MethodsMap[act.Code][method]
|
m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
||||||
}
|
}
|
||||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetParamType(actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) {
|
func GetParamType(ar *vm.ActorRegistry, actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) {
|
||||||
m, found := MethodsMap[actCode][method]
|
m, found := ar.Methods[actCode][method]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, actCode)
|
return nil, fmt.Errorf("unknown method %d for actor %s", method, actCode)
|
||||||
}
|
}
|
||||||
@ -144,7 +70,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
|||||||
|
|
||||||
for i := ts.Height(); i < height; i++ {
|
for i := ts.Height(); i < height; i++ {
|
||||||
// Technically, the tipset we're passing in here should be ts+1, but that may not exist.
|
// Technically, the tipset we're passing in here should be ts+1, but that may not exist.
|
||||||
base, err = sm.handleStateForks(ctx, base, i, &InvocationTracer{trace: &trace}, ts)
|
base, err = sm.HandleStateForks(ctx, base, i, &InvocationTracer{trace: &trace}, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err)
|
return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err)
|
||||||
}
|
}
|
||||||
@ -159,7 +85,8 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
|||||||
Epoch: height,
|
Epoch: height,
|
||||||
Rand: r,
|
Rand: r,
|
||||||
Bstore: sm.cs.StateBlockstore(),
|
Bstore: sm.cs.StateBlockstore(),
|
||||||
Syscalls: sm.syscalls,
|
Actors: sm.tsExec.NewActorRegistry(),
|
||||||
|
Syscalls: sm.Syscalls,
|
||||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||||
@ -31,7 +32,7 @@ func TestIndexSeeks(t *testing.T) {
|
|||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
nbs := blockstore.NewMemorySync()
|
nbs := blockstore.NewMemorySync()
|
||||||
cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
|
cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
_, err = cs.Import(bytes.NewReader(gencar))
|
_, err = cs.Import(bytes.NewReader(gencar))
|
||||||
|
@ -101,10 +101,11 @@ type BlockMessages struct {
|
|||||||
Miner address.Address
|
Miner address.Address
|
||||||
BlsMessages []types.ChainMsg
|
BlsMessages []types.ChainMsg
|
||||||
SecpkMessages []types.ChainMsg
|
SecpkMessages []types.ChainMsg
|
||||||
WinCount int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
|
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
|
||||||
|
// returned BlockMessages match block order in tipset
|
||||||
|
|
||||||
applied := make(map[address.Address]uint64)
|
applied := make(map[address.Address]uint64)
|
||||||
|
|
||||||
cst := cbor.NewCborStore(cs.stateBlockstore)
|
cst := cbor.NewCborStore(cs.stateBlockstore)
|
||||||
@ -150,7 +151,6 @@ func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, err
|
|||||||
Miner: b.Miner,
|
Miner: b.Miner,
|
||||||
BlsMessages: make([]types.ChainMsg, 0, len(bms)),
|
BlsMessages: make([]types.ChainMsg, 0, len(bms)),
|
||||||
SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
|
SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
|
||||||
WinCount: b.ElectionProof.WinCount,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bmsg := range bms {
|
for _, bmsg := range bms {
|
||||||
|
@ -87,6 +87,8 @@ type HeadChangeEvt struct {
|
|||||||
ApplyCount int
|
ApplyCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WeightFunc func(ctx context.Context, stateBs bstore.Blockstore, ts *types.TipSet) (types.BigInt, error)
|
||||||
|
|
||||||
// ChainStore is the main point of access to chain data.
|
// ChainStore is the main point of access to chain data.
|
||||||
//
|
//
|
||||||
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
|
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
|
||||||
@ -101,6 +103,8 @@ type ChainStore struct {
|
|||||||
stateBlockstore bstore.Blockstore
|
stateBlockstore bstore.Blockstore
|
||||||
metadataDs dstore.Batching
|
metadataDs dstore.Batching
|
||||||
|
|
||||||
|
weight WeightFunc
|
||||||
|
|
||||||
chainLocalBlockstore bstore.Blockstore
|
chainLocalBlockstore bstore.Blockstore
|
||||||
|
|
||||||
heaviestLk sync.RWMutex
|
heaviestLk sync.RWMutex
|
||||||
@ -128,7 +132,7 @@ type ChainStore struct {
|
|||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dstore.Batching, j journal.Journal) *ChainStore {
|
func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dstore.Batching, weight WeightFunc, j journal.Journal) *ChainStore {
|
||||||
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||||
if j == nil {
|
if j == nil {
|
||||||
@ -143,6 +147,7 @@ func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dsto
|
|||||||
chainBlockstore: chainBs,
|
chainBlockstore: chainBs,
|
||||||
stateBlockstore: stateBs,
|
stateBlockstore: stateBs,
|
||||||
chainLocalBlockstore: localbs,
|
chainLocalBlockstore: localbs,
|
||||||
|
weight: weight,
|
||||||
metadataDs: ds,
|
metadataDs: ds,
|
||||||
bestTips: pubsub.New(64),
|
bestTips: pubsub.New(64),
|
||||||
tipsets: make(map[abi.ChainEpoch][]cid.Cid),
|
tipsets: make(map[abi.ChainEpoch][]cid.Cid),
|
||||||
@ -410,11 +415,11 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipS
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer cs.heaviestLk.Unlock()
|
defer cs.heaviestLk.Unlock()
|
||||||
w, err := cs.Weight(ctx, ts)
|
w, err := cs.weight(ctx, cs.StateBlockstore(), ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
heaviestW, err := cs.Weight(ctx, cs.heaviest)
|
heaviestW, err := cs.weight(ctx, cs.StateBlockstore(), cs.heaviest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1156,3 +1161,7 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
|||||||
|
|
||||||
return cs.LoadTipSet(lbts.Parents())
|
return cs.LoadTipSet(lbts.Parents())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *ChainStore) Weight(ctx context.Context, hts *types.TipSet) (types.BigInt, error) { // todo remove
|
||||||
|
return cs.weight(ctx, cs.StateBlockstore(), hts)
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -70,7 +71,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
|||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
@ -105,7 +106,7 @@ func TestChainExportImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nbs := blockstore.NewMemory()
|
nbs := blockstore.NewMemory()
|
||||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), nil)
|
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
root, err := cs.Import(buf)
|
root, err := cs.Import(buf)
|
||||||
@ -140,7 +141,7 @@ func TestChainExportImportFull(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nbs := blockstore.NewMemory()
|
nbs := blockstore.NewMemory()
|
||||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), nil)
|
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
root, err := cs.Import(buf)
|
root, err := cs.Import(buf)
|
||||||
@ -157,7 +158,11 @@ func TestChainExportImportFull(t *testing.T) {
|
|||||||
t.Fatal("imported chain differed from exported chain")
|
t.Fatal("imported chain differed from exported chain")
|
||||||
}
|
}
|
||||||
|
|
||||||
sm := stmgr.NewStateManager(cs, nil)
|
sm, err := stmgr.NewStateManager(cs, filcns.TipSetExecutor(), nil, filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
ts, err := cs.GetTipsetByHeight(context.TODO(), abi.ChainEpoch(i), nil, false)
|
ts, err := cs.GetTipsetByHeight(context.TODO(), abi.ChainEpoch(i), nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,32 +2,26 @@ package sub
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
address "github.com/filecoin-project/go-address"
|
address "github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain"
|
"github.com/filecoin-project/lotus/chain"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/lib/sigs"
|
|
||||||
"github.com/filecoin-project/lotus/metrics"
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
"github.com/filecoin-project/lotus/node/impl/client"
|
"github.com/filecoin-project/lotus/node/impl/client"
|
||||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
blocks "github.com/ipfs/go-block-format"
|
blocks "github.com/ipfs/go-block-format"
|
||||||
bserv "github.com/ipfs/go-blockservice"
|
bserv "github.com/ipfs/go-blockservice"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
|
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
"go.opencensus.io/stats"
|
"go.opencensus.io/stats"
|
||||||
"go.opencensus.io/tag"
|
"go.opencensus.io/tag"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -35,9 +29,6 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("sub")
|
var log = logging.Logger("sub")
|
||||||
|
|
||||||
var ErrSoftFailure = errors.New("soft validation failure")
|
|
||||||
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
|
||||||
|
|
||||||
var msgCidPrefix = cid.Prefix{
|
var msgCidPrefix = cid.Prefix{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Codec: cid.DagCBOR,
|
Codec: cid.DagCBOR,
|
||||||
@ -225,11 +216,11 @@ type BlockValidator struct {
|
|||||||
blacklist func(peer.ID)
|
blacklist func(peer.ID)
|
||||||
|
|
||||||
// necessary for block validation
|
// necessary for block validation
|
||||||
chain *store.ChainStore
|
chain *store.ChainStore
|
||||||
stmgr *stmgr.StateManager
|
consensus consensus.Consensus
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockValidator(self peer.ID, chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
|
func NewBlockValidator(self peer.ID, chain *store.ChainStore, cns consensus.Consensus, blacklist func(peer.ID)) *BlockValidator {
|
||||||
p, _ := lru.New2Q(4096)
|
p, _ := lru.New2Q(4096)
|
||||||
return &BlockValidator{
|
return &BlockValidator{
|
||||||
self: self,
|
self: self,
|
||||||
@ -238,7 +229,7 @@ func NewBlockValidator(self peer.ID, chain *store.ChainStore, stmgr *stmgr.State
|
|||||||
blacklist: blacklist,
|
blacklist: blacklist,
|
||||||
recvBlocks: newBlockReceiptCache(),
|
recvBlocks: newBlockReceiptCache(),
|
||||||
chain: chain,
|
chain: chain,
|
||||||
stmgr: stmgr,
|
consensus: cns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,214 +251,35 @@ func (bv *BlockValidator) flagPeer(p peer.ID) {
|
|||||||
bv.peers.Add(p, v.(int)+1)
|
bv.peers.Add(p, v.(int)+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
|
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) (res pubsub.ValidationResult) {
|
||||||
if pid == bv.self {
|
|
||||||
return bv.validateLocalBlock(ctx, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// track validation time
|
|
||||||
begin := build.Clock.Now()
|
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Debugf("block validation time: %s", build.Clock.Since(begin))
|
if rerr := recover(); rerr != nil {
|
||||||
|
err := xerrors.Errorf("validate block: %s", rerr)
|
||||||
|
recordFailure(ctx, metrics.BlockValidationFailure, err.Error())
|
||||||
|
bv.flagPeer(pid)
|
||||||
|
res = pubsub.ValidationReject
|
||||||
|
return
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
var what string
|
||||||
|
res, what = bv.consensus.ValidateBlockPubsub(ctx, pid == bv.self, msg)
|
||||||
|
if res == pubsub.ValidationAccept {
|
||||||
|
// it's a good block! make sure we've only seen it once
|
||||||
|
if count := bv.recvBlocks.add(msg.ValidatorData.(*types.BlockMsg).Cid()); count > 0 {
|
||||||
|
if pid == bv.self {
|
||||||
|
log.Warnf("local block has been seen %d times; ignoring", count)
|
||||||
|
}
|
||||||
|
|
||||||
recordFailureFlagPeer := func(what string) {
|
// TODO: once these changes propagate to the network, we can consider
|
||||||
|
// dropping peers who send us the same block multiple times
|
||||||
|
return pubsub.ValidationIgnore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
recordFailure(ctx, metrics.BlockValidationFailure, what)
|
recordFailure(ctx, metrics.BlockValidationFailure, what)
|
||||||
bv.flagPeer(pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blk, what, err := bv.decodeAndCheckBlock(msg)
|
return res
|
||||||
if err != nil {
|
|
||||||
log.Error("got invalid block over pubsub: ", err)
|
|
||||||
recordFailureFlagPeer(what)
|
|
||||||
return pubsub.ValidationReject
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate the block meta: the Message CID in the header must match the included messages
|
|
||||||
err = bv.validateMsgMeta(ctx, blk)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("error validating message metadata: %s", err)
|
|
||||||
recordFailureFlagPeer("invalid_block_meta")
|
|
||||||
return pubsub.ValidationReject
|
|
||||||
}
|
|
||||||
|
|
||||||
// we want to ensure that it is a block from a known miner; we reject blocks from unknown miners
|
|
||||||
// to prevent spam attacks.
|
|
||||||
// the logic works as follows: we lookup the miner in the chain for its key.
|
|
||||||
// if we can find it then it's a known miner and we can validate the signature.
|
|
||||||
// if we can't find it, we check whether we are (near) synced in the chain.
|
|
||||||
// if we are not synced we cannot validate the block and we must ignore it.
|
|
||||||
// if we are synced and the miner is unknown, then the block is rejcected.
|
|
||||||
key, err := bv.checkPowerAndGetWorkerKey(ctx, blk.Header)
|
|
||||||
if err != nil {
|
|
||||||
if err != ErrSoftFailure && bv.isChainNearSynced() {
|
|
||||||
log.Warnf("received block from unknown miner or miner that doesn't meet min power over pubsub; rejecting message")
|
|
||||||
recordFailureFlagPeer("unknown_miner")
|
|
||||||
return pubsub.ValidationReject
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain: %s", blk.Header.Cid())
|
|
||||||
return pubsub.ValidationIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sigs.CheckBlockSignature(ctx, blk.Header, key)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("block signature verification failed: %s", err)
|
|
||||||
recordFailureFlagPeer("signature_verification_failed")
|
|
||||||
return pubsub.ValidationReject
|
|
||||||
}
|
|
||||||
|
|
||||||
if blk.Header.ElectionProof.WinCount < 1 {
|
|
||||||
log.Errorf("block is not claiming to be winning")
|
|
||||||
recordFailureFlagPeer("not_winning")
|
|
||||||
return pubsub.ValidationReject
|
|
||||||
}
|
|
||||||
|
|
||||||
// it's a good block! make sure we've only seen it once
|
|
||||||
if bv.recvBlocks.add(blk.Header.Cid()) > 0 {
|
|
||||||
// TODO: once these changes propagate to the network, we can consider
|
|
||||||
// dropping peers who send us the same block multiple times
|
|
||||||
return pubsub.ValidationIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
// all good, accept the block
|
|
||||||
msg.ValidatorData = blk
|
|
||||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
|
||||||
return pubsub.ValidationAccept
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *BlockValidator) validateLocalBlock(ctx context.Context, msg *pubsub.Message) pubsub.ValidationResult {
|
|
||||||
stats.Record(ctx, metrics.BlockPublished.M(1))
|
|
||||||
|
|
||||||
if size := msg.Size(); size > 1<<20-1<<15 {
|
|
||||||
log.Errorf("ignoring oversize block (%dB)", size)
|
|
||||||
recordFailure(ctx, metrics.BlockValidationFailure, "oversize_block")
|
|
||||||
return pubsub.ValidationIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
blk, what, err := bv.decodeAndCheckBlock(msg)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("got invalid local block: %s", err)
|
|
||||||
recordFailure(ctx, metrics.BlockValidationFailure, what)
|
|
||||||
return pubsub.ValidationIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
if count := bv.recvBlocks.add(blk.Header.Cid()); count > 0 {
|
|
||||||
log.Warnf("local block has been seen %d times; ignoring", count)
|
|
||||||
return pubsub.ValidationIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.ValidatorData = blk
|
|
||||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
|
||||||
return pubsub.ValidationAccept
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *BlockValidator) decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
|
|
||||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
|
||||||
if err != nil {
|
|
||||||
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
|
|
||||||
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we have a signature
|
|
||||||
if blk.Header.BlockSig == nil {
|
|
||||||
return nil, "missing_signature", fmt.Errorf("block without a signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
return blk, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *BlockValidator) isChainNearSynced() bool {
|
|
||||||
ts := bv.chain.GetHeaviestTipSet()
|
|
||||||
timestamp := ts.MinTimestamp()
|
|
||||||
timestampTime := time.Unix(int64(timestamp), 0)
|
|
||||||
return build.Clock.Since(timestampTime) < 6*time.Hour
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
|
||||||
// TODO there has to be a simpler way to do this without the blockstore dance
|
|
||||||
// block headers use adt0
|
|
||||||
store := blockadt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewMemory()))
|
|
||||||
bmArr := blockadt.MakeEmptyArray(store)
|
|
||||||
smArr := blockadt.MakeEmptyArray(store)
|
|
||||||
|
|
||||||
for i, m := range msg.BlsMessages {
|
|
||||||
c := cbg.CborCid(m)
|
|
||||||
if err := bmArr.Set(uint64(i), &c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, m := range msg.SecpkMessages {
|
|
||||||
c := cbg.CborCid(m)
|
|
||||||
if err := smArr.Set(uint64(i), &c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bmroot, err := bmArr.Root()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
smroot, err := smArr.Root()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mrcid, err := store.Put(store.Context(), &types.MsgMeta{
|
|
||||||
BlsMessages: bmroot,
|
|
||||||
SecpkMessages: smroot,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.Header.Messages != mrcid {
|
|
||||||
return fmt.Errorf("messages didn't match root cid in header")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *types.BlockHeader) (address.Address, error) {
|
|
||||||
// we check that the miner met the minimum power at the lookback tipset
|
|
||||||
|
|
||||||
baseTs := bv.chain.GetHeaviestTipSet()
|
|
||||||
lbts, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, bv.stmgr, baseTs, bh.Height)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to load lookback tipset for incoming block: %s", err)
|
|
||||||
return address.Undef, ErrSoftFailure
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := stmgr.GetMinerWorkerRaw(ctx, bv.stmgr, lbst, bh.Miner)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to resolve worker key for miner %s: %s", bh.Miner, err)
|
|
||||||
return address.Undef, ErrSoftFailure
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: we check to see if the miner was eligible in the lookback
|
|
||||||
// tipset - 1 for historical reasons. DO NOT use the lookback state
|
|
||||||
// returned by GetLookbackTipSetForRound.
|
|
||||||
|
|
||||||
eligible, err := stmgr.MinerEligibleToMine(ctx, bv.stmgr, bh.Miner, baseTs, lbts)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
|
|
||||||
return address.Undef, ErrSoftFailure
|
|
||||||
}
|
|
||||||
|
|
||||||
if !eligible {
|
|
||||||
log.Warnf("incoming block's miner is ineligible")
|
|
||||||
return address.Undef, ErrInsufficientPower
|
|
||||||
}
|
|
||||||
|
|
||||||
return key, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type blockReceiptCache struct {
|
type blockReceiptCache struct {
|
||||||
|
689
chain/sync.go
689
chain/sync.go
@ -5,13 +5,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
@ -29,40 +27,23 @@ import (
|
|||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
|
||||||
|
|
||||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
|
||||||
|
|
||||||
// named msgarray here to make it clear that these are the types used by
|
// named msgarray here to make it clear that these are the types used by
|
||||||
// messages, regardless of specs-actors version.
|
// messages, regardless of specs-actors version.
|
||||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
"github.com/filecoin-project/lotus/chain/exchange"
|
"github.com/filecoin-project/lotus/chain/exchange"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/lib/sigs"
|
|
||||||
"github.com/filecoin-project/lotus/metrics"
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Blocks that are more than MaxHeightDrift epochs above
|
|
||||||
// the theoretical max height based on systime are quickly rejected
|
|
||||||
const MaxHeightDrift = 5
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// LocalIncoming is the _local_ pubsub (unrelated to libp2p pubsub) topic
|
// LocalIncoming is the _local_ pubsub (unrelated to libp2p pubsub) topic
|
||||||
// where the Syncer publishes candidate chain heads to be synced.
|
// where the Syncer publishes candidate chain heads to be synced.
|
||||||
@ -108,6 +89,8 @@ type Syncer struct {
|
|||||||
// the state manager handles making state queries
|
// the state manager handles making state queries
|
||||||
sm *stmgr.StateManager
|
sm *stmgr.StateManager
|
||||||
|
|
||||||
|
consensus consensus.Consensus
|
||||||
|
|
||||||
// The known Genesis tipset
|
// The known Genesis tipset
|
||||||
Genesis *types.TipSet
|
Genesis *types.TipSet
|
||||||
|
|
||||||
@ -127,8 +110,6 @@ type Syncer struct {
|
|||||||
|
|
||||||
receiptTracker *blockReceiptTracker
|
receiptTracker *blockReceiptTracker
|
||||||
|
|
||||||
verifier ffiwrapper.Verifier
|
|
||||||
|
|
||||||
tickerCtxCancel context.CancelFunc
|
tickerCtxCancel context.CancelFunc
|
||||||
|
|
||||||
ds dtypes.MetadataDS
|
ds dtypes.MetadataDS
|
||||||
@ -136,40 +117,44 @@ type Syncer struct {
|
|||||||
|
|
||||||
type SyncManagerCtor func(syncFn SyncFunc) SyncManager
|
type SyncManagerCtor func(syncFn SyncFunc) SyncManager
|
||||||
|
|
||||||
// NewSyncer creates a new Syncer object.
|
type Genesis *types.TipSet
|
||||||
func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, syncMgrCtor SyncManagerCtor, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
|
||||||
|
func LoadGenesis(sm *stmgr.StateManager) (Genesis, error) {
|
||||||
gen, err := sm.ChainStore().GetGenesis()
|
gen, err := sm.ChainStore().GetGenesis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting genesis block: %w", err)
|
return nil, xerrors.Errorf("getting genesis block: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gent, err := types.NewTipSet([]*types.BlockHeader{gen})
|
return types.NewTipSet([]*types.BlockHeader{gen})
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
// NewSyncer creates a new Syncer object.
|
||||||
|
func NewSyncer(ds dtypes.MetadataDS,
|
||||||
|
sm *stmgr.StateManager,
|
||||||
|
exchange exchange.Client,
|
||||||
|
syncMgrCtor SyncManagerCtor,
|
||||||
|
connmgr connmgr.ConnManager,
|
||||||
|
self peer.ID,
|
||||||
|
beacon beacon.Schedule,
|
||||||
|
gent Genesis,
|
||||||
|
consensus consensus.Consensus) (*Syncer, error) {
|
||||||
|
|
||||||
s := &Syncer{
|
s := &Syncer{
|
||||||
ds: ds,
|
ds: ds,
|
||||||
beacon: beacon,
|
beacon: beacon,
|
||||||
bad: NewBadBlockCache(),
|
bad: NewBadBlockCache(),
|
||||||
Genesis: gent,
|
Genesis: gent,
|
||||||
|
consensus: consensus,
|
||||||
Exchange: exchange,
|
Exchange: exchange,
|
||||||
store: sm.ChainStore(),
|
store: sm.ChainStore(),
|
||||||
sm: sm,
|
sm: sm,
|
||||||
self: self,
|
self: self,
|
||||||
receiptTracker: newBlockReceiptTracker(),
|
receiptTracker: newBlockReceiptTracker(),
|
||||||
connmgr: connmgr,
|
connmgr: connmgr,
|
||||||
verifier: verifier,
|
|
||||||
|
|
||||||
incoming: pubsub.New(50),
|
incoming: pubsub.New(50),
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.InsecurePoStValidation {
|
|
||||||
log.Warn("*********************************************************************************************")
|
|
||||||
log.Warn(" [INSECURE-POST-VALIDATION] Insecure test validation is enabled. If you see this outside of a test, it is a severe bug! ")
|
|
||||||
log.Warn("*********************************************************************************************")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.syncmgr = syncMgrCtor(s.Sync)
|
s.syncmgr = syncMgrCtor(s.Sync)
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
@ -212,7 +197,7 @@ func (syncer *Syncer) Stop() {
|
|||||||
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
log.Errorf("panic in InformNewHead: ", err)
|
log.Errorf("panic in InformNewHead: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -222,7 +207,7 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if syncer.IsEpochBeyondCurrMax(fts.TipSet().Height()) {
|
if syncer.consensus.IsEpochBeyondCurrMax(fts.TipSet().Height()) {
|
||||||
log.Errorf("Received block with impossibly large height %d", fts.TipSet().Height())
|
log.Errorf("Received block with impossibly large height %d", fts.TipSet().Height())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -399,33 +384,21 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
|||||||
return nil, fmt.Errorf("msgincl length didnt match tipset size")
|
return nil, fmt.Errorf("msgincl length didnt match tipset size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := checkMsgMeta(ts, allbmsgs, allsmsgs, bmi, smi); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
fts := &store.FullTipSet{}
|
fts := &store.FullTipSet{}
|
||||||
for bi, b := range ts.Blocks() {
|
for bi, b := range ts.Blocks() {
|
||||||
if msgc := len(bmi[bi]) + len(smi[bi]); msgc > build.BlockMessageLimit {
|
|
||||||
return nil, fmt.Errorf("block %q has too many messages (%d)", b.Cid(), msgc)
|
|
||||||
}
|
|
||||||
|
|
||||||
var smsgs []*types.SignedMessage
|
var smsgs []*types.SignedMessage
|
||||||
var smsgCids []cid.Cid
|
|
||||||
for _, m := range smi[bi] {
|
for _, m := range smi[bi] {
|
||||||
smsgs = append(smsgs, allsmsgs[m])
|
smsgs = append(smsgs, allsmsgs[m])
|
||||||
smsgCids = append(smsgCids, allsmsgs[m].Cid())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var bmsgs []*types.Message
|
var bmsgs []*types.Message
|
||||||
var bmsgCids []cid.Cid
|
|
||||||
for _, m := range bmi[bi] {
|
for _, m := range bmi[bi] {
|
||||||
bmsgs = append(bmsgs, allbmsgs[m])
|
bmsgs = append(bmsgs, allbmsgs[m])
|
||||||
bmsgCids = append(bmsgCids, allbmsgs[m].Cid())
|
|
||||||
}
|
|
||||||
|
|
||||||
mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.Messages != mrcid {
|
|
||||||
return nil, fmt.Errorf("messages didnt match message root in header for ts %s", ts.Key())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fb := &types.FullBlock{
|
fb := &types.FullBlock{
|
||||||
@ -584,7 +557,7 @@ func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isPermanent(err error) bool {
|
func isPermanent(err error) bool {
|
||||||
return !errors.Is(err, ErrTemporal)
|
return !errors.Is(err, consensus.ErrTemporal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet, useCache bool) error {
|
func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet, useCache bool) error {
|
||||||
@ -624,55 +597,6 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, baseTs *types.TipSet) error {
|
|
||||||
act, err := syncer.sm.LoadActor(ctx, power.Address, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load power actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
powState, err := power.Load(syncer.store.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load power actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, exist, err := powState.MinerPower(maddr)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to look up miner's claim: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exist {
|
|
||||||
return xerrors.New("miner isn't valid")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var ErrTemporal = errors.New("temporal error")
|
|
||||||
|
|
||||||
func blockSanityChecks(h *types.BlockHeader) error {
|
|
||||||
if h.ElectionProof == nil {
|
|
||||||
return xerrors.Errorf("block cannot have nil election proof")
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.Ticket == nil {
|
|
||||||
return xerrors.Errorf("block cannot have nil ticket")
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.BlockSig == nil {
|
|
||||||
return xerrors.Errorf("block had nil signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.BLSAggregate == nil {
|
|
||||||
return xerrors.Errorf("block had nil bls aggregate signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.Miner.Protocol() != address.ID {
|
|
||||||
return xerrors.Errorf("block had non-ID miner address")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
|
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
|
||||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, useCache bool) (err error) {
|
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, useCache bool) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -703,262 +627,8 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
|||||||
ctx, span := trace.StartSpan(ctx, "validateBlock")
|
ctx, span := trace.StartSpan(ctx, "validateBlock")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if err := blockSanityChecks(b.Header); err != nil {
|
if err := syncer.consensus.ValidateBlock(ctx, b); err != nil {
|
||||||
return xerrors.Errorf("incoming header failed basic sanity checks: %w", err)
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
h := b.Header
|
|
||||||
|
|
||||||
baseTs, err := syncer.store.LoadTipSet(types.NewTipSetKey(h.Parents...))
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("load parent tipset failed (%s): %w", h.Parents, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
winPoStNv := syncer.sm.GetNtwkVersion(ctx, baseTs.Height())
|
|
||||||
|
|
||||||
lbts, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, syncer.sm, baseTs, h.Height)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get lookback tipset for block: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get latest beacon entry: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fast checks first
|
|
||||||
|
|
||||||
if h.Height <= baseTs.Height() {
|
|
||||||
return xerrors.Errorf("block height not greater than parent height: %d != %d", h.Height, baseTs.Height())
|
|
||||||
}
|
|
||||||
|
|
||||||
nulls := h.Height - (baseTs.Height() + 1)
|
|
||||||
if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
|
|
||||||
return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs)
|
|
||||||
}
|
|
||||||
|
|
||||||
now := uint64(build.Clock.Now().Unix())
|
|
||||||
if h.Timestamp > now+build.AllowableClockDriftSecs {
|
|
||||||
return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal)
|
|
||||||
}
|
|
||||||
if h.Timestamp > now {
|
|
||||||
log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix())
|
|
||||||
}
|
|
||||||
|
|
||||||
msgsCheck := async.Err(func() error {
|
|
||||||
if b.Cid() == build.WhitelistedBlock {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syncer.checkBlockMessages(ctx, b, baseTs); err != nil {
|
|
||||||
return xerrors.Errorf("block had invalid messages: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
minerCheck := async.Err(func() error {
|
|
||||||
if err := syncer.minerIsValid(ctx, h.Miner, baseTs); err != nil {
|
|
||||||
return xerrors.Errorf("minerIsValid failed: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
baseFeeCheck := async.Err(func() error {
|
|
||||||
baseFee, err := syncer.store.ComputeBaseFee(ctx, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("computing base fee: %w", err)
|
|
||||||
}
|
|
||||||
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
|
|
||||||
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
|
|
||||||
b.Header.ParentBaseFee, baseFee)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
pweight, err := syncer.store.Weight(ctx, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("getting parent weight: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if types.BigCmp(pweight, b.Header.ParentWeight) != 0 {
|
|
||||||
return xerrors.Errorf("parrent weight different: %s (header) != %s (computed)",
|
|
||||||
b.Header.ParentWeight, pweight)
|
|
||||||
}
|
|
||||||
|
|
||||||
stateRootCheck := async.Err(func() error {
|
|
||||||
stateroot, precp, err := syncer.sm.TipSetState(ctx, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if stateroot != h.ParentStateRoot {
|
|
||||||
msgs, err := syncer.store.MessagesForTipset(baseTs)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
|
|
||||||
} else {
|
|
||||||
log.Warn("Messages for tipset with mismatching state:")
|
|
||||||
for i, m := range msgs {
|
|
||||||
mm := m.VMMessage()
|
|
||||||
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", stateroot, h.ParentStateRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
if precp != h.ParentMessageReceipts {
|
|
||||||
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// Stuff that needs worker address
|
|
||||||
waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, lbst, h.Miner)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
winnerCheck := async.Err(func() error {
|
|
||||||
if h.ElectionProof.WinCount < 1 {
|
|
||||||
return xerrors.Errorf("block is not claiming to be a winner")
|
|
||||||
}
|
|
||||||
|
|
||||||
eligible, err := stmgr.MinerEligibleToMine(ctx, syncer.sm, h.Miner, baseTs, lbts)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !eligible {
|
|
||||||
return xerrors.New("block's miner is ineligible to mine")
|
|
||||||
}
|
|
||||||
|
|
||||||
rBeacon := *prevBeacon
|
|
||||||
if len(h.BeaconEntries) != 0 {
|
|
||||||
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
|
|
||||||
}
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
|
||||||
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
vrfBase, err := store.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("could not draw randomness: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
|
|
||||||
return xerrors.Errorf("validating block election proof failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
slashed, err := stmgr.GetMinerSlashed(ctx, syncer.sm, baseTs, h.Miner)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to check if block miner was slashed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if slashed {
|
|
||||||
return xerrors.Errorf("received block was from slashed or invalid miner")
|
|
||||||
}
|
|
||||||
|
|
||||||
mpow, tpow, _, err := stmgr.GetPowerRaw(ctx, syncer.sm, lbst, h.Miner)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed getting power: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
j := h.ElectionProof.ComputeWinCount(mpow.QualityAdjPower, tpow.QualityAdjPower)
|
|
||||||
if h.ElectionProof.WinCount != j {
|
|
||||||
return xerrors.Errorf("miner claims wrong number of wins: miner: %d, computed: %d", h.ElectionProof.WinCount, j)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
blockSigCheck := async.Err(func() error {
|
|
||||||
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil {
|
|
||||||
return xerrors.Errorf("check block signature failed: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
beaconValuesCheck := async.Err(func() error {
|
|
||||||
if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := beacon.ValidateBlockValues(syncer.beacon, h, baseTs.Height(), *prevBeacon); err != nil {
|
|
||||||
return xerrors.Errorf("failed to validate blocks random beacon values: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
tktsCheck := async.Err(func() error {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
|
||||||
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.Height > build.UpgradeSmokeHeight {
|
|
||||||
buf.Write(baseTs.MinTicket().VRFProof)
|
|
||||||
}
|
|
||||||
|
|
||||||
beaconBase := *prevBeacon
|
|
||||||
if len(h.BeaconEntries) != 0 {
|
|
||||||
beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
vrfBase, err := store.DrawRandomness(beaconBase.Data, crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("validating block tickets failed: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
wproofCheck := async.Err(func() error {
|
|
||||||
if err := syncer.VerifyWinningPoStProof(ctx, winPoStNv, h, *prevBeacon, lbst, waddr); err != nil {
|
|
||||||
return xerrors.Errorf("invalid election post: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
await := []async.ErrorFuture{
|
|
||||||
minerCheck,
|
|
||||||
tktsCheck,
|
|
||||||
blockSigCheck,
|
|
||||||
beaconValuesCheck,
|
|
||||||
wproofCheck,
|
|
||||||
winnerCheck,
|
|
||||||
msgsCheck,
|
|
||||||
baseFeeCheck,
|
|
||||||
stateRootCheck,
|
|
||||||
}
|
|
||||||
|
|
||||||
var merr error
|
|
||||||
for _, fut := range await {
|
|
||||||
if err := fut.AwaitContext(ctx); err != nil {
|
|
||||||
merr = multierror.Append(merr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if merr != nil {
|
|
||||||
mulErr := merr.(*multierror.Error)
|
|
||||||
mulErr.ErrorFormat = func(es []error) string {
|
|
||||||
if len(es) == 1 {
|
|
||||||
return fmt.Sprintf("1 error occurred:\n\t* %+v\n\n", es[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
points := make([]string, len(es))
|
|
||||||
for i, err := range es {
|
|
||||||
points[i] = fmt.Sprintf("* %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"%d errors occurred:\n\t%s\n\n",
|
|
||||||
len(es), strings.Join(points, "\n\t"))
|
|
||||||
}
|
|
||||||
return mulErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if useCache {
|
if useCache {
|
||||||
@ -970,249 +640,6 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, nv network.Version, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
|
|
||||||
if build.InsecurePoStValidation {
|
|
||||||
if len(h.WinPoStProof) == 0 {
|
|
||||||
return xerrors.Errorf("[INSECURE-POST-VALIDATION] No winning post proof given")
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(h.WinPoStProof[0].ProofBytes) == "valid proof" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return xerrors.Errorf("[INSECURE-POST-VALIDATION] winning post was invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := h.Miner.MarshalCBOR(buf); err != nil {
|
|
||||||
return xerrors.Errorf("failed to marshal miner address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rbase := prevBeacon
|
|
||||||
if len(h.BeaconEntries) > 0 {
|
|
||||||
rbase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mid, err := address.IDFromAddress(h.Miner)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get ID from miner address %s: %w", h.Miner, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sectors, err := stmgr.GetSectorsForWinningPoSt(ctx, nv, syncer.verifier, syncer.sm, lbst, h.Miner, rand)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("getting winning post sector set: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, proof2.WinningPoStVerifyInfo{
|
|
||||||
Randomness: rand,
|
|
||||||
Proofs: h.WinPoStProof,
|
|
||||||
ChallengedSectors: sectors,
|
|
||||||
Prover: abi.ActorID(mid),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to verify election post: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
log.Errorf("invalid winning post (block: %s, %x; %v)", h.Cid(), rand, sectors)
|
|
||||||
return xerrors.Errorf("winning post was invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: We should extract this somewhere else and make the message pool and miner use the same logic
|
|
||||||
func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error {
|
|
||||||
{
|
|
||||||
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
|
|
||||||
var pubks [][]byte
|
|
||||||
|
|
||||||
for _, m := range b.BlsMessages {
|
|
||||||
sigCids = append(sigCids, m.Cid())
|
|
||||||
|
|
||||||
pubk, err := syncer.sm.GetBlsPublicKey(ctx, m.From, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pubks = append(pubks, pubk)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syncer.verifyBlsAggregate(ctx, b.Header.BLSAggregate, sigCids, pubks); err != nil {
|
|
||||||
return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nonces := make(map[address.Address]uint64)
|
|
||||||
|
|
||||||
stateroot, _, err := syncer.sm.TipSetState(ctx, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
st, err := state.LoadStateTree(syncer.store.ActorStore(ctx), stateroot)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load base state tree: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
nv := syncer.sm.GetNtwkVersion(ctx, b.Header.Height)
|
|
||||||
pl := vm.PricelistByEpoch(baseTs.Height())
|
|
||||||
var sumGasLimit int64
|
|
||||||
checkMsg := func(msg types.ChainMsg) error {
|
|
||||||
m := msg.VMMessage()
|
|
||||||
|
|
||||||
// Phase 1: syntactic validation, as defined in the spec
|
|
||||||
minGas := pl.OnChainMessage(msg.ChainLength())
|
|
||||||
if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
|
|
||||||
// So below is overflow safe
|
|
||||||
sumGasLimit += m.GasLimit
|
|
||||||
if sumGasLimit > build.BlockGasLimit {
|
|
||||||
return xerrors.Errorf("block gas limit exceeded")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 2: (Partial) semantic validation:
|
|
||||||
// the sender exists and is an account actor, and the nonces make sense
|
|
||||||
var sender address.Address
|
|
||||||
if nv >= network.Version13 {
|
|
||||||
sender, err = st.LookupID(m.From)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender = m.From
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := nonces[sender]; !ok {
|
|
||||||
// `GetActor` does not validate that this is an account actor.
|
|
||||||
act, err := st.GetActor(sender)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !builtin.IsAccountActor(act.Code) {
|
|
||||||
return xerrors.New("Sender must be an account actor")
|
|
||||||
}
|
|
||||||
nonces[sender] = act.Nonce
|
|
||||||
}
|
|
||||||
|
|
||||||
if nonces[sender] != m.Nonce {
|
|
||||||
return xerrors.Errorf("wrong nonce (exp: %d, got: %d)", nonces[sender], m.Nonce)
|
|
||||||
}
|
|
||||||
nonces[sender]++
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate message arrays in a temporary blockstore.
|
|
||||||
tmpbs := bstore.NewMemory()
|
|
||||||
tmpstore := blockadt.WrapStore(ctx, cbor.NewCborStore(tmpbs))
|
|
||||||
|
|
||||||
bmArr := blockadt.MakeEmptyArray(tmpstore)
|
|
||||||
for i, m := range b.BlsMessages {
|
|
||||||
if err := checkMsg(m); err != nil {
|
|
||||||
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := store.PutMessage(tmpbs, m)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
k := cbg.CborCid(c)
|
|
||||||
if err := bmArr.Set(uint64(i), &k); err != nil {
|
|
||||||
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
smArr := blockadt.MakeEmptyArray(tmpstore)
|
|
||||||
for i, m := range b.SecpkMessages {
|
|
||||||
if err := checkMsg(m); err != nil {
|
|
||||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// `From` being an account actor is only validated inside the `vm.ResolveToKeyAddr` call
|
|
||||||
// in `StateManager.ResolveToKeyAddress` here (and not in `checkMsg`).
|
|
||||||
kaddr, err := syncer.sm.ResolveToKeyAddress(ctx, m.Message.From, baseTs)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil {
|
|
||||||
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := store.PutMessage(tmpbs, m)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
|
||||||
}
|
|
||||||
k := cbg.CborCid(c)
|
|
||||||
if err := smArr.Set(uint64(i), &k); err != nil {
|
|
||||||
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bmroot, err := bmArr.Root()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
smroot, err := smArr.Root()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
|
|
||||||
BlsMessages: bmroot,
|
|
||||||
SecpkMessages: smroot,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.Header.Messages != mrcid {
|
|
||||||
return fmt.Errorf("messages didnt match message root in header")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, flush.
|
|
||||||
return vm.Copy(ctx, tmpbs, syncer.store.ChainBlockstore(), mrcid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signature, msgs []cid.Cid, pubks [][]byte) error {
|
|
||||||
_, span := trace.StartSpan(ctx, "syncer.verifyBlsAggregate")
|
|
||||||
defer span.End()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.Int64Attribute("msgCount", int64(len(msgs))),
|
|
||||||
)
|
|
||||||
|
|
||||||
msgsS := make([]ffi.Message, len(msgs))
|
|
||||||
pubksS := make([]ffi.PublicKey, len(msgs))
|
|
||||||
for i := 0; i < len(msgs); i++ {
|
|
||||||
msgsS[i] = msgs[i].Bytes()
|
|
||||||
copy(pubksS[i][:], pubks[i][:ffi.PublicKeyBytes])
|
|
||||||
}
|
|
||||||
|
|
||||||
sigS := new(ffi.Signature)
|
|
||||||
copy(sigS[:], sig.Data[:ffi.SignatureBytes])
|
|
||||||
|
|
||||||
if len(msgs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
valid := ffi.HashVerify(sigS, msgsS, pubksS)
|
|
||||||
if !valid {
|
|
||||||
return xerrors.New("bls aggregate signature failed to verify")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type syncStateKey struct{}
|
type syncStateKey struct{}
|
||||||
|
|
||||||
func extractSyncState(ctx context.Context) *SyncerState {
|
func extractSyncState(ctx context.Context) *SyncerState {
|
||||||
@ -1374,7 +801,7 @@ loop:
|
|||||||
return nil, xerrors.Errorf("retrieved segments of the chain are not connected at heights %d/%d",
|
return nil, xerrors.Errorf("retrieved segments of the chain are not connected at heights %d/%d",
|
||||||
blockSet[len(blockSet)-1].Height(), blks[0].Height())
|
blockSet[len(blockSet)-1].Height(), blks[0].Height())
|
||||||
// A successful `GetBlocks()` call is guaranteed to fetch at least
|
// A successful `GetBlocks()` call is guaranteed to fetch at least
|
||||||
// one tipset so the acess `blks[0]` is safe.
|
// one tipset so the access `blks[0]` is safe.
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, b := range blks {
|
for _, b := range blks {
|
||||||
@ -1598,6 +1025,35 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkMsgMeta(ts *types.TipSet, allbmsgs []*types.Message, allsmsgs []*types.SignedMessage, bmi, smi [][]uint64) error {
|
||||||
|
for bi, b := range ts.Blocks() {
|
||||||
|
if msgc := len(bmi[bi]) + len(smi[bi]); msgc > build.BlockMessageLimit {
|
||||||
|
return fmt.Errorf("block %q has too many messages (%d)", b.Cid(), msgc)
|
||||||
|
}
|
||||||
|
|
||||||
|
var smsgCids []cid.Cid
|
||||||
|
for _, m := range smi[bi] {
|
||||||
|
smsgCids = append(smsgCids, allsmsgs[m].Cid())
|
||||||
|
}
|
||||||
|
|
||||||
|
var bmsgCids []cid.Cid
|
||||||
|
for _, m := range bmi[bi] {
|
||||||
|
bmsgCids = append(bmsgCids, allbmsgs[m].Cid())
|
||||||
|
}
|
||||||
|
|
||||||
|
mrcid, err := computeMsgMeta(cbor.NewCborStore(bstore.NewMemory()), bmsgCids, smsgCids)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Messages != mrcid {
|
||||||
|
return fmt.Errorf("messages didnt match message root in header for ts %s", ts.Key())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) fetchMessages(ctx context.Context, headers []*types.TipSet, startOffset int) ([]*exchange.CompactedMessages, error) {
|
func (syncer *Syncer) fetchMessages(ctx context.Context, headers []*types.TipSet, startOffset int) ([]*exchange.CompactedMessages, error) {
|
||||||
batchSize := len(headers)
|
batchSize := len(headers)
|
||||||
batch := make([]*exchange.CompactedMessages, batchSize)
|
batch := make([]*exchange.CompactedMessages, batchSize)
|
||||||
@ -1636,7 +1092,19 @@ func (syncer *Syncer) fetchMessages(ctx context.Context, headers []*types.TipSet
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
requestErr = multierror.Append(requestErr, err)
|
requestErr = multierror.Append(requestErr, err)
|
||||||
} else {
|
} else {
|
||||||
requestResult = result
|
isGood := true
|
||||||
|
for index, ts := range headers[nextI:lastI] {
|
||||||
|
cm := result[index]
|
||||||
|
if err := checkMsgMeta(ts, cm.Bls, cm.Secpk, cm.BlsIncludes, cm.SecpkIncludes); err != nil {
|
||||||
|
log.Errorf("fetched messages not as expected: %s", err)
|
||||||
|
isGood = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isGood {
|
||||||
|
requestResult = result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1754,10 +1222,6 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet, hts *t
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []byte, evrf []byte) error {
|
|
||||||
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (syncer *Syncer) State() []SyncerStateSnapshot {
|
func (syncer *Syncer) State() []SyncerStateSnapshot {
|
||||||
return syncer.syncmgr.State()
|
return syncer.syncmgr.State()
|
||||||
}
|
}
|
||||||
@ -1802,12 +1266,3 @@ func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet)
|
|||||||
|
|
||||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
|
||||||
if syncer.Genesis == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
now := uint64(build.Clock.Now().Unix())
|
|
||||||
return epoch > (abi.ChainEpoch((now-syncer.Genesis.MinTimestamp())/build.BlockDelaySecs) + MaxHeightDrift)
|
|
||||||
}
|
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -105,7 +106,7 @@ func prepSyncTest(t testing.TB, h int) *syncTestUtil {
|
|||||||
|
|
||||||
mn: mocknet.New(ctx),
|
mn: mocknet.New(ctx),
|
||||||
g: g,
|
g: g,
|
||||||
us: stmgr.DefaultUpgradeSchedule(),
|
us: filcns.DefaultUpgradeSchedule(),
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.addSourceNode(h)
|
tu.addSourceNode(h)
|
||||||
@ -125,19 +126,19 @@ func prepSyncTestWithV5Height(t testing.TB, h int, v5height abi.ChainEpoch) *syn
|
|||||||
// prepare for upgrade.
|
// prepare for upgrade.
|
||||||
Network: network.Version9,
|
Network: network.Version9,
|
||||||
Height: 1,
|
Height: 1,
|
||||||
Migration: stmgr.UpgradeActorsV2,
|
Migration: filcns.UpgradeActorsV2,
|
||||||
}, {
|
}, {
|
||||||
Network: network.Version10,
|
Network: network.Version10,
|
||||||
Height: 2,
|
Height: 2,
|
||||||
Migration: stmgr.UpgradeActorsV3,
|
Migration: filcns.UpgradeActorsV3,
|
||||||
}, {
|
}, {
|
||||||
Network: network.Version12,
|
Network: network.Version12,
|
||||||
Height: 3,
|
Height: 3,
|
||||||
Migration: stmgr.UpgradeActorsV4,
|
Migration: filcns.UpgradeActorsV4,
|
||||||
}, {
|
}, {
|
||||||
Network: network.Version13,
|
Network: network.Version13,
|
||||||
Height: v5height,
|
Height: v5height,
|
||||||
Migration: stmgr.UpgradeActorsV5,
|
Migration: filcns.UpgradeActorsV5,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
g, err := gen.NewGeneratorWithUpgradeSchedule(sched)
|
g, err := gen.NewGeneratorWithUpgradeSchedule(sched)
|
||||||
|
@ -47,7 +47,8 @@ func NewBeaconEntry(round uint64, data []byte) BeaconEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BlockHeader struct {
|
type BlockHeader struct {
|
||||||
Miner address.Address // 0 unique per block/miner
|
Miner address.Address // 0 unique per block/miner
|
||||||
|
|
||||||
Ticket *Ticket // 1 unique per block/miner: should be a valid VRF
|
Ticket *Ticket // 1 unique per block/miner: should be a valid VRF
|
||||||
ElectionProof *ElectionProof // 2 unique per block/miner: should be a valid VRF
|
ElectionProof *ElectionProof // 2 unique per block/miner: should be a valid VRF
|
||||||
BeaconEntries []BeaconEntry // 3 identical for all blocks in same tipset
|
BeaconEntries []BeaconEntry // 3 identical for all blocks in same tipset
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
|
||||||
@ -14,11 +16,6 @@ import (
|
|||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
|
||||||
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
|
||||||
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
|
|
||||||
exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported"
|
|
||||||
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
|
||||||
vmr "github.com/filecoin-project/specs-actors/v5/actors/runtime"
|
vmr "github.com/filecoin-project/specs-actors/v5/actors/runtime"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
@ -30,8 +27,17 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MethodMeta struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
Params reflect.Type
|
||||||
|
Ret reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
type ActorRegistry struct {
|
type ActorRegistry struct {
|
||||||
actors map[cid.Cid]*actorInfo
|
actors map[cid.Cid]*actorInfo
|
||||||
|
|
||||||
|
Methods map[cid.Cid]map[abi.MethodNum]MethodMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
// An ActorPredicate returns an error if the given actor is not valid for the given runtime environment (e.g., chain height, version, etc.).
|
// An ActorPredicate returns an error if the given actor is not valid for the given runtime environment (e.g., chain height, version, etc.).
|
||||||
@ -61,18 +67,10 @@ type actorInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewActorRegistry() *ActorRegistry {
|
func NewActorRegistry() *ActorRegistry {
|
||||||
inv := &ActorRegistry{actors: make(map[cid.Cid]*actorInfo)}
|
return &ActorRegistry{
|
||||||
|
actors: make(map[cid.Cid]*actorInfo),
|
||||||
// TODO: define all these properties on the actors themselves, in specs-actors.
|
Methods: map[cid.Cid]map[abi.MethodNum]MethodMeta{},
|
||||||
|
}
|
||||||
// add builtInCode using: register(cid, singleton)
|
|
||||||
inv.Register(ActorsVersionPredicate(actors.Version0), exported0.BuiltinActors()...)
|
|
||||||
inv.Register(ActorsVersionPredicate(actors.Version2), exported2.BuiltinActors()...)
|
|
||||||
inv.Register(ActorsVersionPredicate(actors.Version3), exported3.BuiltinActors()...)
|
|
||||||
inv.Register(ActorsVersionPredicate(actors.Version4), exported4.BuiltinActors()...)
|
|
||||||
inv.Register(ActorsVersionPredicate(actors.Version5), exported5.BuiltinActors()...)
|
|
||||||
|
|
||||||
return inv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
@ -96,6 +94,7 @@ func (ar *ActorRegistry) Register(pred ActorPredicate, actors ...rtt.VMActor) {
|
|||||||
pred = func(vmr.Runtime, rtt.VMActor) error { return nil }
|
pred = func(vmr.Runtime, rtt.VMActor) error { return nil }
|
||||||
}
|
}
|
||||||
for _, a := range actors {
|
for _, a := range actors {
|
||||||
|
// register in the `actors` map (for the invoker)
|
||||||
code, err := ar.transform(a)
|
code, err := ar.transform(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err))
|
panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err))
|
||||||
@ -105,6 +104,51 @@ func (ar *ActorRegistry) Register(pred ActorPredicate, actors ...rtt.VMActor) {
|
|||||||
vmActor: a,
|
vmActor: a,
|
||||||
predicate: pred,
|
predicate: pred,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register in the `Methods` map (used by statemanager utils)
|
||||||
|
exports := a.Exports()
|
||||||
|
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
||||||
|
|
||||||
|
// Explicitly add send, it's special.
|
||||||
|
methods[builtin.MethodSend] = MethodMeta{
|
||||||
|
Name: "Send",
|
||||||
|
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
||||||
|
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over exported methods. Some of these _may_ be nil and
|
||||||
|
// must be skipped.
|
||||||
|
for number, export := range exports {
|
||||||
|
if export == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := reflect.ValueOf(export)
|
||||||
|
et := ev.Type()
|
||||||
|
|
||||||
|
// Extract the method names using reflection. These
|
||||||
|
// method names always match the field names in the
|
||||||
|
// `builtin.Method*` structs (tested in the specs-actors
|
||||||
|
// tests).
|
||||||
|
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
||||||
|
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
||||||
|
|
||||||
|
switch abi.MethodNum(number) {
|
||||||
|
case builtin.MethodSend:
|
||||||
|
panic("method 0 is reserved for Send")
|
||||||
|
case builtin.MethodConstructor:
|
||||||
|
if fnName != "Constructor" {
|
||||||
|
panic("method 1 is reserved for Constructor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
methods[abi.MethodNum(number)] = MethodMeta{
|
||||||
|
Name: fnName,
|
||||||
|
Params: et.In(1),
|
||||||
|
Ret: et.Out(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ar.Methods[a.Code()] = methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,13 +270,11 @@ func DecodeParams(b []byte, out interface{}) error {
|
|||||||
return um.UnmarshalCBOR(bytes.NewReader(b))
|
return um.UnmarshalCBOR(bytes.NewReader(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func DumpActorState(act *types.Actor, b []byte) (interface{}, error) {
|
func DumpActorState(i *ActorRegistry, act *types.Actor, b []byte) (interface{}, error) {
|
||||||
if builtin.IsAccountActor(act.Code) { // Account code special case
|
if builtin.IsAccountActor(act.Code) { // Account code special case
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i := NewActorRegistry()
|
|
||||||
|
|
||||||
actInfo, ok := i.actors[act.Code]
|
actInfo, ok := i.actors[act.Code]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, xerrors.Errorf("state type for actor %s not found", act.Code)
|
return nil, xerrors.Errorf("state type for actor %s not found", act.Code)
|
||||||
|
@ -223,6 +223,7 @@ type VMOpts struct {
|
|||||||
Epoch abi.ChainEpoch
|
Epoch abi.ChainEpoch
|
||||||
Rand Rand
|
Rand Rand
|
||||||
Bstore blockstore.Blockstore
|
Bstore blockstore.Blockstore
|
||||||
|
Actors *ActorRegistry
|
||||||
Syscalls SyscallBuilder
|
Syscalls SyscallBuilder
|
||||||
CircSupplyCalc CircSupplyCalculator
|
CircSupplyCalc CircSupplyCalculator
|
||||||
NtwkVersion NtwkVersionGetter // TODO: stebalien: In what cases do we actually need this? It seems like even when creating new networks we want to use the 'global'/build-default version getter
|
NtwkVersion NtwkVersionGetter // TODO: stebalien: In what cases do we actually need this? It seems like even when creating new networks we want to use the 'global'/build-default version getter
|
||||||
@ -244,7 +245,7 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) {
|
|||||||
cst: cst,
|
cst: cst,
|
||||||
buf: buf,
|
buf: buf,
|
||||||
blockHeight: opts.Epoch,
|
blockHeight: opts.Epoch,
|
||||||
areg: NewActorRegistry(),
|
areg: opts.Actors,
|
||||||
rand: opts.Rand, // TODO: Probably should be a syscall
|
rand: opts.Rand, // TODO: Probably should be a syscall
|
||||||
circSupplyCalc: opts.CircSupplyCalc,
|
circSupplyCalc: opts.CircSupplyCalc,
|
||||||
ntwkVersion: opts.NtwkVersion,
|
ntwkVersion: opts.NtwkVersion,
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api/v0api"
|
"github.com/filecoin-project/lotus/api/v0api"
|
||||||
|
|
||||||
@ -1397,7 +1398,7 @@ func sumGas(changes []*types.GasTrace) types.GasTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
|
func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
|
||||||
p, err := stmgr.GetParamType(code, method)
|
p, err := stmgr.GetParamType(filcns.NewActorRegistry(), code, method) // todo use api for correct actor registry
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
badgerbs "github.com/filecoin-project/lotus/blockstore/badger"
|
badgerbs "github.com/filecoin-project/lotus/blockstore/badger"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -253,10 +254,13 @@ var importBenchCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
metadataDs := datastore.NewMapDatastore()
|
metadataDs := datastore.NewMapDatastore()
|
||||||
cs := store.NewChainStore(bs, bs, metadataDs, nil)
|
cs := store.NewChainStore(bs, bs, metadataDs, filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
stm := stmgr.NewStateManager(cs, vm.Syscalls(verifier))
|
stm, err := stmgr.NewStateManager(cs, filcns.TipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var carFile *os.File
|
var carFile *os.File
|
||||||
// open the CAR file if one is provided.
|
// open the CAR file if one is provided.
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/gen/genesis"
|
"github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||||
|
|
||||||
@ -510,13 +511,16 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
cst := cbor.NewCborStore(bs)
|
cst := cbor.NewCborStore(bs)
|
||||||
store := adt.WrapStore(ctx, cst)
|
store := adt.WrapStore(ctx, cst)
|
||||||
|
|
||||||
sm := stmgr.NewStateManager(cs, vm.Syscalls(ffiwrapper.ProofVerifier))
|
sm, err := stmgr.NewStateManager(cs, filcns.TipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
tree, err := state.LoadStateTree(cst, sroot)
|
tree, err := state.LoadStateTree(cst, sroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -731,14 +735,16 @@ var chainPledgeCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
cst := cbor.NewCborStore(bs)
|
cst := cbor.NewCborStore(bs)
|
||||||
store := adt.WrapStore(ctx, cst)
|
store := adt.WrapStore(ctx, cst)
|
||||||
|
|
||||||
sm := stmgr.NewStateManager(cs, vm.Syscalls(ffiwrapper.ProofVerifier))
|
sm, err := stmgr.NewStateManager(cs, filcns.TipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
state, err := state.LoadStateTree(cst, sroot)
|
state, err := state.LoadStateTree(cst, sroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -90,7 +90,7 @@ var exportChainCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
cs := store.NewChainStore(bs, bs, mds, nil, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
if err := cs.Load(); err != nil {
|
if err := cs.Load(); err != nil {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
@ -54,7 +55,7 @@ var genesisVerifyCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
bs := blockstore.FromDatastore(datastore.NewMapDatastore())
|
bs := blockstore.FromDatastore(datastore.NewMapDatastore())
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), nil)
|
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
cf := cctx.Args().Get(0)
|
cf := cctx.Args().Get(0)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
big2 "github.com/filecoin-project/go-state-types/big"
|
big2 "github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
@ -74,7 +75,7 @@ var minerTypesCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
cst := cbor.NewCborStore(bs)
|
cst := cbor.NewCborStore(bs)
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/ipfs/bbloom"
|
"github.com/ipfs/bbloom"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@ -167,7 +168,7 @@ var stateTreePruneCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
if err := cs.Load(); err != nil {
|
if err := cs.Load(); err != nil {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S
|
|||||||
Epoch: parentTs.Height() + 1,
|
Epoch: parentTs.Height() + 1,
|
||||||
Rand: r,
|
Rand: r,
|
||||||
Bstore: sm.ChainStore().StateBlockstore(),
|
Bstore: sm.ChainStore().StateBlockstore(),
|
||||||
|
Actors: filcns.NewActorRegistry(),
|
||||||
Syscalls: sm.VMSys(),
|
Syscalls: sm.VMSys(),
|
||||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/ipfs/go-datastore/query"
|
"github.com/ipfs/go-datastore/query"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -61,7 +62,7 @@ func NewNode(ctx context.Context, r repo.Repo) (nd *Node, _err error) {
|
|||||||
}
|
}
|
||||||
return &Node{
|
return &Node{
|
||||||
repo: lr,
|
repo: lr,
|
||||||
Chainstore: store.NewChainStore(bs, bs, ds, nil),
|
Chainstore: store.NewChainStore(bs, bs, ds, filcns.Weight, nil),
|
||||||
MetadataDS: ds,
|
MetadataDS: ds,
|
||||||
Blockstore: bs,
|
Blockstore: bs,
|
||||||
}, err
|
}, err
|
||||||
@ -105,7 +106,7 @@ func (nd *Node) LoadSim(ctx context.Context, name string) (*Simulation, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to create upgrade schedule for simulation %s: %w", name, err)
|
return nil, xerrors.Errorf("failed to create upgrade schedule for simulation %s: %w", name, err)
|
||||||
}
|
}
|
||||||
sim.StateManager, err = stmgr.NewStateManagerWithUpgradeSchedule(nd.Chainstore, vm.Syscalls(mock.Verifier), us)
|
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.TipSetExecutor(), vm.Syscalls(mock.Verifier), us)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to create state manager for simulation %s: %w", name, err)
|
return nil, xerrors.Errorf("failed to create state manager for simulation %s: %w", name, err)
|
||||||
}
|
}
|
||||||
@ -124,10 +125,14 @@ func (nd *Node) CreateSim(ctx context.Context, name string, head *types.TipSet)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.TipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("creating state manager: %w", err)
|
||||||
|
}
|
||||||
sim := &Simulation{
|
sim := &Simulation{
|
||||||
name: name,
|
name: name,
|
||||||
Node: nd,
|
Node: nd,
|
||||||
StateManager: stmgr.NewStateManager(nd.Chainstore, vm.Syscalls(mock.Verifier)),
|
StateManager: sm,
|
||||||
stages: stages,
|
stages: stages,
|
||||||
}
|
}
|
||||||
if has, err := nd.MetadataDS.Has(sim.key("head")); err != nil {
|
if has, err := nd.MetadataDS.Has(sim.key("head")); err != nil {
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
|
|
||||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
@ -35,7 +36,7 @@ type config struct {
|
|||||||
// upgradeSchedule constructs an stmgr.StateManager upgrade schedule, overriding any network upgrade
|
// upgradeSchedule constructs an stmgr.StateManager upgrade schedule, overriding any network upgrade
|
||||||
// epochs as specified in the config.
|
// epochs as specified in the config.
|
||||||
func (c *config) upgradeSchedule() (stmgr.UpgradeSchedule, error) {
|
func (c *config) upgradeSchedule() (stmgr.UpgradeSchedule, error) {
|
||||||
upgradeSchedule := stmgr.DefaultUpgradeSchedule()
|
upgradeSchedule := filcns.DefaultUpgradeSchedule()
|
||||||
expected := make(map[network.Version]struct{}, len(c.Upgrades))
|
expected := make(map[network.Version]struct{}, len(c.Upgrades))
|
||||||
for nv := range c.Upgrades {
|
for nv := range c.Upgrades {
|
||||||
expected[nv] = struct{}{}
|
expected[nv] = struct{}{}
|
||||||
@ -200,7 +201,7 @@ func (sim *Simulation) SetUpgradeHeight(nv network.Version, epoch abi.ChainEpoch
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sm, err := stmgr.NewStateManagerWithUpgradeSchedule(sim.Node.Chainstore, vm.Syscalls(mock.Verifier), newUpgradeSchedule)
|
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.TipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -483,7 +484,7 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
|||||||
return xerrors.Errorf("failed to open journal: %w", err)
|
return xerrors.Errorf("failed to open journal: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cst := store.NewChainStore(bs, bs, mds, j)
|
cst := store.NewChainStore(bs, bs, mds, filcns.Weight, j)
|
||||||
defer cst.Close() //nolint:errcheck
|
defer cst.Close() //nolint:errcheck
|
||||||
|
|
||||||
log.Infof("importing chain from %s...", fname)
|
log.Infof("importing chain from %s...", fname)
|
||||||
@ -519,7 +520,10 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stm := stmgr.NewStateManager(cst, vm.Syscalls(ffiwrapper.ProofVerifier))
|
stm, err := stmgr.NewStateManager(cst, filcns.TipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !snapshot {
|
if !snapshot {
|
||||||
log.Infof("validating imported chain...")
|
log.Infof("validating imported chain...")
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -101,9 +102,13 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
|||||||
tipset = params.Tipset
|
tipset = params.Tipset
|
||||||
syscalls = vm.Syscalls(ffiwrapper.ProofVerifier)
|
syscalls = vm.Syscalls(ffiwrapper.ProofVerifier)
|
||||||
|
|
||||||
cs = store.NewChainStore(bs, bs, ds, nil)
|
cs = store.NewChainStore(bs, bs, ds, filcns.Weight, nil)
|
||||||
sm = stmgr.NewStateManager(cs, syscalls)
|
tse = filcns.TipSetExecutor()
|
||||||
|
sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule())
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if params.Rand == nil {
|
if params.Rand == nil {
|
||||||
params.Rand = NewFixedRand()
|
params.Rand = NewFixedRand()
|
||||||
@ -115,11 +120,10 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
|||||||
|
|
||||||
defer cs.Close() //nolint:errcheck
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
blocks := make([]store.BlockMessages, 0, len(tipset.Blocks))
|
blocks := make([]filcns.FilecoinBlockMessages, 0, len(tipset.Blocks))
|
||||||
for _, b := range tipset.Blocks {
|
for _, b := range tipset.Blocks {
|
||||||
sb := store.BlockMessages{
|
sb := store.BlockMessages{
|
||||||
Miner: b.MinerAddr,
|
Miner: b.MinerAddr,
|
||||||
WinCount: b.WinCount,
|
|
||||||
}
|
}
|
||||||
for _, m := range b.Messages {
|
for _, m := range b.Messages {
|
||||||
msg, err := types.DecodeMessage(m)
|
msg, err := types.DecodeMessage(m)
|
||||||
@ -138,7 +142,10 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
|||||||
sb.BlsMessages = append(sb.BlsMessages, msg)
|
sb.BlsMessages = append(sb.BlsMessages, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocks = append(blocks, sb)
|
blocks = append(blocks, filcns.FilecoinBlockMessages{
|
||||||
|
BlockMessages: sb,
|
||||||
|
WinCount: b.WinCount,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
recordOutputs := &outputRecorder{
|
recordOutputs := &outputRecorder{
|
||||||
@ -146,7 +153,8 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
|||||||
results: []*vm.ApplyRet{},
|
results: []*vm.ApplyRet{},
|
||||||
}
|
}
|
||||||
|
|
||||||
postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(),
|
postcid, receiptsroot, err := tse.ApplyBlocks(context.Background(),
|
||||||
|
sm,
|
||||||
params.ParentEpoch,
|
params.ParentEpoch,
|
||||||
params.Preroot,
|
params.Preroot,
|
||||||
blocks,
|
blocks,
|
||||||
@ -196,7 +204,10 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
|||||||
|
|
||||||
// dummy state manager; only to reference the GetNetworkVersion method,
|
// dummy state manager; only to reference the GetNetworkVersion method,
|
||||||
// which does not depend on state.
|
// which does not depend on state.
|
||||||
sm := stmgr.NewStateManager(nil, nil)
|
sm, err := stmgr.NewStateManager(nil, filcns.TipSetExecutor(), nil, filcns.DefaultUpgradeSchedule())
|
||||||
|
if err != nil {
|
||||||
|
return nil, cid.Cid{}, err
|
||||||
|
}
|
||||||
|
|
||||||
vmOpts := &vm.VMOpts{
|
vmOpts := &vm.VMOpts{
|
||||||
StateBase: params.Preroot,
|
StateBase: params.Preroot,
|
||||||
@ -216,7 +227,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
|||||||
return nil, cid.Undef, err
|
return nil, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
invoker := vm.NewActorRegistry()
|
invoker := filcns.NewActorRegistry()
|
||||||
|
|
||||||
// register the chaos actor if required by the vector.
|
// register the chaos actor if required by the vector.
|
||||||
if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" {
|
if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" {
|
||||||
|
2
go.sum
2
go.sum
@ -169,6 +169,7 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf
|
|||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
@ -1513,6 +1514,7 @@ github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
|||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||||
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
|
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
|
||||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
@ -3,6 +3,8 @@ package kit
|
|||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +30,7 @@ func SDRUpgradeAt(calico, persian abi.ChainEpoch) EnsembleOpt {
|
|||||||
}, stmgr.Upgrade{
|
}, stmgr.Upgrade{
|
||||||
Network: network.Version7,
|
Network: network.Version7,
|
||||||
Height: calico,
|
Height: calico,
|
||||||
Migration: stmgr.UpgradeCalico,
|
Migration: filcns.UpgradeCalico,
|
||||||
}, stmgr.Upgrade{
|
}, stmgr.Upgrade{
|
||||||
Network: network.Version8,
|
Network: network.Version8,
|
||||||
Height: persian,
|
Height: persian,
|
||||||
@ -42,7 +44,7 @@ func LatestActorsAt(upgradeHeight abi.ChainEpoch) EnsembleOpt {
|
|||||||
}, stmgr.Upgrade{
|
}, stmgr.Upgrade{
|
||||||
Network: network.Version13,
|
Network: network.Version13,
|
||||||
Height: upgradeHeight,
|
Height: upgradeHeight,
|
||||||
Migration: stmgr.UpgradeActorsV5,
|
Migration: filcns.UpgradeActorsV5,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +55,6 @@ func TurboUpgradeAt(upgradeHeight abi.ChainEpoch) EnsembleOpt {
|
|||||||
}, stmgr.Upgrade{
|
}, stmgr.Upgrade{
|
||||||
Network: network.Version12,
|
Network: network.Version12,
|
||||||
Height: upgradeHeight,
|
Height: upgradeHeight,
|
||||||
Migration: stmgr.UpgradeActorsV4,
|
Migration: filcns.UpgradeActorsV4,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
51
lib/async/error.go
Normal file
51
lib/async/error.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package async
|
||||||
|
|
||||||
|
// based on https://github.com/Gurpartap/async
|
||||||
|
// Apache-2.0 License, see https://github.com/Gurpartap/async/blob/master/License.txt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorFuture interface {
|
||||||
|
Await() error
|
||||||
|
AwaitContext(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorFuture struct {
|
||||||
|
await func(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f errorFuture) Await() error {
|
||||||
|
return f.await(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f errorFuture) AwaitContext(ctx context.Context) error {
|
||||||
|
return f.await(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Err(f func() error) ErrorFuture {
|
||||||
|
var err error
|
||||||
|
c := make(chan struct{}, 1)
|
||||||
|
go func() {
|
||||||
|
defer close(c)
|
||||||
|
defer func() {
|
||||||
|
if rerr := recover(); rerr != nil {
|
||||||
|
err = xerrors.Errorf("async error: %s", rerr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err = f()
|
||||||
|
}()
|
||||||
|
return errorFuture{
|
||||||
|
await: func(ctx context.Context) error {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-c:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain"
|
"github.com/filecoin-project/lotus/chain"
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/exchange"
|
"github.com/filecoin-project/lotus/chain/exchange"
|
||||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||||
"github.com/filecoin-project/lotus/chain/market"
|
"github.com/filecoin-project/lotus/chain/market"
|
||||||
@ -46,7 +48,7 @@ var ChainNode = Options(
|
|||||||
|
|
||||||
// Consensus settings
|
// Consensus settings
|
||||||
Override(new(dtypes.DrandSchedule), modules.BuiltinDrandConfig),
|
Override(new(dtypes.DrandSchedule), modules.BuiltinDrandConfig),
|
||||||
Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()),
|
Override(new(stmgr.UpgradeSchedule), filcns.DefaultUpgradeSchedule()),
|
||||||
Override(new(dtypes.NetworkName), modules.NetworkName),
|
Override(new(dtypes.NetworkName), modules.NetworkName),
|
||||||
Override(new(modules.Genesis), modules.ErrorGenesis),
|
Override(new(modules.Genesis), modules.ErrorGenesis),
|
||||||
Override(new(dtypes.AfterGenesisSet), modules.SetGenesis),
|
Override(new(dtypes.AfterGenesisSet), modules.SetGenesis),
|
||||||
@ -65,6 +67,10 @@ var ChainNode = Options(
|
|||||||
Override(new(vm.SyscallBuilder), vm.Syscalls),
|
Override(new(vm.SyscallBuilder), vm.Syscalls),
|
||||||
|
|
||||||
// Consensus: Chain storage/access
|
// Consensus: Chain storage/access
|
||||||
|
Override(new(chain.Genesis), chain.LoadGenesis),
|
||||||
|
Override(new(store.WeightFunc), filcns.Weight),
|
||||||
|
Override(new(stmgr.Executor), filcns.TipSetExecutor()),
|
||||||
|
Override(new(consensus.Consensus), filcns.NewFilecoinExpectedConsensus),
|
||||||
Override(new(*store.ChainStore), modules.ChainStore),
|
Override(new(*store.ChainStore), modules.ChainStore),
|
||||||
Override(new(*stmgr.StateManager), modules.StateManager),
|
Override(new(*stmgr.StateManager), modules.StateManager),
|
||||||
Override(new(dtypes.ChainBitswap), modules.ChainBitswap),
|
Override(new(dtypes.ChainBitswap), modules.ChainBitswap),
|
||||||
|
@ -2,6 +2,7 @@ package hello
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
@ -48,10 +49,11 @@ type Service struct {
|
|||||||
|
|
||||||
cs *store.ChainStore
|
cs *store.ChainStore
|
||||||
syncer *chain.Syncer
|
syncer *chain.Syncer
|
||||||
|
cons consensus.Consensus
|
||||||
pmgr *peermgr.PeerMgr
|
pmgr *peermgr.PeerMgr
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHelloService(h host.Host, cs *store.ChainStore, syncer *chain.Syncer, pmgr peermgr.MaybePeerMgr) *Service {
|
func NewHelloService(h host.Host, cs *store.ChainStore, syncer *chain.Syncer, cons consensus.Consensus, pmgr peermgr.MaybePeerMgr) *Service {
|
||||||
if pmgr.Mgr == nil {
|
if pmgr.Mgr == nil {
|
||||||
log.Warn("running without peer manager")
|
log.Warn("running without peer manager")
|
||||||
}
|
}
|
||||||
@ -61,6 +63,7 @@ func NewHelloService(h host.Host, cs *store.ChainStore, syncer *chain.Syncer, pm
|
|||||||
|
|
||||||
cs: cs,
|
cs: cs,
|
||||||
syncer: syncer,
|
syncer: syncer,
|
||||||
|
cons: cons,
|
||||||
pmgr: pmgr.Mgr,
|
pmgr: pmgr.Mgr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -78,7 +79,8 @@ type ChainAPI struct {
|
|||||||
WalletAPI
|
WalletAPI
|
||||||
ChainModuleAPI
|
ChainModuleAPI
|
||||||
|
|
||||||
Chain *store.ChainStore
|
Chain *store.ChainStore
|
||||||
|
TsExec stmgr.Executor
|
||||||
|
|
||||||
// ExposedBlockstore is the global monolith blockstore that is safe to
|
// ExposedBlockstore is the global monolith blockstore that is safe to
|
||||||
// expose externally. In the future, this will be segregated into two
|
// expose externally. In the future, this will be segregated into two
|
||||||
@ -394,7 +396,7 @@ func (s stringKey) Key() string {
|
|||||||
|
|
||||||
// TODO: ActorUpgrade: this entire function is a problem (in theory) as we don't know the HAMT version.
|
// TODO: ActorUpgrade: this entire function is a problem (in theory) as we don't know the HAMT version.
|
||||||
// In practice, hamt v0 should work "just fine" for reading.
|
// In practice, hamt v0 should work "just fine" for reading.
|
||||||
func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) {
|
func resolveOnce(bs blockstore.Blockstore, tse stmgr.Executor) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) {
|
||||||
return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) {
|
return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) {
|
||||||
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
|
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
|
||||||
|
|
||||||
@ -468,7 +470,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
|
|||||||
}, nil, nil
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveOnce(bs)(ctx, ds, n, names[1:])
|
return resolveOnce(bs, tse)(ctx, ds, n, names[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(names[0], "@A:") {
|
if strings.HasPrefix(names[0], "@A:") {
|
||||||
@ -517,7 +519,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
|
|||||||
}, nil, nil
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveOnce(bs)(ctx, ds, n, names[1:])
|
return resolveOnce(bs, tse)(ctx, ds, n, names[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if names[0] == "@state" {
|
if names[0] == "@state" {
|
||||||
@ -531,7 +533,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
|
|||||||
return nil, nil, xerrors.Errorf("getting actor head for @state: %w", err)
|
return nil, nil, xerrors.Errorf("getting actor head for @state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := vm.DumpActorState(&act, head.RawData())
|
m, err := vm.DumpActorState(tse.NewActorRegistry(), &act, head.RawData())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -565,7 +567,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
|
|||||||
}, nil, nil
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveOnce(bs)(ctx, ds, n, names[1:])
|
return resolveOnce(bs, tse)(ctx, ds, n, names[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
return nd.ResolveLink(names)
|
return nd.ResolveLink(names)
|
||||||
@ -585,7 +587,7 @@ func (a *ChainAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject,
|
|||||||
|
|
||||||
r := &resolver.Resolver{
|
r := &resolver.Resolver{
|
||||||
DAG: dag,
|
DAG: dag,
|
||||||
ResolveOnce: resolveOnce(bs),
|
ResolveOnce: resolveOnce(bs, a.TsExec),
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := r.ResolvePath(ctx, ip)
|
node, err := r.ResolvePath(ctx, ip)
|
||||||
|
@ -29,7 +29,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -88,6 +88,8 @@ type StateAPI struct {
|
|||||||
StateManager *stmgr.StateManager
|
StateManager *stmgr.StateManager
|
||||||
Chain *store.ChainStore
|
Chain *store.ChainStore
|
||||||
Beacon beacon.Schedule
|
Beacon beacon.Schedule
|
||||||
|
Consensus consensus.Consensus
|
||||||
|
TsExec stmgr.Executor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
|
func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
|
||||||
@ -469,7 +471,7 @@ func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, ts
|
|||||||
return nil, xerrors.Errorf("getting actor head: %w", err)
|
return nil, xerrors.Errorf("getting actor head: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
oif, err := vm.DumpActorState(act, blk.RawData())
|
oif, err := vm.DumpActorState(a.TsExec.NewActorRegistry(), act, blk.RawData())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("dumping actor state (a:%s): %w", actor, err)
|
return nil, xerrors.Errorf("dumping actor state (a:%s): %w", actor, err)
|
||||||
}
|
}
|
||||||
@ -487,7 +489,7 @@ func (a *StateAPI) StateDecodeParams(ctx context.Context, toAddr address.Address
|
|||||||
return nil, xerrors.Errorf("getting actor: %w", err)
|
return nil, xerrors.Errorf("getting actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
paramType, err := stmgr.GetParamType(act.Code, method)
|
paramType, err := stmgr.GetParamType(a.TsExec.NewActorRegistry(), act.Code, method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting params type: %w", err)
|
return nil, xerrors.Errorf("getting params type: %w", err)
|
||||||
}
|
}
|
||||||
@ -500,7 +502,7 @@ func (a *StateAPI) StateDecodeParams(ctx context.Context, toAddr address.Address
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateEncodeParams(ctx context.Context, toActCode cid.Cid, method abi.MethodNum, params json.RawMessage) ([]byte, error) {
|
func (a *StateAPI) StateEncodeParams(ctx context.Context, toActCode cid.Cid, method abi.MethodNum, params json.RawMessage) ([]byte, error) {
|
||||||
paramType, err := stmgr.GetParamType(toActCode, method)
|
paramType, err := stmgr.GetParamType(a.TsExec.NewActorRegistry(), toActCode, method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting params type: %w", err)
|
return nil, xerrors.Errorf("getting params type: %w", err)
|
||||||
}
|
}
|
||||||
@ -524,10 +526,13 @@ func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) (*types.BlockMsg, error) {
|
func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) (*types.BlockMsg, error) {
|
||||||
fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, bt)
|
fblk, err := a.Consensus.CreateBlock(ctx, a.Wallet, bt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if fblk == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var out types.BlockMsg
|
var out types.BlockMsg
|
||||||
out.Header = fblk.Header
|
out.Header = fblk.Header
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
type SyncAPI struct {
|
type SyncAPI struct {
|
||||||
fx.In
|
fx.In
|
||||||
|
|
||||||
SlashFilter *slashfilter.SlashFilter
|
SlashFilter *slashfilter.SlashFilter `optional:"true"`
|
||||||
Syncer *chain.Syncer
|
Syncer *chain.Syncer
|
||||||
PubSub *pubsub.PubSub
|
PubSub *pubsub.PubSub
|
||||||
NetName dtypes.NetworkName
|
NetName dtypes.NetworkName
|
||||||
@ -56,9 +56,11 @@ func (a *SyncAPI) SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) erro
|
|||||||
return xerrors.Errorf("loading parent block: %w", err)
|
return xerrors.Errorf("loading parent block: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.SlashFilter.MinedBlock(blk.Header, parent.Height); err != nil {
|
if a.SlashFilter != nil {
|
||||||
log.Errorf("<!!> SLASH FILTER ERROR: %s", err)
|
if err := a.SlashFilter.MinedBlock(blk.Header, parent.Height); err != nil {
|
||||||
return xerrors.Errorf("<!!> SLASH FILTER ERROR: %w", err)
|
log.Errorf("<!!> SLASH FILTER ERROR: %s", err)
|
||||||
|
return xerrors.Errorf("<!!> SLASH FILTER ERROR: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should we have some sort of fast path to adding a local block?
|
// TODO: should we have some sort of fast path to adding a local block?
|
||||||
|
@ -17,13 +17,13 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain"
|
"github.com/filecoin-project/lotus/chain"
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
"github.com/filecoin-project/lotus/chain/exchange"
|
"github.com/filecoin-project/lotus/chain/exchange"
|
||||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
|
||||||
"github.com/filecoin-project/lotus/journal"
|
"github.com/filecoin-project/lotus/journal"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||||
@ -58,8 +58,8 @@ func ChainBlockService(bs dtypes.ExposedBlockstore, rem dtypes.ChainBitswap) dty
|
|||||||
return blockservice.New(bs, rem)
|
return blockservice.New(bs, rem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MessagePool(lc fx.Lifecycle, mpp messagepool.Provider, ds dtypes.MetadataDS, nn dtypes.NetworkName, j journal.Journal, protector dtypes.GCReferenceProtector) (*messagepool.MessagePool, error) {
|
func MessagePool(lc fx.Lifecycle, us stmgr.UpgradeSchedule, mpp messagepool.Provider, ds dtypes.MetadataDS, nn dtypes.NetworkName, j journal.Journal, protector dtypes.GCReferenceProtector) (*messagepool.MessagePool, error) {
|
||||||
mp, err := messagepool.New(mpp, ds, nn, j)
|
mp, err := messagepool.New(mpp, ds, us, nn, j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("constructing mpool: %w", err)
|
return nil, xerrors.Errorf("constructing mpool: %w", err)
|
||||||
}
|
}
|
||||||
@ -72,8 +72,15 @@ func MessagePool(lc fx.Lifecycle, mpp messagepool.Provider, ds dtypes.MetadataDS
|
|||||||
return mp, nil
|
return mp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChainStore(lc fx.Lifecycle, cbs dtypes.ChainBlockstore, sbs dtypes.StateBlockstore, ds dtypes.MetadataDS, basebs dtypes.BaseBlockstore, j journal.Journal) *store.ChainStore {
|
func ChainStore(lc fx.Lifecycle,
|
||||||
chain := store.NewChainStore(cbs, sbs, ds, j)
|
cbs dtypes.ChainBlockstore,
|
||||||
|
sbs dtypes.StateBlockstore,
|
||||||
|
ds dtypes.MetadataDS,
|
||||||
|
basebs dtypes.BaseBlockstore,
|
||||||
|
weight store.WeightFunc,
|
||||||
|
j journal.Journal) *store.ChainStore {
|
||||||
|
|
||||||
|
chain := store.NewChainStore(cbs, sbs, ds, weight, j)
|
||||||
|
|
||||||
if err := chain.Load(); err != nil {
|
if err := chain.Load(); err != nil {
|
||||||
log.Warnf("loading chain state from disk: %s", err)
|
log.Warnf("loading chain state from disk: %s", err)
|
||||||
@ -100,14 +107,20 @@ func ChainStore(lc fx.Lifecycle, cbs dtypes.ChainBlockstore, sbs dtypes.StateBlo
|
|||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, syscalls vm.SyscallBuilder, us stmgr.UpgradeSchedule, _ dtypes.AfterGenesisSet) (dtypes.NetworkName, error) {
|
func NetworkName(mctx helpers.MetricsCtx,
|
||||||
|
lc fx.Lifecycle,
|
||||||
|
cs *store.ChainStore,
|
||||||
|
tsexec stmgr.Executor,
|
||||||
|
syscalls vm.SyscallBuilder,
|
||||||
|
us stmgr.UpgradeSchedule,
|
||||||
|
_ dtypes.AfterGenesisSet) (dtypes.NetworkName, error) {
|
||||||
if !build.Devnet {
|
if !build.Devnet {
|
||||||
return "testnetnet", nil
|
return "testnetnet", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||||
|
|
||||||
sm, err := stmgr.NewStateManagerWithUpgradeSchedule(cs, syscalls, us)
|
sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -126,7 +139,8 @@ type SyncerParams struct {
|
|||||||
SyncMgrCtor chain.SyncManagerCtor
|
SyncMgrCtor chain.SyncManagerCtor
|
||||||
Host host.Host
|
Host host.Host
|
||||||
Beacon beacon.Schedule
|
Beacon beacon.Schedule
|
||||||
Verifier ffiwrapper.Verifier
|
Gent chain.Genesis
|
||||||
|
Consensus consensus.Consensus
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSyncer(params SyncerParams) (*chain.Syncer, error) {
|
func NewSyncer(params SyncerParams) (*chain.Syncer, error) {
|
||||||
@ -138,9 +152,8 @@ func NewSyncer(params SyncerParams) (*chain.Syncer, error) {
|
|||||||
smCtor = params.SyncMgrCtor
|
smCtor = params.SyncMgrCtor
|
||||||
h = params.Host
|
h = params.Host
|
||||||
b = params.Beacon
|
b = params.Beacon
|
||||||
v = params.Verifier
|
|
||||||
)
|
)
|
||||||
syncer, err := chain.NewSyncer(ds, sm, ex, smCtor, h.ConnManager(), h.ID(), b, v)
|
syncer, err := chain.NewSyncer(ds, sm, ex, smCtor, h.ConnManager(), h.ID(), b, params.Gent, params.Consensus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
"github.com/ipfs/go-datastore/namespace"
|
"github.com/ipfs/go-datastore/namespace"
|
||||||
eventbus "github.com/libp2p/go-eventbus"
|
eventbus "github.com/libp2p/go-eventbus"
|
||||||
@ -136,11 +137,19 @@ func waitForSync(stmgr *stmgr.StateManager, epochs int, subscribe func()) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) {
|
func HandleIncomingBlocks(mctx helpers.MetricsCtx,
|
||||||
|
lc fx.Lifecycle,
|
||||||
|
ps *pubsub.PubSub,
|
||||||
|
s *chain.Syncer,
|
||||||
|
bserv dtypes.ChainBlockService,
|
||||||
|
chain *store.ChainStore,
|
||||||
|
cns consensus.Consensus,
|
||||||
|
h host.Host,
|
||||||
|
nn dtypes.NetworkName) {
|
||||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||||
|
|
||||||
v := sub.NewBlockValidator(
|
v := sub.NewBlockValidator(
|
||||||
h.ID(), chain, stmgr,
|
h.ID(), chain, cns,
|
||||||
func(p peer.ID) {
|
func(p peer.ID) {
|
||||||
ps.BlacklistPeer(p)
|
ps.BlacklistPeer(p)
|
||||||
h.ConnManager().TagPeer(p, "badblock", -1000)
|
h.ConnManager().TagPeer(p, "badblock", -1000)
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StateManager(lc fx.Lifecycle, cs *store.ChainStore, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule) (*stmgr.StateManager, error) {
|
func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule) (*stmgr.StateManager, error) {
|
||||||
sm, err := stmgr.NewStateManagerWithUpgradeSchedule(cs, sys, us)
|
sm, err := stmgr.NewStateManager(cs, exec, sys, us)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,9 @@ func as(in interface{}, as interface{}) interface{} {
|
|||||||
panic("outType is not a pointer")
|
panic("outType is not a pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(in).Kind() != reflect.Func {
|
inType := reflect.TypeOf(in)
|
||||||
|
|
||||||
|
if inType.Kind() != reflect.Func || inType.AssignableTo(outType.Elem()) {
|
||||||
ctype := reflect.FuncOf(nil, []reflect.Type{outType.Elem()}, false)
|
ctype := reflect.FuncOf(nil, []reflect.Type{outType.Elem()}, false)
|
||||||
|
|
||||||
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
||||||
@ -121,8 +123,6 @@ func as(in interface{}, as interface{}) interface{} {
|
|||||||
}).Interface()
|
}).Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
inType := reflect.TypeOf(in)
|
|
||||||
|
|
||||||
ins := make([]reflect.Type, inType.NumIn())
|
ins := make([]reflect.Type, inType.NumIn())
|
||||||
outs := make([]reflect.Type, inType.NumOut())
|
outs := make([]reflect.Type, inType.NumOut())
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user