fix miner message filter nonce checking

This commit is contained in:
whyrusleeping 2019-12-02 22:41:28 -08:00 committed by Łukasz Magiera
parent 8e09fd6ca8
commit 9ad4a00cda
5 changed files with 67 additions and 11 deletions

View File

@ -29,6 +29,7 @@ type FullNode interface {
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
ChainGetTipSetMessages(context.Context, types.TipSetKey) ([]Message, error)
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainSetHead(context.Context, *types.TipSet) error

View File

@ -45,6 +45,7 @@ type FullNodeStruct struct {
ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"`
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"`
ChainGetTipSetMessages func(context.Context, types.TipSetKey) ([]Message, error) `perm:"read"`
ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"`
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"`
@ -310,6 +311,10 @@ func (c *FullNodeStruct) ChainGetParentMessages(ctx context.Context, b cid.Cid)
return c.Internal.ChainGetParentMessages(ctx, b)
}
func (c *FullNodeStruct) ChainGetTipSetMessages(ctx context.Context, tsk types.TipSetKey) ([]Message, error) {
return c.Internal.ChainGetTipSetMessages(ctx, tsk)
}
func (c *FullNodeStruct) ChainNotify(ctx context.Context) (<-chan []*store.HeadChange, error) {
return c.Internal.ChainNotify(ctx)
}

View File

@ -334,14 +334,40 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, base *M
}, nil
}
func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof) (*types.BlockMsg, error) {
func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types.TipSet) (uint64, *types.BigInt, error) {
// TODO: strong opportunities for some caching in this method
act, err := m.api.StateGetActor(ctx, addr, ts)
if err != nil {
return 0, nil, xerrors.Errorf("looking up actor failed: %w", err)
}
msgs, err := m.api.ChainGetTipSetMessages(ctx, ts.Key())
if err != nil {
return 0, nil, xerrors.Errorf("failed to get tipset messages: %w", err)
}
balance := act.Balance
curnonce := act.Nonce
for _, m := range msgs {
if m.Message.From == addr {
if m.Message.Nonce != curnonce {
return 0, nil, xerrors.Errorf("tipset messages had bad nonce: %s had nonce %d, expected %d", m.Cid, m.Message.Nonce, curnonce)
}
curnonce++
balance = types.BigSub(balance, m.Message.RequiredFunds())
}
}
return curnonce, &balance, nil
}
func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof) (*types.BlockMsg, error) {
pending, err := m.api.MpoolPending(context.TODO(), base.ts)
if err != nil {
return nil, xerrors.Errorf("failed to get pending messages: %w", err)
}
msgs, err := selectMessages(context.TODO(), m.api.StateGetActor, base, pending)
msgs, err := selectMessages(context.TODO(), m.actorLookup, base, pending)
if err != nil {
return nil, xerrors.Errorf("message filtering failed: %w", err)
}
@ -354,7 +380,7 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type
return m.api.MinerCreateBlock(context.TODO(), addr, base.ts, ticket, proof, msgs, nheight, uint64(uts))
}
type actorLookup func(context.Context, address.Address, *types.TipSet) (*types.Actor, error)
type actorLookup func(context.Context, address.Address, *types.TipSet) (uint64, *types.BigInt, error)
func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs []*types.SignedMessage) ([]*types.SignedMessage, error) {
out := make([]*types.SignedMessage, 0, len(msgs))
@ -367,14 +393,15 @@ func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs
}
from := msg.Message.From
act, err := al(ctx, from, base.ts)
if err != nil {
return nil, xerrors.Errorf("failed to check message sender balance: %w", err)
}
if _, ok := inclNonces[from]; !ok {
inclNonces[from] = act.Nonce
inclBalances[from] = act.Balance
nonce, balance, err := al(ctx, from, base.ts)
if err != nil {
return nil, xerrors.Errorf("failed to check message sender balance: %w", err)
}
inclNonces[from] = nonce
inclBalances[from] = *balance
}
if inclBalances[from].LessThan(msg.Message.RequiredFunds()) {

View File

@ -33,8 +33,8 @@ func TestMessageFiltering(t *testing.T) {
},
}
af := func(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, error) {
return actors[addr], nil
af := func(ctx context.Context, addr address.Address, ts *types.TipSet) (uint64, *types.BigInt, error) {
return actors[addr].Nonce, &actors[addr].Balance, nil
}
msgs := []types.Message{

View File

@ -68,6 +68,7 @@ func (a *ChainAPI) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api
}, nil
}
// TODO: Maybe deprecate in favor of just using ChainGetTipSetMessages?
func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([]api.Message, error) {
b, err := a.Chain.GetBlock(bcid)
if err != nil {
@ -101,6 +102,28 @@ func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([]
return out, nil
}
func (a *ChainAPI) ChainGetTipSetMessages(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) {
ts, err := a.Chain.LoadTipSet(tsk.Cids())
if err != nil {
return nil, xerrors.Errorf("failed to load tipset from key: %w", err)
}
messages, err := a.Chain.MessagesForTipset(ts)
if err != nil {
return nil, xerrors.Errorf("getting messages for tipset: %w", err)
}
var out []api.Message
for _, m := range messages {
out = append(out, api.Message{
Cid: m.Cid(),
Message: m.VMMessage(),
})
}
return out, nil
}
func (a *ChainAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Cid) ([]*types.MessageReceipt, error) {
b, err := a.Chain.GetBlock(bcid)
if err != nil {