Merge pull request #6048 from filecoin-project/fix/nonce-getting

Fix nonce getting on Lotus lite
This commit is contained in:
Łukasz Magiera 2021-04-18 16:25:47 +02:00 committed by GitHub
commit c72eb0ccaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 31 deletions

View File

@ -795,7 +795,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict, untrusted bool)
return nil return nil
} }
func (mp *MessagePool) GetNonce(addr address.Address) (uint64, error) { func (mp *MessagePool) GetNonce(_ context.Context, addr address.Address, _ types.TipSetKey) (uint64, error) {
mp.curTsLk.Lock() mp.curTsLk.Lock()
defer mp.curTsLk.Unlock() defer mp.curTsLk.Unlock()

View File

@ -199,7 +199,7 @@ func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipS
func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) { func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
t.Helper() t.Helper()
n, err := mp.GetNonce(addr) n, err := mp.GetNonce(context.Background(), addr, types.EmptyTSK)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -23,7 +23,7 @@ const dsKeyActorNonce = "ActorNextNonce"
var log = logging.Logger("messagesigner") var log = logging.Logger("messagesigner")
type MpoolNonceAPI interface { type MpoolNonceAPI interface {
GetNonce(address.Address) (uint64, error) GetNonce(context.Context, address.Address, types.TipSetKey) (uint64, error)
} }
// MessageSigner keeps track of nonces per address, and increments the nonce // MessageSigner keeps track of nonces per address, and increments the nonce
@ -51,7 +51,7 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb
defer ms.lk.Unlock() defer ms.lk.Unlock()
// Get the next message nonce // Get the next message nonce
nonce, err := ms.nextNonce(msg.From) nonce, err := ms.nextNonce(ctx, msg.From)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to create nonce: %w", err) return nil, xerrors.Errorf("failed to create nonce: %w", err)
} }
@ -92,12 +92,12 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb
// nextNonce gets the next nonce for the given address. // nextNonce gets the next nonce for the given address.
// If there is no nonce in the datastore, gets the nonce from the message pool. // If there is no nonce in the datastore, gets the nonce from the message pool.
func (ms *MessageSigner) nextNonce(addr address.Address) (uint64, error) { func (ms *MessageSigner) nextNonce(ctx context.Context, addr address.Address) (uint64, error) {
// Nonces used to be created by the mempool and we need to support nodes // Nonces used to be created by the mempool and we need to support nodes
// that have mempool nonces, so first check the mempool for a nonce for // that have mempool nonces, so first check the mempool for a nonce for
// this address. Note that the mempool returns the actor state's nonce // this address. Note that the mempool returns the actor state's nonce
// by default. // by default.
nonce, err := ms.mpool.GetNonce(addr) nonce, err := ms.mpool.GetNonce(ctx, addr, types.EmptyTSK)
if err != nil { if err != nil {
return 0, xerrors.Errorf("failed to get nonce from mempool: %w", err) return 0, xerrors.Errorf("failed to get nonce from mempool: %w", err)
} }

View File

@ -35,7 +35,7 @@ func (mp *mockMpool) setNonce(addr address.Address, nonce uint64) {
mp.nonces[addr] = nonce mp.nonces[addr] = nonce
} }
func (mp *mockMpool) GetNonce(addr address.Address) (uint64, error) { func (mp *mockMpool) GetNonce(_ context.Context, addr address.Address, _ types.TipSetKey) (uint64, error) {
mp.lk.RLock() mp.lk.RLock()
defer mp.lk.RUnlock() defer mp.lk.RUnlock()

View File

@ -226,7 +226,7 @@ func (a *MpoolAPI) MpoolBatchPushMessage(ctx context.Context, msgs []*types.Mess
} }
func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) { func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
return a.Mpool.GetNonce(addr) return a.Mpool.GetNonce(ctx, addr, types.EmptyTSK)
} }
func (a *MpoolAPI) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate, error) { func (a *MpoolAPI) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate, error) {

View File

@ -2,6 +2,7 @@ package modules
import ( import (
"context" "context"
"strings"
"go.uber.org/fx" "go.uber.org/fx"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -19,41 +20,77 @@ import (
type MpoolNonceAPI struct { type MpoolNonceAPI struct {
fx.In fx.In
StateAPI full.StateAPI ChainModule full.ChainModuleAPI
StateModule full.StateModuleAPI
} }
// GetNonce gets the nonce from current chain head. // GetNonce gets the nonce from current chain head.
func (a *MpoolNonceAPI) GetNonce(addr address.Address) (uint64, error) { func (a *MpoolNonceAPI) GetNonce(ctx context.Context, addr address.Address, tsk types.TipSetKey) (uint64, error) {
ts := a.StateAPI.Chain.GetHeaviestTipSet() var err error
var ts *types.TipSet
// make sure we have a key address so we can compare with messages if tsk == types.EmptyTSK {
keyAddr, err := a.StateAPI.StateManager.ResolveToKeyAddress(context.TODO(), addr, ts) // we need consistent tsk
ts, err = a.ChainModule.ChainHead(ctx)
if err != nil { if err != nil {
return 0, err return 0, xerrors.Errorf("getting head: %w", err)
}
tsk = ts.Key()
} else {
ts, err = a.ChainModule.ChainGetTipSet(ctx, tsk)
if err != nil {
return 0, xerrors.Errorf("getting tipset: %w", err)
}
}
keyAddr := addr
if addr.Protocol() == address.ID {
// make sure we have a key address so we can compare with messages
keyAddr, err = a.StateModule.StateAccountKey(ctx, addr, tsk)
if err != nil {
return 0, xerrors.Errorf("getting account key: %w", err)
}
} else {
addr, err = a.StateModule.StateLookupID(ctx, addr, types.EmptyTSK)
if err != nil {
log.Infof("failed to look up id addr for %s: %w", addr, err)
addr = address.Undef
}
} }
// Load the last nonce from the state, if it exists. // Load the last nonce from the state, if it exists.
highestNonce := uint64(0) highestNonce := uint64(0)
if baseActor, err := a.StateAPI.StateManager.LoadActorRaw(context.TODO(), addr, ts.ParentState()); err != nil { act, err := a.StateModule.StateGetActor(ctx, keyAddr, ts.Key())
if !xerrors.Is(err, types.ErrActorNotFound) { if err != nil {
return 0, err if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) {
return 0, types.ErrActorNotFound
}
return 0, xerrors.Errorf("getting actor: %w", err)
}
highestNonce = act.Nonce
apply := func(msg *types.Message) {
if msg.From != addr && msg.From != keyAddr {
return
}
if msg.Nonce == highestNonce {
highestNonce = msg.Nonce + 1
} }
} else {
highestNonce = baseActor.Nonce
} }
// Otherwise, find the highest nonce in the tipset. for _, b := range ts.Blocks() {
msgs, err := a.StateAPI.Chain.MessagesForTipset(ts) msgs, err := a.ChainModule.ChainGetBlockMessages(ctx, b.Cid())
if err != nil { if err != nil {
return 0, err return 0, xerrors.Errorf("getting block messages: %w", err)
} }
for _, msg := range msgs { if keyAddr.Protocol() == address.BLS {
vmmsg := msg.VMMessage() for _, m := range msgs.BlsMessages {
if vmmsg.From != keyAddr { apply(m)
continue }
} else {
for _, sm := range msgs.SecpkMessages {
apply(&sm.Message)
} }
if vmmsg.Nonce >= highestNonce {
highestNonce = vmmsg.Nonce + 1
} }
} }
return highestNonce, nil return highestNonce, nil