Merge branch 'next' into feat/cid-builder
This commit is contained in:
commit
b51e2a868b
@ -68,7 +68,11 @@ type FullNode interface {
|
||||
|
||||
// ChainHasObj checks if a given CID exists in the chain blockstore.
|
||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, error)
|
||||
|
||||
// ChainStatObj returns statistics about the graph referenced by 'obj'.
|
||||
// If 'base' is also specified, then the returned stat will be a diff
|
||||
// between the two objects.
|
||||
ChainStatObj(ctx context.Context, obj cid.Cid, base cid.Cid) (ObjStat, error)
|
||||
|
||||
// ChainSetHead forcefully sets current chain head. Use with caution.
|
||||
ChainSetHead(context.Context, types.TipSetKey) error
|
||||
@ -639,6 +643,7 @@ type MiningBaseInfo struct {
|
||||
SectorSize abi.SectorSize
|
||||
PrevBeaconEntry types.BeaconEntry
|
||||
BeaconEntries []types.BeaconEntry
|
||||
HasMinPower bool
|
||||
}
|
||||
|
||||
type BlockTemplate struct {
|
||||
|
@ -59,8 +59,8 @@ const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
// /////
|
||||
// Devnet settings
|
||||
|
||||
const TotalFilecoin = uint64(2_000_000_000)
|
||||
const MiningRewardTotal = uint64(1_900_000_000)
|
||||
const FilBase = uint64(2_000_000_000)
|
||||
const FilAllocStorageMining = uint64(1_100_000_000)
|
||||
|
||||
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
||||
|
||||
@ -69,7 +69,7 @@ var InitialRewardBalance *big.Int
|
||||
// TODO: Move other important consts here
|
||||
|
||||
func init() {
|
||||
InitialRewardBalance = big.NewInt(int64(MiningRewardTotal))
|
||||
InitialRewardBalance = big.NewInt(int64(FilAllocStorageMining))
|
||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
||||
}
|
||||
|
||||
|
@ -49,13 +49,13 @@ var (
|
||||
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
|
||||
TotalFilecoin uint64 = 2_000_000_000
|
||||
MiningRewardTotal uint64 = 1_400_000_000
|
||||
FilBase uint64 = 2_000_000_000
|
||||
FilAllocStorageMining uint64 = 1_400_000_000
|
||||
|
||||
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
||||
|
||||
InitialRewardBalance = func() *big.Int {
|
||||
v := big.NewInt(int64(MiningRewardTotal))
|
||||
v := big.NewInt(int64(FilAllocStorageMining))
|
||||
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||
return v
|
||||
}()
|
||||
|
@ -321,7 +321,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
|
||||
var sum abi.PaddedPieceSize
|
||||
|
||||
vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys()))
|
||||
vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys()), nil)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
||||
}
|
||||
|
@ -56,7 +56,11 @@ func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder {
|
||||
}
|
||||
|
||||
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, miners []genesis.Miner) (cid.Cid, error) {
|
||||
vm, err := vm.NewVM(sroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys()))
|
||||
vc := func(context.Context, abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
return big.Zero(), nil
|
||||
}
|
||||
|
||||
vm, err := vm.NewVM(sroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys()), vc)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ const futureDebug = false
|
||||
|
||||
const ReplaceByFeeRatio = 1.25
|
||||
|
||||
const repubMsgLimit = 5
|
||||
|
||||
var (
|
||||
rbfNum = types.NewInt(uint64((ReplaceByFeeRatio - 1) * 256))
|
||||
rbfDenom = types.NewInt(256)
|
||||
@ -269,6 +271,10 @@ func (mp *MessagePool) repubLocal() {
|
||||
log.Infow("republishing local messages", "n", len(outputMsgs))
|
||||
}
|
||||
|
||||
if len(outputMsgs) > repubMsgLimit {
|
||||
outputMsgs = outputMsgs[:repubMsgLimit]
|
||||
}
|
||||
|
||||
for _, msg := range outputMsgs {
|
||||
msgb, err := msg.Serialize()
|
||||
if err != nil {
|
||||
|
@ -22,7 +22,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw")
|
||||
defer span.End()
|
||||
|
||||
vmi, err := vm.NewVM(bstate, bheight, r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
vmi, err := vm.NewVM(bstate, bheight, r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
@ -106,7 +106,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
)
|
||||
}
|
||||
|
||||
vmi, err := vm.NewVM(state, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
vmi, err := vm.NewVM(state, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
|
@ -151,8 +151,8 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{})
|
||||
sm.SetVMConstructor(func(c cid.Cid, h abi.ChainEpoch, r vm.Rand, b blockstore.Blockstore, s vm.SyscallBuilder) (*vm.VM, error) {
|
||||
nvm, err := vm.NewVM(c, h, r, b, s)
|
||||
sm.SetVMConstructor(func(c cid.Cid, h abi.ChainEpoch, r vm.Rand, b blockstore.Blockstore, s vm.SyscallBuilder, vc vm.VestedCalculator) (*vm.VM, error) {
|
||||
nvm, err := vm.NewVM(c, h, r, b, s, sm.GetVestedFunds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package stmgr
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -37,10 +38,12 @@ var log = logging.Logger("statemgr")
|
||||
type StateManager struct {
|
||||
cs *store.ChainStore
|
||||
|
||||
stCache map[string][]cid.Cid
|
||||
compWait map[string]chan struct{}
|
||||
stlk sync.Mutex
|
||||
newVM func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder) (*vm.VM, error)
|
||||
stCache map[string][]cid.Cid
|
||||
compWait map[string]chan struct{}
|
||||
stlk sync.Mutex
|
||||
genesisMsigLk sync.Mutex
|
||||
newVM func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder, vm.VestedCalculator) (*vm.VM, error)
|
||||
genesisMsigs []multisig.State
|
||||
}
|
||||
|
||||
func NewStateManager(cs *store.ChainStore) *StateManager {
|
||||
@ -149,7 +152,7 @@ type BlockMessages struct {
|
||||
type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error
|
||||
|
||||
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback) (cid.Cid, cid.Cid, error) {
|
||||
vmi, err := sm.newVM(pstate, epoch, r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
vmi, err := sm.newVM(pstate, epoch, r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
|
||||
}
|
||||
@ -763,6 +766,91 @@ func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder) (*vm.VM, error)) {
|
||||
func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder, vm.VestedCalculator) (*vm.VM, error)) {
|
||||
sm.newVM = nvm
|
||||
}
|
||||
|
||||
type GenesisMsigEntry struct {
|
||||
totalFunds abi.TokenAmount
|
||||
unitVest abi.TokenAmount
|
||||
}
|
||||
|
||||
func (sm *StateManager) setupGenesisMsigs(ctx context.Context) error {
|
||||
gb, err := sm.cs.GetGenesis()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis block: %w", err)
|
||||
}
|
||||
|
||||
gts, err := types.NewTipSet([]*types.BlockHeader{gb})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis tipset: %w", err)
|
||||
}
|
||||
|
||||
st, _, err := sm.TipSetState(ctx, gts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis tipset state: %w", err)
|
||||
}
|
||||
|
||||
r, err := adt.AsMap(sm.cs.Store(ctx), st)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis actors: %w", err)
|
||||
}
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
var act types.Actor
|
||||
err = r.ForEach(&act, func(k string) error {
|
||||
if act.Code == builtin.MultisigActorCodeID {
|
||||
var s multisig.State
|
||||
err := sm.cs.Store(ctx).Get(ctx, act.Head, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.StartEpoch != 0 {
|
||||
return xerrors.New("genesis multisig doesn't start vesting at epoch 0!")
|
||||
}
|
||||
|
||||
ot, f := totalsByEpoch[s.UnlockDuration]
|
||||
if f {
|
||||
totalsByEpoch[s.UnlockDuration] = big.Add(ot, s.InitialBalance)
|
||||
} else {
|
||||
totalsByEpoch[s.UnlockDuration] = s.InitialBalance
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error setting up composite genesis multisigs: %w", err)
|
||||
}
|
||||
|
||||
sm.genesisMsigs = make([]multisig.State, 0, len(totalsByEpoch))
|
||||
for k, v := range totalsByEpoch {
|
||||
ns := multisig.State{
|
||||
InitialBalance: v,
|
||||
UnlockDuration: k,
|
||||
PendingTxns: cid.Undef,
|
||||
}
|
||||
sm.genesisMsigs = append(sm.genesisMsigs, ns)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetVestedFunds(ctx context.Context, height abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
sm.genesisMsigLk.Lock()
|
||||
defer sm.genesisMsigLk.Unlock()
|
||||
if sm.genesisMsigs == nil {
|
||||
err := sm.setupGenesisMsigs(ctx)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to setup genesis msig entries: %w", err)
|
||||
}
|
||||
}
|
||||
vf := big.Zero()
|
||||
for _, v := range sm.genesisMsigs {
|
||||
au := big.Sub(v.InitialBalance, v.AmountLocked(height))
|
||||
vf = big.Add(vf, au)
|
||||
}
|
||||
return vf, nil
|
||||
}
|
||||
|
@ -440,7 +440,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), height)
|
||||
vmi, err := vm.NewVM(base, height, r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
vmi, err := vm.NewVM(base, height, r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
@ -567,6 +567,11 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||
}
|
||||
|
||||
hmp, err := MinerHasMinPower(ctx, sm, maddr, lbts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||
}
|
||||
|
||||
return &api.MiningBaseInfo{
|
||||
MinerPower: mpow.QualityAdjPower,
|
||||
NetworkPower: tpow.QualityAdjPower,
|
||||
@ -575,6 +580,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
SectorSize: info.SectorSize,
|
||||
PrevBeaconEntry: *prev,
|
||||
BeaconEntries: entries,
|
||||
HasMinPower: hmp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -589,7 +595,7 @@ func (sm *StateManager) CirculatingSupply(ctx context.Context, ts *types.TipSet)
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())
|
||||
vmi, err := vm.NewVM(st, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
vmi, err := vm.NewVM(st, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds)
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
@ -659,3 +665,13 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
||||
m := MethodsMap[act.Code][method]
|
||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
}
|
||||
|
||||
func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||
var ps power.State
|
||||
_, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &ps, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||
}
|
||||
|
||||
return ps.MinerNominalPowerMeetsConsensusMinimum(sm.ChainStore().Store(ctx), addr)
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
big2 "github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
@ -73,44 +72,3 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
||||
|
||||
return types.BigInt{Int: out}, nil
|
||||
}
|
||||
|
||||
// todo: dedupe with state manager
|
||||
func (cs *ChainStore) call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
|
||||
bstate := ts.ParentState()
|
||||
|
||||
r := NewChainRand(cs, ts.Cids(), ts.Height())
|
||||
|
||||
vmi, err := vm.NewVM(bstate, ts.Height(), r, cs.bs, cs.vmcalls)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
|
||||
if msg.GasLimit == 0 {
|
||||
msg.GasLimit = 10000000000
|
||||
}
|
||||
if msg.GasPrice == types.EmptyInt {
|
||||
msg.GasPrice = types.NewInt(0)
|
||||
}
|
||||
if msg.Value == types.EmptyInt {
|
||||
msg.Value = types.NewInt(0)
|
||||
}
|
||||
|
||||
fromActor, err := vmi.StateTree().GetActor(msg.From)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("call raw get actor: %s", err)
|
||||
}
|
||||
|
||||
msg.Nonce = fromActor.Nonce
|
||||
|
||||
// TODO: maybe just use the invoker directly?
|
||||
// TODO: use signed message length for secp messages
|
||||
ret, err := vmi.ApplyMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("apply message failed: %w", err)
|
||||
}
|
||||
|
||||
if ret.ActorErr != nil {
|
||||
log.Warnf("chain call failed: %s", ret.ActorErr)
|
||||
}
|
||||
return &ret.MessageReceipt, nil
|
||||
}
|
||||
|
@ -190,14 +190,14 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
// 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.getMinerWorkerKey(ctx, blk)
|
||||
key, err := bv.checkPowerAndGetWorkerKey(ctx, blk.Header)
|
||||
if err != nil {
|
||||
if bv.isChainNearSynced() {
|
||||
log.Warnf("received block message from unknown miner over pubsub; rejecting message")
|
||||
log.Warnf("received block from unknown miner or miner that doesn't meet min power over pubsub; rejecting message")
|
||||
recordFailure("unknown_miner")
|
||||
return pubsub.ValidationReject
|
||||
} else {
|
||||
log.Warnf("cannot validate block message; unknown miner in unsynced chain")
|
||||
log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
}
|
||||
@ -282,60 +282,83 @@ func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockM
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.BlockMsg) (address.Address, error) {
|
||||
addr := msg.Header.Miner
|
||||
func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *types.BlockHeader) (address.Address, error) {
|
||||
addr := bh.Miner
|
||||
|
||||
bv.mx.Lock()
|
||||
key, ok := bv.keycache[addr.String()]
|
||||
bv.mx.Unlock()
|
||||
if ok {
|
||||
return key, nil
|
||||
if !ok {
|
||||
// TODO I have a feeling all this can be simplified by cleverer DI to use the API
|
||||
ts := bv.chain.GetHeaviestTipSet()
|
||||
st, _, err := bv.stmgr.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore())
|
||||
cst := cbor.NewCborStore(buf)
|
||||
state, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
act, err := state.GetActor(addr)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
blk, err := bv.chain.Blockstore().Get(act.Head)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
aso := blk.RawData()
|
||||
|
||||
var mst miner.State
|
||||
err = mst.UnmarshalCBOR(bytes.NewReader(aso))
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
info, err := mst.GetInfo(adt.WrapStore(ctx, cst))
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
worker := info.Worker
|
||||
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
bv.mx.Lock()
|
||||
bv.keycache[addr.String()] = key
|
||||
bv.mx.Unlock()
|
||||
}
|
||||
|
||||
// TODO I have a feeling all this can be simplified by cleverer DI to use the API
|
||||
ts := bv.chain.GetHeaviestTipSet()
|
||||
st, _, err := bv.stmgr.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore())
|
||||
cst := cbor.NewCborStore(buf)
|
||||
state, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
act, err := state.GetActor(addr)
|
||||
// we check that the miner met the minimum power at the lookback tipset
|
||||
|
||||
baseTs, err := bv.stmgr.ChainStore().LoadTipSet(types.NewTipSetKey(bh.Parents...))
|
||||
if err != nil {
|
||||
log.Warnf("failed to load parent tipset of incoming block")
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
blk, err := bv.chain.Blockstore().Get(act.Head)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
aso := blk.RawData()
|
||||
|
||||
var mst miner.State
|
||||
err = mst.UnmarshalCBOR(bytes.NewReader(aso))
|
||||
lbts, err := stmgr.GetLookbackTipSetForRound(ctx, bv.stmgr, baseTs, bh.Height)
|
||||
if err != nil {
|
||||
log.Warnf("failed to load lookback tipset for incoming block")
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
info, err := mst.GetInfo(adt.WrapStore(ctx, cst))
|
||||
hmp, err := stmgr.MinerHasMinPower(ctx, bv.stmgr, bh.Miner, lbts)
|
||||
if err != nil {
|
||||
log.Warnf("failed to determine if incoming block's miner has minimum power")
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
worker := info.Worker
|
||||
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
if !hmp {
|
||||
log.Warnf("incoming block's miner does not have minimum power")
|
||||
return address.Undef, xerrors.New("incoming block's miner does not have minimum power")
|
||||
}
|
||||
|
||||
bv.mx.Lock()
|
||||
bv.keycache[addr.String()] = key
|
||||
bv.mx.Unlock()
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
|
@ -738,6 +738,15 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
return xerrors.Errorf("block is not claiming to be a winner")
|
||||
}
|
||||
|
||||
hp, err := stmgr.MinerHasMinPower(ctx, syncer.sm, h.Miner, lbts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||
}
|
||||
|
||||
if !hp {
|
||||
return xerrors.New("block's miner does not meet minimum power threshold")
|
||||
}
|
||||
|
||||
rBeacon := *prevBeacon
|
||||
if len(h.BeaconEntries) != 0 {
|
||||
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
const BigIntMaxSerializedLen = 128 // is this big enough? or too big?
|
||||
|
||||
var TotalFilecoinInt = FromFil(build.TotalFilecoin)
|
||||
var TotalFilecoinInt = FromFil(build.FilBase)
|
||||
|
||||
var EmptyInt = BigInt{}
|
||||
|
||||
|
@ -135,7 +135,7 @@ func (a *Applier) applyMessage(epoch abi.ChainEpoch, lm types.ChainMsg) (vtypes.
|
||||
ctx := context.TODO()
|
||||
base := a.stateWrapper.Root()
|
||||
|
||||
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, a.syscalls)
|
||||
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, a.syscalls, nil)
|
||||
// need to modify the VM invoker to add the puppet actor
|
||||
chainValInvoker := vm.NewInvoker()
|
||||
chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{})
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
samarket "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
gruntime "runtime"
|
||||
"time"
|
||||
|
||||
@ -60,38 +61,62 @@ type Runtime struct {
|
||||
}
|
||||
|
||||
func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount {
|
||||
total := types.FromFil(build.TotalFilecoin)
|
||||
|
||||
filVested, err := rt.vm.GetVestedFunds(rt.ctx)
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get vested funds for computing total supply: %s", err)
|
||||
}
|
||||
|
||||
rew, err := rt.state.GetActor(builtin.RewardActorAddr)
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get reward actor for computing total supply: %s", err)
|
||||
}
|
||||
|
||||
filMined := types.BigSub(types.FromFil(build.FilAllocStorageMining), rew.Balance)
|
||||
if filMined.LessThan(big.Zero()) {
|
||||
filMined = big.Zero()
|
||||
}
|
||||
|
||||
burnt, err := rt.state.GetActor(builtin.BurntFundsActorAddr)
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get reward actor for computing total supply: %s", err)
|
||||
}
|
||||
|
||||
filBurned := burnt.Balance
|
||||
|
||||
market, err := rt.state.GetActor(builtin.StorageMarketActorAddr)
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get reward actor for computing total supply: %s", err)
|
||||
}
|
||||
|
||||
var mst samarket.State
|
||||
if err := rt.cst.Get(rt.ctx, market.Head, &mst); err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get market state: %s", err)
|
||||
}
|
||||
|
||||
filMarketLocked := types.BigAdd(mst.TotalClientLockedCollateral, mst.TotalProviderLockedCollateral)
|
||||
filMarketLocked = types.BigAdd(filMarketLocked, mst.TotalClientStorageFee)
|
||||
|
||||
power, err := rt.state.GetActor(builtin.StoragePowerActorAddr)
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get reward actor for computing total supply: %s", err)
|
||||
}
|
||||
|
||||
total = types.BigSub(total, rew.Balance)
|
||||
total = types.BigSub(total, burnt.Balance)
|
||||
total = types.BigSub(total, market.Balance)
|
||||
|
||||
var st sapower.State
|
||||
if err := rt.cst.Get(rt.ctx, power.Head, &st); err != nil {
|
||||
var pst sapower.State
|
||||
if err := rt.cst.Get(rt.ctx, power.Head, &pst); err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to get storage power state: %s", err)
|
||||
}
|
||||
|
||||
return types.BigSub(total, st.TotalPledgeCollateral)
|
||||
filLocked := types.BigAdd(filMarketLocked, pst.TotalPledgeCollateral)
|
||||
|
||||
ret := types.BigAdd(filVested, filMined)
|
||||
ret = types.BigSub(ret, filBurned)
|
||||
ret = types.BigSub(ret, filLocked)
|
||||
|
||||
if ret.LessThan(big.Zero()) {
|
||||
ret = big.Zero()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (rt *Runtime) ResolveAddress(addr address.Address) (ret address.Address, ok bool) {
|
||||
|
@ -138,6 +138,8 @@ func (vm *UnsafeVM) MakeRuntime(ctx context.Context, msg *types.Message, origin
|
||||
return vm.VM.makeRuntime(ctx, msg, origin, originNonce, usedGas, nac)
|
||||
}
|
||||
|
||||
type VestedCalculator func(context.Context, abi.ChainEpoch) (abi.TokenAmount, error)
|
||||
|
||||
type VM struct {
|
||||
cstate *state.StateTree
|
||||
base cid.Cid
|
||||
@ -146,11 +148,12 @@ type VM struct {
|
||||
blockHeight abi.ChainEpoch
|
||||
inv *Invoker
|
||||
rand Rand
|
||||
vc VestedCalculator
|
||||
|
||||
Syscalls SyscallBuilder
|
||||
}
|
||||
|
||||
func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, cbs blockstore.Blockstore, syscalls SyscallBuilder) (*VM, error) {
|
||||
func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, cbs blockstore.Blockstore, syscalls SyscallBuilder, vestedCalc VestedCalculator) (*VM, error) {
|
||||
buf := bufbstore.NewBufferedBstore(cbs)
|
||||
cst := cbor.NewCborStore(buf)
|
||||
state, err := state.LoadStateTree(cst, base)
|
||||
@ -166,6 +169,7 @@ func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, cbs blockstore.Blockstor
|
||||
blockHeight: height,
|
||||
inv: NewInvoker(),
|
||||
rand: r, // TODO: Probably should be a syscall
|
||||
vc: vestedCalc,
|
||||
Syscalls: syscalls,
|
||||
}, nil
|
||||
}
|
||||
@ -675,6 +679,10 @@ func (vm *VM) SetInvoker(i *Invoker) {
|
||||
vm.inv = i
|
||||
}
|
||||
|
||||
func (vm *VM) GetVestedFunds(ctx context.Context) (abi.TokenAmount, error) {
|
||||
return vm.vc(ctx, vm.blockHeight)
|
||||
}
|
||||
|
||||
func (vm *VM) incrementNonce(addr address.Address) error {
|
||||
return vm.cstate.MutateActor(addr, func(a *types.Actor) error {
|
||||
a.Nonce++
|
||||
|
@ -131,7 +131,15 @@ func LoadTipSet(ctx context.Context, cctx *cli.Context, api api.FullNode) (*type
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return ParseTipSetRef(ctx, api, tss)
|
||||
}
|
||||
|
||||
func ParseTipSetRef(ctx context.Context, api api.FullNode, tss string) (*types.TipSet, error) {
|
||||
if tss[0] == '@' {
|
||||
if tss == "@head" {
|
||||
return api.ChainHead(ctx)
|
||||
}
|
||||
|
||||
var h uint64
|
||||
if _, err := fmt.Sscanf(tss, "@%d", &h); err != nil {
|
||||
return nil, xerrors.Errorf("parsing height tipset ref: %w", err)
|
||||
|
@ -21,7 +21,7 @@ func main() {
|
||||
keyinfoCmd,
|
||||
noncefix,
|
||||
bigIntParseCmd,
|
||||
staterootStatsCmd,
|
||||
staterootCmd,
|
||||
importCarCmd,
|
||||
commpToCidCmd,
|
||||
fetchParamCmd,
|
||||
|
@ -2,17 +2,29 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/multiformats/go-multihash"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
|
||||
var staterootStatsCmd = &cli.Command{
|
||||
Name: "stateroot-stats",
|
||||
var staterootCmd = &cli.Command{
|
||||
Name: "stateroot",
|
||||
Subcommands: []*cli.Command{
|
||||
staterootDiffsCmd,
|
||||
staterootStatCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var staterootDiffsCmd = &cli.Command{
|
||||
Name: "diffs",
|
||||
Description: "Walk down the chain and collect stats-obj changes between tipsets",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@ -92,3 +104,101 @@ var staterootStatsCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type statItem struct {
|
||||
Addr address.Address
|
||||
Actor *types.Actor
|
||||
Stat api.ObjStat
|
||||
}
|
||||
|
||||
var staterootStatCmd = &cli.Command{
|
||||
Name: "stat",
|
||||
Usage: "print statistics for the stateroot of a given block",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
Usage: "specify tipset to start from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
ts, err := lcli.LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ts == nil {
|
||||
ts, err = api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var addrs []address.Address
|
||||
|
||||
for _, inp := range cctx.Args().Slice() {
|
||||
a, err := address.NewFromString(inp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addrs = append(addrs, a)
|
||||
}
|
||||
|
||||
if len(addrs) == 0 {
|
||||
allActors, err := api.StateListActors(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addrs = allActors
|
||||
}
|
||||
|
||||
var infos []statItem
|
||||
for _, a := range addrs {
|
||||
act, err := api.StateGetActor(ctx, a, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stat, err := api.ChainStatObj(ctx, act.Head, cid.Undef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infos = append(infos, statItem{
|
||||
Addr: a,
|
||||
Actor: act,
|
||||
Stat: stat,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(infos, func(i, j int) bool {
|
||||
return infos[i].Stat.Size > infos[j].Stat.Size
|
||||
})
|
||||
|
||||
outcap := 10
|
||||
if cctx.Args().Len() > outcap {
|
||||
outcap = cctx.Args().Len()
|
||||
}
|
||||
if len(infos) < outcap {
|
||||
outcap = len(infos)
|
||||
}
|
||||
|
||||
fmt.Print("Addr\tType\tSize\n")
|
||||
for _, inf := range infos[:outcap] {
|
||||
cmh, err := multihash.Decode(inf.Actor.Code.Hash())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s\t%s\t%d\n", inf.Addr, string(cmh.Digest), inf.Stat.Size)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -23,7 +23,7 @@ require (
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
||||
github.com/filecoin-project/go-data-transfer v0.5.1
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f
|
||||
github.com/filecoin-project/go-fil-markets v0.5.2-0.20200728110539-caae3fda6623
|
||||
github.com/filecoin-project/go-fil-markets v0.5.2
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24
|
||||
github.com/filecoin-project/go-multistore v0.0.2
|
||||
github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261
|
||||
|
4
go.sum
4
go.sum
@ -244,8 +244,8 @@ github.com/filecoin-project/go-data-transfer v0.5.1/go.mod h1:PRs78hp9u8T4G2Jce5
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA=
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s=
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
|
||||
github.com/filecoin-project/go-fil-markets v0.5.2-0.20200728110539-caae3fda6623 h1:LuX25+rzM56XX+M4413ngRA+RAhm88vlFbsvbVtpcDc=
|
||||
github.com/filecoin-project/go-fil-markets v0.5.2-0.20200728110539-caae3fda6623/go.mod h1:zDhwmUy/AS/xCJOayW7Cedff9SDuSdGIWRnGXBDjcOk=
|
||||
github.com/filecoin-project/go-fil-markets v0.5.2 h1:4xW3JoPnPDKP+f4s/tWLmuYaReGdjetHZT7qgXivdiw=
|
||||
github.com/filecoin-project/go-fil-markets v0.5.2/go.mod h1:zDhwmUy/AS/xCJOayW7Cedff9SDuSdGIWRnGXBDjcOk=
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24 h1:Jc7vkplmZYVuaEcSXGHDwefvZIdoyyaoGDLqSr8Svms=
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24/go.mod h1:j6zV//WXIIY5kky873Q3iIKt/ViOE8rcijovmpxrXzM=
|
||||
github.com/filecoin-project/go-multistore v0.0.2 h1:JZEddnXXt3mMzHi7bi9IH7Yi1NpGLy19J5Lk/xbxBMs=
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
|
||||
@ -271,15 +270,6 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error)
|
||||
return m.lastWork, nil
|
||||
}
|
||||
|
||||
func (m *Miner) hasPower(ctx context.Context, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||
mpower, err := m.api.StateMinerPower(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return mpower.MinerPower.QualityAdjPower.GreaterThanEqual(power.ConsensusMinerMinPower), nil
|
||||
}
|
||||
|
||||
// mineOne attempts to mine a single block, and does so synchronously, if and
|
||||
// only if we are eligible to mine.
|
||||
//
|
||||
@ -303,6 +293,10 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg,
|
||||
if mbi == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if !mbi.HasMinPower {
|
||||
// slashed or just have no power yet
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tMBI := build.Clock.Now()
|
||||
|
||||
@ -311,15 +305,6 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg,
|
||||
tDrand := build.Clock.Now()
|
||||
bvals := mbi.BeaconEntries
|
||||
|
||||
hasPower, err := m.hasPower(ctx, m.address, base.TipSet)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("checking if miner is slashed: %w", err)
|
||||
}
|
||||
if !hasPower {
|
||||
// slashed or just have no power yet
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tPowercheck := build.Clock.Now()
|
||||
|
||||
log.Infof("Time delta between now and our mining base: %ds (nulls: %d)", uint64(build.Clock.Now().Unix())-base.TipSet.MinTimestamp(), base.NullRounds)
|
||||
|
Loading…
Reference in New Issue
Block a user