Merge branch 'next' into feat/cid-builder

This commit is contained in:
Aayush Rajasekaran 2020-07-28 21:02:30 -04:00 committed by GitHub
commit b51e2a868b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 381 additions and 136 deletions

View File

@ -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 {

View File

@ -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)))
}

View File

@ -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
}()

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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]

View File

@ -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{}

View File

@ -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{})

View File

@ -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) {

View File

@ -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++

View File

@ -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)

View File

@ -21,7 +21,7 @@ func main() {
keyinfoCmd,
noncefix,
bigIntParseCmd,
staterootStatsCmd,
staterootCmd,
importCarCmd,
commpToCidCmd,
fetchParamCmd,

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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)