lotus/node/impl/full/txhashmanager.go
Steven Allen 9b4df6a4d0
fix: eth: use the correct state-tree when resolving addresses (#11387)
We need to always use the state-tree from the tipset _after_ the message
executed. If we use any other state-tree, we might not find the address
we're trying to resolve.

This change also has some implication for pending messages: there's no
guarantee we'll be able to generate a 0x-style address for a pending
native message. So, instead of trying, I've removed support for pending
native messages from the Eth API. Messages from EthAccounts will still
work, and native messages will still show up in blocks/traces, they just
won't show up as "pending". Which should affect exactly nobody.

I'm also taking this opportunity to cleanup some edge-cases:

1. Pass contexts where appropriate.
2. Remove all state access from `ethTxHashFromSignedMessage`.

Part of #11355
2023-11-17 18:20:31 +01:00

136 lines
3.2 KiB
Go

package full
import (
"context"
"time"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/ethhashlookup"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
)
type EthTxHashManager struct {
StateAPI StateAPI
TransactionHashLookup *ethhashlookup.EthTxHashLookup
}
func (m *EthTxHashManager) Revert(ctx context.Context, from, to *types.TipSet) error {
return nil
}
func (m *EthTxHashManager) PopulateExistingMappings(ctx context.Context, minHeight abi.ChainEpoch) error {
if minHeight < build.UpgradeHyggeHeight {
minHeight = build.UpgradeHyggeHeight
}
ts := m.StateAPI.Chain.GetHeaviestTipSet()
for ts.Height() > minHeight {
for _, block := range ts.Blocks() {
msgs, err := m.StateAPI.Chain.SecpkMessagesForBlock(ctx, block)
if err != nil {
// If we can't find the messages, we've either imported from snapshot or pruned the store
log.Debug("exiting message mapping population at epoch ", ts.Height())
return nil
}
for _, msg := range msgs {
m.ProcessSignedMessage(ctx, msg)
}
}
var err error
ts, err = m.StateAPI.Chain.GetTipSetFromKey(ctx, ts.Parents())
if err != nil {
return err
}
}
return nil
}
func (m *EthTxHashManager) Apply(ctx context.Context, from, to *types.TipSet) error {
for _, blk := range to.Blocks() {
_, smsgs, err := m.StateAPI.Chain.MessagesForBlock(ctx, blk)
if err != nil {
return err
}
for _, smsg := range smsgs {
if smsg.Signature.Type != crypto.SigTypeDelegated {
continue
}
hash, err := ethTxHashFromSignedMessage(smsg)
if err != nil {
return err
}
err = m.TransactionHashLookup.UpsertHash(hash, smsg.Cid())
if err != nil {
return err
}
}
}
return nil
}
func (m *EthTxHashManager) ProcessSignedMessage(ctx context.Context, msg *types.SignedMessage) {
if msg.Signature.Type != crypto.SigTypeDelegated {
return
}
ethTx, err := ethtypes.EthTxFromSignedEthMessage(msg)
if err != nil {
log.Errorf("error converting filecoin message to eth tx: %s", err)
return
}
txHash, err := ethTx.TxHash()
if err != nil {
log.Errorf("error hashing transaction: %s", err)
return
}
err = m.TransactionHashLookup.UpsertHash(txHash, msg.Cid())
if err != nil {
log.Errorf("error inserting tx mapping to db: %s", err)
return
}
}
func WaitForMpoolUpdates(ctx context.Context, ch <-chan api.MpoolUpdate, manager *EthTxHashManager) {
for {
select {
case <-ctx.Done():
return
case u := <-ch:
if u.Type != api.MpoolAdd {
continue
}
manager.ProcessSignedMessage(ctx, u.Message)
}
}
}
func EthTxHashGC(ctx context.Context, retentionDays int, manager *EthTxHashManager) {
if retentionDays == 0 {
return
}
gcPeriod := 1 * time.Hour
for {
entriesDeleted, err := manager.TransactionHashLookup.DeleteEntriesOlderThan(retentionDays)
if err != nil {
log.Errorf("error garbage collecting eth transaction hash database: %s", err)
}
log.Info("garbage collection run on eth transaction hash lookup database. %d entries deleted", entriesDeleted)
time.Sleep(gcPeriod)
}
}