Skip to content

Commit

Permalink
Merge branch 'master' into feat/chaos-inspect-runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
raulk committed Sep 16, 2020
2 parents ed4caac + b78ffd1 commit 4fbb322
Show file tree
Hide file tree
Showing 22 changed files with 290 additions and 74 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/lotus-stats
/lotus-bench
/lotus-gateway
/lotus-pcr
/bench.json
/lotuspond/front/node_modules
/lotuspond/front/build
Expand Down
13 changes: 13 additions & 0 deletions api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ type FullNode interface {
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
// StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
StateMsgGasCost(context.Context, cid.Cid, types.TipSetKey) (*MsgGasCost, error)
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
// message arrives on chain, and gets to the indicated confidence depth.
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
Expand Down Expand Up @@ -531,6 +533,17 @@ type MsgLookup struct {
Height abi.ChainEpoch
}

type MsgGasCost struct {
Message cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed
GasUsed abi.TokenAmount
BaseFeeBurn abi.TokenAmount
OverEstimationBurn abi.TokenAmount
MinerPenalty abi.TokenAmount
MinerTip abi.TokenAmount
Refund abi.TokenAmount
TotalCost abi.TokenAmount
}

type BlockMessages struct {
BlsMessages []*types.Message
SecpkMessages []*types.SignedMessage
Expand Down
5 changes: 5 additions & 0 deletions api/apistruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ type FullNodeStruct struct {
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
Expand Down Expand Up @@ -816,6 +817,10 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
return c.Internal.StateReadState(ctx, addr, tsk)
}

func (c *FullNodeStruct) StateMsgGasCost(ctx context.Context, msgc cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
return c.Internal.StateMsgGasCost(ctx, msgc, tsk)
}

func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
}
Expand Down
2 changes: 1 addition & 1 deletion build/params_2k.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func init() {
BuildType |= Build2k
}

const BlockDelaySecs = uint64(30)
const BlockDelaySecs = uint64(4)

const PropagationDelaySecs = uint64(1)

Expand Down
4 changes: 2 additions & 2 deletions chain/stmgr/stmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
}

receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, r.MinerTip)
penalty = big.Add(penalty, r.Penalty)
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)

if cb != nil {
if err := cb(cm.Cid(), m, r); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion chain/stmgr/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule

sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand)
if err != nil {
return nil, xerrors.Errorf("getting wpost proving set: %w", err)
return nil, xerrors.Errorf("getting winning post proving set: %w", err)
}

if len(sectors) == 0 {
Expand Down
25 changes: 4 additions & 21 deletions chain/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/filecoin-project/specs-actors/actors/util/adt"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/journal"
bstore "github.com/filecoin-project/lotus/lib/blockstore"
Expand Down Expand Up @@ -767,32 +766,16 @@ type BlockMessages struct {
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
applied := make(map[address.Address]uint64)

cst := cbor.NewCborStore(cs.bs)
st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot)
if err != nil {
return nil, xerrors.Errorf("failed to load state tree")
}

preloadAddr := func(a address.Address) error {
if _, ok := applied[a]; !ok {
act, err := st.GetActor(a)
if err != nil {
return err
}

applied[a] = act.Nonce
}
return nil
}

selectMsg := func(m *types.Message) (bool, error) {
if err := preloadAddr(m.From); err != nil {
return false, err
// The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise
if _, ok := applied[m.From]; !ok {
applied[m.From] = m.Nonce
}

if applied[m.From] != m.Nonce {
return false, nil
}

applied[m.From]++

return true, nil
Expand Down
2 changes: 1 addition & 1 deletion chain/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block

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 winningPost proof: %w", err)
return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err)
}

mid, err := address.IDFromAddress(h.Miner)
Expand Down
43 changes: 43 additions & 0 deletions chain/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,49 @@ func TestDuplicateNonce(t *testing.T) {
require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message")
}

// This test asserts that a block that includes a message with bad nonce can't be synced. A nonce is "bad" if it can't
// be applied on the parent state.
func TestBadNonce(t *testing.T) {
H := 10
tu := prepSyncTest(t, H)

base := tu.g.CurTipset

// Produce a message from the banker with a bad nonce
makeBadMsg := func() *types.SignedMessage {

ba, err := tu.nds[0].StateGetActor(context.TODO(), tu.g.Banker(), base.TipSet().Key())
require.NoError(t, err)
msg := types.Message{
To: tu.g.Banker(),
From: tu.g.Banker(),

Nonce: ba.Nonce + 5,

Value: types.NewInt(1),

Method: 0,

GasLimit: 100_000_000,
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
}

sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
require.NoError(t, err)

return &types.SignedMessage{
Message: msg,
Signature: *sig,
}
}

msgs := make([][]*types.SignedMessage, 1)
msgs[0] = []*types.SignedMessage{makeBadMsg()}

tu.mineOnBlock(base, 0, []int{0}, true, true, msgs)
}

func BenchmarkSyncBasic(b *testing.B) {
for i := 0; i < b.N; i++ {
runSyncBenchLength(b, 100)
Expand Down
19 changes: 12 additions & 7 deletions chain/vm/burn.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ type GasOutputs struct {
GasBurned int64
}

// ZeroGasOutputs returns a logically zeroed GasOutputs.
func ZeroGasOutputs() GasOutputs {
return GasOutputs{
BaseFeeBurn: big.Zero(),
OverEstimationBurn: big.Zero(),
MinerPenalty: big.Zero(),
MinerTip: big.Zero(),
Refund: big.Zero(),
}
}

// ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned
// Result is (refund, burn)
func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
Expand Down Expand Up @@ -58,13 +69,7 @@ func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {

func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs {
gasUsedBig := big.NewInt(gasUsed)
out := GasOutputs{
BaseFeeBurn: big.Zero(),
OverEstimationBurn: big.Zero(),
MinerPenalty: big.Zero(),
MinerTip: big.Zero(),
Refund: big.Zero(),
}
out := ZeroGasOutputs()

baseFeeToPay := baseFee
if baseFee.Cmp(feeCap.Int) > 0 {
Expand Down
35 changes: 19 additions & 16 deletions chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,9 @@ type Rand interface {
type ApplyRet struct {
types.MessageReceipt
ActorErr aerrors.ActorError
Penalty types.BigInt
MinerTip types.BigInt
ExecutionTrace types.ExecutionTrace
Duration time.Duration
GasCosts GasOutputs
}

func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
Expand Down Expand Up @@ -328,8 +327,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0),
MinerTip: types.NewInt(0),
GasCosts: GasOutputs{},
Duration: time.Since(start),
}, actorErr
}
Expand Down Expand Up @@ -357,14 +355,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
msgGasCost := msgGas.Total()
// this should never happen, but is currently still exercised by some tests
if msgGasCost > msg.GasLimit {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost))
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrOutOfGas,
GasUsed: 0,
},
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
GasCosts: gasOutputs,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

Expand All @@ -375,60 +374,65 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
// this should never happen, but is currently still exercised by some tests
if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderInvalid,
GasUsed: 0,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
Penalty: minerPenaltyAmount,
GasCosts: gasOutputs,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}
return nil, xerrors.Errorf("failed to look up from actor: %w", err)
}

// this should never happen, but is currently still exercised by some tests
if !fromActor.Code.Equals(builtin.AccountActorCodeID) {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderInvalid,
GasUsed: 0,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
Penalty: minerPenaltyAmount,
GasCosts: gasOutputs,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

if msg.Nonce != fromActor.Nonce {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderStateInvalid,
GasUsed: 0,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
Penalty: minerPenaltyAmount,

GasCosts: gasOutputs,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap)
if fromActor.Balance.LessThan(gascost) {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderStateInvalid,
GasUsed: 0,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
Penalty: minerPenaltyAmount,
GasCosts: gasOutputs,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

Expand Down Expand Up @@ -521,8 +525,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
Penalty: gasOutputs.MinerPenalty,
MinerTip: gasOutputs.MinerTip,
GasCosts: gasOutputs,
Duration: time.Since(start),
}, nil
}
Expand Down
7 changes: 7 additions & 0 deletions cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"text/tabwriter"
"time"

"github.com/filecoin-project/specs-actors/actors/builtin"

tm "github.com/buger/goterm"
"github.com/docker/go-units"
"github.com/fatih/color"
Expand Down Expand Up @@ -527,6 +529,11 @@ func interactiveDeal(cctx *cli.Context) error {
continue
}

if days < int(build.MinDealDuration/builtin.EpochsInDay) {
printErr(xerrors.Errorf("minimum duration is %d days", int(build.MinDealDuration/builtin.EpochsInDay)))
continue
}

state = "miner"
case "miner":
fmt.Print("Miner Address (t0..): ")
Expand Down
Loading

0 comments on commit 4fbb322

Please sign in to comment.