e164dbb953
We could also do this in the message pool itself, but I'm not sure if it's worth it?
63 lines
1.5 KiB
Go
63 lines
1.5 KiB
Go
package modules
|
|
|
|
import (
|
|
"context"
|
|
|
|
"go.uber.org/fx"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/filecoin-project/lotus/node/impl/full"
|
|
|
|
"github.com/filecoin-project/lotus/chain/messagesigner"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
)
|
|
|
|
// MpoolNonceAPI substitutes the mpool nonce with an implementation that
|
|
// doesn't rely on the mpool - it just gets the nonce from actor state
|
|
type MpoolNonceAPI struct {
|
|
fx.In
|
|
|
|
StateAPI full.StateAPI
|
|
}
|
|
|
|
// GetNonce gets the nonce from current chain head.
|
|
func (a *MpoolNonceAPI) GetNonce(addr address.Address) (uint64, error) {
|
|
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 {
|
|
return 0, err
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
return highestNonce, nil
|
|
}
|
|
|
|
var _ messagesigner.MpoolNonceAPI = (*MpoolNonceAPI)(nil)
|