v1 api: Cleanup message wait/search apis

This commit is contained in:
Łukasz Magiera 2021-04-02 13:52:24 +02:00
parent 64bf5b382b
commit 0103d2f621
5 changed files with 67 additions and 139 deletions

View File

@ -430,7 +430,7 @@ type FullNode interface {
StateSectorExpiration(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorExpiration, error) //perm:read StateSectorExpiration(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorExpiration, error) //perm:read
// StateSectorPartition finds deadline/partition with the specified sector // StateSectorPartition finds deadline/partition with the specified sector
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) //perm:read StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) //perm:read
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed // StateSearchMsg looks back up to limit epochs in the chain for a message, and returns its receipt and the tipset where it was executed
// //
// NOTE: If a replacing message is found on chain, this method will return // NOTE: If a replacing message is found on chain, this method will return
// a MsgLookup for the replacing message - the MsgLookup.Message will be a different // a MsgLookup for the replacing message - the MsgLookup.Message will be a different
@ -438,48 +438,16 @@ type FullNode interface {
// result of the execution of the replacing message. // result of the execution of the replacing message.
// //
// If the caller wants to ensure that exactly the requested message was executed, // If the caller wants to ensure that exactly the requested message was executed,
// they MUST check that MsgLookup.Message is equal to the provided 'cid'. // they must check that MsgLookup.Message is equal to the provided 'cid', or set the
// Without this check both the requested and original message may appear as // `allowReplaced` parameter to false. Without this check, and with `allowReplaced`
// set to true, both the requested and original message may appear as
// successfully executed on-chain, which may look like a double-spend. // successfully executed on-chain, which may look like a double-spend.
// //
// A replacing message is a message with a different CID, any of Gas values, and // A replacing message is a message with a different CID, any of Gas values, and
// different signature, but with all other parameters matching (source/destination, // different signature, but with all other parameters matching (source/destination,
// nonce, params, etc.) // nonce, params, etc.)
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error) //perm:read StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*MsgLookup, error) //perm:read
// StateSearchMsgLimited looks back up to limit epochs in the chain for a message, and returns its receipt and the tipset where it was executed // StateWaitMsg looks back up to limit epochs in the chain for a message.
//
// NOTE: If a replacing message is found on chain, this method will return
// a MsgLookup for the replacing message - the MsgLookup.Message will be a different
// CID than the one provided in the 'cid' param, MsgLookup.Receipt will contain the
// result of the execution of the replacing message.
//
// If the caller wants to ensure that exactly the requested message was executed,
// they MUST check that MsgLookup.Message is equal to the provided 'cid'.
// Without this check both the requested and original message may appear as
// successfully executed on-chain, which may look like a double-spend.
//
// A replacing message is a message with a different CID, any of Gas values, and
// different signature, but with all other parameters matching (source/destination,
// nonce, params, etc.)
StateSearchMsgLimited(ctx context.Context, msg cid.Cid, limit abi.ChainEpoch) (*MsgLookup, error) //perm:read
// 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.
//
// NOTE: If a replacing message is found on chain, this method will return
// a MsgLookup for the replacing message - the MsgLookup.Message will be a different
// CID than the one provided in the 'cid' param, MsgLookup.Receipt will contain the
// result of the execution of the replacing message.
//
// If the caller wants to ensure that exactly the requested message was executed,
// they MUST check that MsgLookup.Message is equal to the provided 'cid'.
// Without this check both the requested and original message may appear as
// successfully executed on-chain, which may look like a double-spend.
//
// A replacing message is a message with a different CID, any of Gas values, and
// different signature, but with all other parameters matching (source/destination,
// nonce, params, etc.)
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error) //perm:read
// StateWaitMsgLimited looks back up to limit epochs in the chain for a message.
// If not found, it blocks until the message arrives on chain, and gets to the // If not found, it blocks until the message arrives on chain, and gets to the
// indicated confidence depth. // indicated confidence depth.
// //
@ -489,14 +457,15 @@ type FullNode interface {
// result of the execution of the replacing message. // result of the execution of the replacing message.
// //
// If the caller wants to ensure that exactly the requested message was executed, // If the caller wants to ensure that exactly the requested message was executed,
// they MUST check that MsgLookup.Message is equal to the provided 'cid'. // they must check that MsgLookup.Message is equal to the provided 'cid', or set the
// Without this check both the requested and original message may appear as // `allowReplaced` parameter to false. Without this check, and with `allowReplaced`
// set to true, both the requested and original message may appear as
// successfully executed on-chain, which may look like a double-spend. // successfully executed on-chain, which may look like a double-spend.
// //
// A replacing message is a message with a different CID, any of Gas values, and // A replacing message is a message with a different CID, any of Gas values, and
// different signature, but with all other parameters matching (source/destination, // different signature, but with all other parameters matching (source/destination,
// nonce, params, etc.) // nonce, params, etc.)
StateWaitMsgLimited(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch) (*MsgLookup, error) //perm:read StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*MsgLookup, error) //perm:read
// StateListMiners returns the addresses of every miner that has claimed power in the Power Actor // StateListMiners returns the addresses of every miner that has claimed power in the Power Actor
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error) //perm:read StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error) //perm:read
// StateListActors returns the addresses of every actor in the state // StateListActors returns the addresses of every actor in the state
@ -516,16 +485,6 @@ type FullNode interface {
// StateChangedActors returns all the actors whose states change between the two given state CIDs // StateChangedActors returns all the actors whose states change between the two given state CIDs
// TODO: Should this take tipset keys instead? // TODO: Should this take tipset keys instead?
StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) //perm:read StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) //perm:read
// StateGetReceipt returns the message receipt for the given message or for a
// matching gas-repriced replacing message
//
// NOTE: If the requested message was replaced, this method will return the receipt
// for the replacing message - if the caller needs the receipt for exactly the
// requested message, use StateSearchMsg().Receipt, and check that MsgLookup.Message
// is matching the requested CID
//
// DEPRECATED: Use StateSearchMsg, this method won't be supported in v1 API
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) //perm:read
// StateMinerSectorCount returns the number of sectors in a miner's sector set and proving set // StateMinerSectorCount returns the number of sectors in a miner's sector set and proving set
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error) //perm:read StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error) //perm:read
// StateCompute is a flexible command that applies the given messages on the given tipset. // StateCompute is a flexible command that applies the given messages on the given tipset.

View File

@ -330,8 +330,6 @@ type FullNodeStruct struct {
StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"` StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateGetReceipt func(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"`
StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"`
StateListMessages func(p0 context.Context, p1 *MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"` StateListMessages func(p0 context.Context, p1 *MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
@ -384,9 +382,7 @@ type FullNodeStruct struct {
StateReplay func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*InvocResult, error) `perm:"read"` StateReplay func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*InvocResult, error) `perm:"read"`
StateSearchMsg func(p0 context.Context, p1 cid.Cid) (*MsgLookup, error) `perm:"read"` StateSearchMsg func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"`
StateSearchMsgLimited func(p0 context.Context, p1 cid.Cid, p2 abi.ChainEpoch) (*MsgLookup, error) `perm:"read"`
StateSectorExpiration func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorExpiration, error) `perm:"read"` StateSectorExpiration func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorExpiration, error) `perm:"read"`
@ -404,9 +400,7 @@ type FullNodeStruct struct {
StateVerifierStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` StateVerifierStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64) (*MsgLookup, error) `perm:"read"` StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"`
StateWaitMsgLimited func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch) (*MsgLookup, error) `perm:"read"`
SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"` SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"`
@ -1334,10 +1328,6 @@ func (s *FullNodeStruct) StateGetActor(p0 context.Context, p1 address.Address, p
return s.Internal.StateGetActor(p0, p1, p2) return s.Internal.StateGetActor(p0, p1, p2)
} }
func (s *FullNodeStruct) StateGetReceipt(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) {
return s.Internal.StateGetReceipt(p0, p1, p2)
}
func (s *FullNodeStruct) StateListActors(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) { func (s *FullNodeStruct) StateListActors(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) {
return s.Internal.StateListActors(p0, p1) return s.Internal.StateListActors(p0, p1)
} }
@ -1442,12 +1432,8 @@ func (s *FullNodeStruct) StateReplay(p0 context.Context, p1 types.TipSetKey, p2
return s.Internal.StateReplay(p0, p1, p2) return s.Internal.StateReplay(p0, p1, p2)
} }
func (s *FullNodeStruct) StateSearchMsg(p0 context.Context, p1 cid.Cid) (*MsgLookup, error) { func (s *FullNodeStruct) StateSearchMsg(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) {
return s.Internal.StateSearchMsg(p0, p1) return s.Internal.StateSearchMsg(p0, p1, p2, p3, p4)
}
func (s *FullNodeStruct) StateSearchMsgLimited(p0 context.Context, p1 cid.Cid, p2 abi.ChainEpoch) (*MsgLookup, error) {
return s.Internal.StateSearchMsgLimited(p0, p1, p2)
} }
func (s *FullNodeStruct) StateSectorExpiration(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorExpiration, error) { func (s *FullNodeStruct) StateSectorExpiration(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorExpiration, error) {
@ -1482,12 +1468,8 @@ func (s *FullNodeStruct) StateVerifierStatus(p0 context.Context, p1 address.Addr
return s.Internal.StateVerifierStatus(p0, p1, p2) return s.Internal.StateVerifierStatus(p0, p1, p2)
} }
func (s *FullNodeStruct) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64) (*MsgLookup, error) { func (s *FullNodeStruct) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) {
return s.Internal.StateWaitMsg(p0, p1, p2) return s.Internal.StateWaitMsg(p0, p1, p2, p3, p4)
}
func (s *FullNodeStruct) StateWaitMsgLimited(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch) (*MsgLookup, error) {
return s.Internal.StateWaitMsgLimited(p0, p1, p2, p3)
} }
func (s *FullNodeStruct) SyncCheckBad(p0 context.Context, p1 cid.Cid) (string, error) { func (s *FullNodeStruct) SyncCheckBad(p0 context.Context, p1 cid.Cid) (string, error) {

View File

@ -1,32 +1,50 @@
package v0api package v0api
import ( import (
"context"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/v1api" "github.com/filecoin-project/lotus/api/v1api"
"github.com/filecoin-project/lotus/chain/stmgr"
) )
type WrapperV1Full struct { type WrapperV1Full struct {
v1api.FullNode v1api.FullNode
} }
/* example: func (w *WrapperV1Full) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) {
- dropped StateGetReceipt return w.FullNode.StateSearchMsg(ctx, types.EmptyTSK, msg, stmgr.LookbackNoLimit, true)
- tsk param for StateSearchMsg
func (w *WrapperV1Full) StateSearchMsg(ctx context.Context, c cid.Cid) (*api.MsgLookup, error) {
return w.FullNode.StateSearchMsg(ctx, c, types.EmptyTSK)
} }
func (w *WrapperV1Full) StateGetReceipt(ctx context.Context, cid cid.Cid, key types.TipSetKey) (*types.MessageReceipt, error) { func (w *WrapperV1Full) StateSearchMsgLimited(ctx context.Context, msg cid.Cid, limit abi.ChainEpoch) (*api.MsgLookup, error) {
m, err := w.FullNode.StateSearchMsg(ctx, cid, key) return w.FullNode.StateSearchMsg(ctx, types.EmptyTSK, msg, limit, true)
}
func (w *WrapperV1Full) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return w.FullNode.StateWaitMsg(ctx, msg, confidence, stmgr.LookbackNoLimit, true)
}
func (w *WrapperV1Full) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, limit abi.ChainEpoch) (*api.MsgLookup, error) {
return w.FullNode.StateWaitMsg(ctx, msg, confidence, limit, true)
}
func (w *WrapperV1Full) StateGetReceipt(ctx context.Context, msg cid.Cid, from types.TipSetKey) (*types.MessageReceipt, error) {
ml, err := w.FullNode.StateSearchMsg(ctx, from, msg, stmgr.LookbackNoLimit, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if m == nil { if ml == nil {
return nil, nil return nil, nil
} }
return &m.Receipt, nil return &ml.Receipt, nil
}*/ }
var _ FullNode = &WrapperV1Full{} var _ FullNode = &WrapperV1Full{}

View File

@ -564,24 +564,10 @@ func (sm *StateManager) LookupID(ctx context.Context, addr address.Address, ts *
return state.LookupID(addr) return state.LookupID(addr)
} }
func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.TipSet) (*types.MessageReceipt, error) {
m, err := sm.cs.GetCMessage(msg)
if err != nil {
return nil, fmt.Errorf("failed to load message: %w", err)
}
_, r, _, err := sm.searchBackForMsg(ctx, ts, m, LookbackNoLimit)
if err != nil {
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
}
return r, nil
}
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already // WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
// happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on // happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on
// chain for at least confidence epochs without being reverted before returning. // chain for at least confidence epochs without being reverted before returning.
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) { func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch, allowReplaced bool) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@ -605,7 +591,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
return nil, nil, cid.Undef, fmt.Errorf("expected current head on SHC stream (got %s)", head[0].Type) return nil, nil, cid.Undef, fmt.Errorf("expected current head on SHC stream (got %s)", head[0].Type)
} }
r, foundMsg, err := sm.tipsetExecutedMessage(head[0].Val, mcid, msg.VMMessage()) r, foundMsg, err := sm.tipsetExecutedMessage(head[0].Val, mcid, msg.VMMessage(), allowReplaced)
if err != nil { if err != nil {
return nil, nil, cid.Undef, err return nil, nil, cid.Undef, err
} }
@ -619,7 +605,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
var backFm cid.Cid var backFm cid.Cid
backSearchWait := make(chan struct{}) backSearchWait := make(chan struct{})
go func() { go func() {
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg, lookbackLimit) fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg, lookbackLimit, allowReplaced)
if err != nil { if err != nil {
log.Warnf("failed to look back through chain for message: %v", err) log.Warnf("failed to look back through chain for message: %v", err)
return return
@ -658,7 +644,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) { if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) {
return candidateTs, candidateRcp, candidateFm, nil return candidateTs, candidateRcp, candidateFm, nil
} }
r, foundMsg, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage()) r, foundMsg, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage(), allowReplaced)
if err != nil { if err != nil {
return nil, nil, cid.Undef, err return nil, nil, cid.Undef, err
} }
@ -694,15 +680,13 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
} }
} }
func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid, lookbackLimit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) { func (sm *StateManager) SearchForMessage(ctx context.Context, head *types.TipSet, mcid cid.Cid, lookbackLimit abi.ChainEpoch, allowReplaced bool) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
msg, err := sm.cs.GetCMessage(mcid) msg, err := sm.cs.GetCMessage(mcid)
if err != nil { if err != nil {
return nil, nil, cid.Undef, fmt.Errorf("failed to load message: %w", err) return nil, nil, cid.Undef, fmt.Errorf("failed to load message: %w", err)
} }
head := sm.cs.GetHeaviestTipSet() r, foundMsg, err := sm.tipsetExecutedMessage(head, mcid, msg.VMMessage(), allowReplaced)
r, foundMsg, err := sm.tipsetExecutedMessage(head, mcid, msg.VMMessage())
if err != nil { if err != nil {
return nil, nil, cid.Undef, err return nil, nil, cid.Undef, err
} }
@ -711,7 +695,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid, look
return head, r, foundMsg, nil return head, r, foundMsg, nil
} }
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg, lookbackLimit) fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg, lookbackLimit, allowReplaced)
if err != nil { if err != nil {
log.Warnf("failed to look back through chain for message %s", mcid) log.Warnf("failed to look back through chain for message %s", mcid)
@ -731,7 +715,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid, look
// - 0 then no tipsets are searched // - 0 then no tipsets are searched
// - 5 then five tipset are searched // - 5 then five tipset are searched
// - LookbackNoLimit then there is no limit // - LookbackNoLimit then there is no limit
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg, limit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) { func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg, limit abi.ChainEpoch, allowReplaced bool) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
limitHeight := from.Height() - limit limitHeight := from.Height() - limit
noLimit := limit == LookbackNoLimit noLimit := limit == LookbackNoLimit
@ -781,7 +765,7 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
// check that between cur and parent tipset the nonce fell into range of our message // check that between cur and parent tipset the nonce fell into range of our message
if actorNoExist || (curActor.Nonce > mNonce && act.Nonce <= mNonce) { if actorNoExist || (curActor.Nonce > mNonce && act.Nonce <= mNonce) {
r, foundMsg, err := sm.tipsetExecutedMessage(cur, m.Cid(), m.VMMessage()) r, foundMsg, err := sm.tipsetExecutedMessage(cur, m.Cid(), m.VMMessage(), allowReplaced)
if err != nil { if err != nil {
return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err) return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err)
} }
@ -796,7 +780,7 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
} }
} }
func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm *types.Message) (*types.MessageReceipt, cid.Cid, error) { func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm *types.Message, allowReplaced bool) (*types.MessageReceipt, cid.Cid, error) {
// The genesis block did not execute any messages // The genesis block did not execute any messages
if ts.Height() == 0 { if ts.Height() == 0 {
return nil, cid.Undef, nil return nil, cid.Undef, nil
@ -819,7 +803,7 @@ func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm
if m.VMMessage().From == vmm.From { // cheaper to just check origin first if m.VMMessage().From == vmm.From { // cheaper to just check origin first
if m.VMMessage().Nonce == vmm.Nonce { if m.VMMessage().Nonce == vmm.Nonce {
if m.VMMessage().EqualCall(vmm) { if allowReplaced && m.VMMessage().EqualCall(vmm) {
if m.Cid() != msg { if m.Cid() != msg {
log.Warnw("found message with equal nonce and call params but different CID", log.Warnw("found message with equal nonce and call params but different CID",
"wanted", msg, "found", m.Cid(), "nonce", vmm.Nonce, "from", vmm.From) "wanted", msg, "found", m.Cid(), "nonce", vmm.Nonce, "from", vmm.From)

View File

@ -520,28 +520,22 @@ func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate)
return &out, nil return &out, nil
} }
func (m *StateModule) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) { func (m *StateModule) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*api.MsgLookup, error) {
return stateWaitMsgLimited(ctx, m.StateManager, m.Chain, msg, confidence, stmgr.LookbackNoLimit) ts, recpt, found, err := m.StateManager.WaitForMessage(ctx, msg, confidence, lookbackLimit)
}
func (a *StateAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*api.MsgLookup, error) {
return stateWaitMsgLimited(ctx, a.StateManager, a.Chain, msg, confidence, lookbackLimit)
}
func stateWaitMsgLimited(ctx context.Context, smgr *stmgr.StateManager, cstore *store.ChainStore, msg cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*api.MsgLookup, error) {
ts, recpt, found, err := smgr.WaitForMessage(ctx, msg, confidence, lookbackLimit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var returndec interface{} var returndec interface{}
if recpt.ExitCode == 0 && len(recpt.Return) > 0 { if recpt.ExitCode == 0 && len(recpt.Return) > 0 {
cmsg, err := cstore.GetCMessage(msg) cmsg, err := m.Chain.GetCMessage(msg)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to load message after successful receipt search: %w", err) return nil, xerrors.Errorf("failed to load message after successful receipt search: %w", err)
} }
vmsg := cmsg.VMMessage() vmsg := cmsg.VMMessage()
t, err := stmgr.GetReturnType(ctx, smgr, vmsg.To, vmsg.Method, ts) t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get return type: %w", err) return nil, xerrors.Errorf("failed to get return type: %w", err)
} }
@ -562,14 +556,13 @@ func stateWaitMsgLimited(ctx context.Context, smgr *stmgr.StateManager, cstore *
}, nil }, nil
} }
func (m *StateModule) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) { func (m *StateModule) StateSearchMsg(ctx context.Context, tsk types.TipSetKey, msg cid.Cid, lookbackLimit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) {
return stateSearchMsgLimited(ctx, m.StateManager, msg, stmgr.LookbackNoLimit) fromTs, err := m.Chain.GetTipSetFromKey(tsk)
} if err != nil {
func (a *StateAPI) StateSearchMsgLimited(ctx context.Context, msg cid.Cid, lookbackLimit abi.ChainEpoch) (*api.MsgLookup, error) { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
return stateSearchMsgLimited(ctx, a.StateManager, msg, lookbackLimit) }
}
func stateSearchMsgLimited(ctx context.Context, smgr *stmgr.StateManager, msg cid.Cid, lookbackLimit abi.ChainEpoch) (*api.MsgLookup, error) { ts, recpt, found, err := m.StateManager.SearchForMessage(ctx, fromTs, msg, lookbackLimit, allowReplaced)
ts, recpt, found, err := smgr.SearchForMessage(ctx, msg, lookbackLimit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -585,14 +578,6 @@ func stateSearchMsgLimited(ctx context.Context, smgr *stmgr.StateManager, msg ci
return nil, nil return nil, nil
} }
func (m *StateModule) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) {
ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return m.StateManager.GetReceipt(ctx, msg, ts)
}
func (m *StateModule) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { func (m *StateModule) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
ts, err := m.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {