Merge pull request #4545 from filecoin-project/steb/refactor-consistent-tipset-methods
Make state tipset usage consistent in the API
This commit is contained in:
commit
ec58099cc7
@ -331,10 +331,14 @@ type FullNode interface {
|
|||||||
|
|
||||||
// MethodGroup: State
|
// MethodGroup: State
|
||||||
// The State methods are used to query, inspect, and interact with chain state.
|
// The State methods are used to query, inspect, and interact with chain state.
|
||||||
// Most methods take a TipSetKey as a parameter. The state looked up is the state at that tipset.
|
// Most methods take a TipSetKey as a parameter. The state looked up is the parent state of the tipset.
|
||||||
// A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used.
|
// A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used.
|
||||||
|
|
||||||
// StateCall runs the given message and returns its result without any persisted changes.
|
// StateCall runs the given message and returns its result without any persisted changes.
|
||||||
|
//
|
||||||
|
// StateCall applies the message to the tipset's parent state. The
|
||||||
|
// message is not applied on-top-of the messages in the passed-in
|
||||||
|
// tipset.
|
||||||
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
|
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
|
||||||
// StateReplay replays a given message, assuming it was included in a block in the specified tipset.
|
// StateReplay replays a given message, assuming it was included in a block in the specified tipset.
|
||||||
// If no tipset key is provided, the appropriate tipset is looked up.
|
// If no tipset key is provided, the appropriate tipset is looked up.
|
||||||
|
@ -89,7 +89,7 @@ func VersionForType(nodeType NodeType) (Version, error) {
|
|||||||
|
|
||||||
// semver versions of the rpc api exposed
|
// semver versions of the rpc api exposed
|
||||||
var (
|
var (
|
||||||
FullAPIVersion = newVer(1, 0, 0)
|
FullAPIVersion = newVer(1, 1, 0)
|
||||||
MinerAPIVersion = newVer(1, 0, 1)
|
MinerAPIVersion = newVer(1, 0, 1)
|
||||||
WorkerAPIVersion = newVer(1, 0, 0)
|
WorkerAPIVersion = newVer(1, 0, 0)
|
||||||
)
|
)
|
||||||
|
@ -145,20 +145,6 @@ func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Addres
|
|||||||
return mas.GetSector(sid)
|
return mas.GetSector(sid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, snos *bitfield.BitField) ([]*miner.SectorOnChainInfo, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mas, err := miner.Load(sm.cs.Store(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mas.LoadSectors(snos)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSectorsForWinningPoSt(ctx context.Context, nv network.Version, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]builtin.SectorInfo, error) {
|
func GetSectorsForWinningPoSt(ctx context.Context, nv network.Version, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]builtin.SectorInfo, error) {
|
||||||
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -573,11 +573,14 @@ func TestDuplicateNonce(t *testing.T) {
|
|||||||
|
|
||||||
base := tu.g.CurTipset
|
base := tu.g.CurTipset
|
||||||
|
|
||||||
|
// Get the banker from computed tipset state, not the parent.
|
||||||
|
st, _, err := tu.g.StateManager().TipSetState(context.TODO(), base.TipSet())
|
||||||
|
require.NoError(t, err)
|
||||||
|
ba, err := tu.g.StateManager().LoadActorRaw(context.TODO(), tu.g.Banker(), st)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Produce a message from the banker to the rcvr
|
// Produce a message from the banker to the rcvr
|
||||||
makeMsg := func(rcvr address.Address) *types.SignedMessage {
|
makeMsg := func(rcvr address.Address) *types.SignedMessage {
|
||||||
|
|
||||||
ba, err := tu.nds[0].StateGetActor(context.TODO(), tu.g.Banker(), base.TipSet().Key())
|
|
||||||
require.NoError(t, err)
|
|
||||||
msg := types.Message{
|
msg := types.Message{
|
||||||
To: rcvr,
|
To: rcvr,
|
||||||
From: tu.g.Banker(),
|
From: tu.g.Banker(),
|
||||||
|
@ -168,7 +168,7 @@ Response:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"Version": "string value",
|
"Version": "string value",
|
||||||
"APIVersion": 65536,
|
"APIVersion": 65792,
|
||||||
"BlockDelay": 42
|
"BlockDelay": 42
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -146,7 +146,7 @@ Perms: admin
|
|||||||
|
|
||||||
Inputs: `null`
|
Inputs: `null`
|
||||||
|
|
||||||
Response: `65536`
|
Response: `65792`
|
||||||
|
|
||||||
## Add
|
## Add
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ Response:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"Version": "string value",
|
"Version": "string value",
|
||||||
"APIVersion": 65536,
|
"APIVersion": 65792,
|
||||||
"BlockDelay": 42
|
"BlockDelay": 42
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -3309,7 +3309,7 @@ Response:
|
|||||||
|
|
||||||
## State
|
## State
|
||||||
The State methods are used to query, inspect, and interact with chain state.
|
The State methods are used to query, inspect, and interact with chain state.
|
||||||
Most methods take a TipSetKey as a parameter. The state looked up is the state at that tipset.
|
Most methods take a TipSetKey as a parameter. The state looked up is the parent state of the tipset.
|
||||||
A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used.
|
A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used.
|
||||||
|
|
||||||
|
|
||||||
@ -3362,6 +3362,10 @@ Response: `null`
|
|||||||
### StateCall
|
### StateCall
|
||||||
StateCall runs the given message and returns its result without any persisted changes.
|
StateCall runs the given message and returns its result without any persisted changes.
|
||||||
|
|
||||||
|
StateCall applies the message to the tipset's parent state. The
|
||||||
|
message is not applied on-top-of the messages in the passed-in
|
||||||
|
tipset.
|
||||||
|
|
||||||
|
|
||||||
Perms: read
|
Perms: read
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/journal"
|
"github.com/filecoin-project/lotus/journal"
|
||||||
@ -506,33 +505,3 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type
|
|||||||
WinningPoStProof: wpostProof,
|
WinningPoStProof: wpostProof,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type actCacheEntry struct {
|
|
||||||
act *types.Actor
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
type cachedActorLookup struct {
|
|
||||||
tsk types.TipSetKey
|
|
||||||
cache map[address.Address]actCacheEntry
|
|
||||||
fallback gasguess.ActorLookup
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cachedActorLookup) StateGetActor(ctx context.Context, a address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
|
||||||
if c.tsk == tsk {
|
|
||||||
e, has := c.cache[a]
|
|
||||||
if has {
|
|
||||||
return e.act, e.err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e, err := c.fallback(ctx, a, tsk)
|
|
||||||
if c.tsk == tsk {
|
|
||||||
c.cache[a] = actCacheEntry{
|
|
||||||
act: e, err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error)
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@ -35,7 +34,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
"github.com/filecoin-project/lotus/lib/bufbstore"
|
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,19 +92,20 @@ func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, sectorNos *bitfield.BitField, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {
|
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, sectorNos *bitfield.BitField, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {
|
||||||
ts, err := a.Chain.GetTipSetFromKey(tsk)
|
act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||||
}
|
}
|
||||||
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, sectorNos)
|
|
||||||
|
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mas.LoadSectors(sectorNos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { // TODO: only used in cli
|
func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { // TODO: only used in cli
|
||||||
ts, err := a.Chain.GetTipSetFromKey(tsk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk)
|
act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||||
@ -122,7 +121,7 @@ func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Ad
|
|||||||
return nil, xerrors.Errorf("merge partition active sets: %w", err)
|
return nil, xerrors.Errorf("merge partition active sets: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, maddr, &activeSectors)
|
return mas.LoadSectors(&activeSectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *StateModule) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
|
func (m *StateModule) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
|
||||||
@ -426,38 +425,12 @@ func (a *StateAPI) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func stateForTs(ctx context.Context, ts *types.TipSet, cstore *store.ChainStore, smgr *stmgr.StateManager) (*state.StateTree, error) {
|
|
||||||
if ts == nil {
|
|
||||||
ts = cstore.GetHeaviestTipSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
st, _, err := smgr.TipSetState(ctx, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bufbstore.NewBufferedBstore(cstore.Blockstore())
|
|
||||||
cst := cbor.NewCborStore(buf)
|
|
||||||
return state.LoadStateTree(cst, st)
|
|
||||||
}
|
|
||||||
func (a *StateAPI) stateForTs(ctx context.Context, ts *types.TipSet) (*state.StateTree, error) {
|
|
||||||
return stateForTs(ctx, ts, a.Chain, a.StateManager)
|
|
||||||
}
|
|
||||||
func (m *StateModule) stateForTs(ctx context.Context, ts *types.TipSet) (*state.StateTree, error) {
|
|
||||||
return stateForTs(ctx, ts, m.Chain, m.StateManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *StateModule) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
func (m *StateModule) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||||
ts, err := m.Chain.GetTipSetFromKey(tsk)
|
ts, err := m.Chain.GetTipSetFromKey(tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||||
}
|
}
|
||||||
state, err := m.stateForTs(ctx, ts)
|
return m.StateManager.LoadActor(ctx, actor, ts)
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("computing tipset state failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.GetActor(actor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *StateModule) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
func (m *StateModule) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||||
@ -483,17 +456,12 @@ func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, ts
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||||
}
|
}
|
||||||
state, err := a.stateForTs(ctx, ts)
|
act, err := a.StateManager.LoadActor(ctx, actor, ts)
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("getting state for tipset: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
act, err := state.GetActor(actor)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting actor: %w", err)
|
return nil, xerrors.Errorf("getting actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
blk, err := state.Store.(*cbor.BasicIpldStore).Blocks.Get(act.Head)
|
blk, err := a.Chain.Blockstore().Get(act.Head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting actor head: %w", err)
|
return nil, xerrors.Errorf("getting actor head: %w", err)
|
||||||
}
|
}
|
||||||
@ -529,6 +497,7 @@ func (a *StateAPI) StateDecodeParams(ctx context.Context, toAddr address.Address
|
|||||||
|
|
||||||
// This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
|
// This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
|
||||||
func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
||||||
|
// XXX: Gets the state by computing the tipset state, instead of looking at the parent.
|
||||||
return stmgr.MinerGetBaseInfo(ctx, a.StateManager, a.Beacon, tsk, epoch, maddr, a.ProofVerifier)
|
return stmgr.MinerGetBaseInfo(ctx, a.StateManager, a.Beacon, tsk, epoch, maddr, a.ProofVerifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1372,11 +1341,11 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK
|
|||||||
return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sTree, err := a.stateForTs(ctx, ts)
|
sTree, err := a.StateManager.ParentState(ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.EmptyInt, err
|
return types.EmptyInt, err
|
||||||
}
|
}
|
||||||
return a.StateManager.GetCirculatingSupply(ctx, ts.Height(), sTree)
|
return a.StateManager.GetCirculatingSupply(ctx, ts.Height()-1, sTree)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *StateAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
func (a *StateAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||||
@ -1393,7 +1362,7 @@ func stateVMCirculatingSupplyInternal(
|
|||||||
return api.CirculatingSupply{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
return api.CirculatingSupply{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sTree, err := stateForTs(ctx, ts, cstore, smgr)
|
sTree, err := smgr.ParentState(ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.CirculatingSupply{}, err
|
return api.CirculatingSupply{}, err
|
||||||
}
|
}
|
||||||
@ -1407,5 +1376,7 @@ func (m *StateModule) StateNetworkVersion(ctx context.Context, tsk types.TipSetK
|
|||||||
return network.VersionMax, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
return network.VersionMax, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Height-1 to be consistent with the rest of the APIs?
|
||||||
|
// But that's likely going to break a bunch of stuff.
|
||||||
return m.StateManager.GetNtwkVersion(ctx, ts.Height()), nil
|
return m.StateManager.GetNtwkVersion(ctx, ts.Height()), nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/node/impl/full"
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
|
|
||||||
@ -21,13 +22,41 @@ type MpoolNonceAPI struct {
|
|||||||
StateAPI full.StateAPI
|
StateAPI full.StateAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNonce gets the nonce from actor state
|
// GetNonce gets the nonce from current chain head.
|
||||||
func (a *MpoolNonceAPI) GetNonce(addr address.Address) (uint64, error) {
|
func (a *MpoolNonceAPI) GetNonce(addr address.Address) (uint64, error) {
|
||||||
act, err := a.StateAPI.StateGetActor(context.Background(), addr, types.EmptyTSK)
|
ts := a.StateAPI.Chain.GetHeaviestTipSet()
|
||||||
|
|
||||||
|
// make sure we have a key address so we can compare with messages
|
||||||
|
keyAddr, err := a.StateAPI.StateManager.ResolveToKeyAddress(context.TODO(), addr, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return act.Nonce, nil
|
|
||||||
|
// Load the last nonce from the state, if it exists.
|
||||||
|
highestNonce := uint64(0)
|
||||||
|
if baseActor, err := a.StateAPI.StateManager.LoadActorRaw(context.TODO(), addr, ts.ParentState()); err != nil {
|
||||||
|
if !xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
highestNonce = baseActor.Nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, find the highest nonce in the tipset.
|
||||||
|
msgs, err := a.StateAPI.Chain.MessagesForTipset(ts)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for _, msg := range msgs {
|
||||||
|
vmmsg := msg.VMMessage()
|
||||||
|
if vmmsg.From != keyAddr {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if vmmsg.Nonce >= highestNonce {
|
||||||
|
highestNonce = vmmsg.Nonce + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return highestNonce, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ messagesigner.MpoolNonceAPI = (*MpoolNonceAPI)(nil)
|
var _ messagesigner.MpoolNonceAPI = (*MpoolNonceAPI)(nil)
|
||||||
|
@ -92,6 +92,10 @@ func TestAPIDealFlowReal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDealMining(t *testing.T) {
|
func TestDealMining(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
logging.SetLogLevel("miner", "ERROR")
|
logging.SetLogLevel("miner", "ERROR")
|
||||||
logging.SetLogLevel("chainstore", "ERROR")
|
logging.SetLogLevel("chainstore", "ERROR")
|
||||||
logging.SetLogLevel("chain", "ERROR")
|
logging.SetLogLevel("chain", "ERROR")
|
||||||
|
Loading…
Reference in New Issue
Block a user