diff --git a/CHANGELOG.md b/CHANGELOG.md index e54438ebae8..6cb54b5f3d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - fix: Add time slicing to splitstore purging step during compaction to reduce lock congestion [filecoin-project/lotus#11269](https://github.com/filecoin-project/lotus/pull/11269) - feat: Added instructions on how to setup Prometheus/Grafana for monitoring a local Lotus node [filecoin-project/lotus#11276](https://github.com/filecoin-project/lotus/pull/11276) - fix: Exclude reverted events in `eth_getLogs` results [filecoin-project/lotus#11318](https://github.com/filecoin-project/lotus/pull/11318) +- fix: The Ethereum API will now use the correct state-tree when resolving "native" addresses into masked ID addresses. Additionally, pending messages from native account types won't be visible in the Ethereum API because there is no "correct" state-tree to pick in this case. However, pending _Ethereum_ transactions and native messages that have landed on-chain will still be visible through the Ethereum API. ## New features - feat: Add move-partition command ([filecoin-project/lotus#11290](https://github.com/filecoin-project/lotus/pull/11290)) diff --git a/chain/types/ethtypes/eth_transactions.go b/chain/types/ethtypes/eth_transactions.go index 6c13c5bf6a2..a3b1d01502a 100644 --- a/chain/types/ethtypes/eth_transactions.go +++ b/chain/types/ethtypes/eth_transactions.go @@ -62,9 +62,14 @@ type EthTxArgs struct { // - BlockHash // - BlockNumber // - TransactionIndex -// - From // - Hash func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) { + // The from address is always an f410f address, never an ID or other address. + if !IsEthAddress(smsg.Message.From) { + return EthTx{}, xerrors.Errorf("sender must be an eth account, was %s", smsg.Message.From) + } + + // Probably redundant, but we might as well check. if smsg.Signature.Type != typescrypto.SigTypeDelegated { return EthTx{}, xerrors.Errorf("signature is not delegated type, is type: %d", smsg.Signature.Type) } @@ -79,10 +84,18 @@ func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) { return EthTx{}, xerrors.Errorf("failed to recover signature: %w", err) } + from, err := EthAddressFromFilecoinAddress(smsg.Message.From) + if err != nil { + // This should be impossible as we've already asserted that we have an EthAddress + // sender... + return EthTx{}, xerrors.Errorf("sender was not an eth account") + } + return EthTx{ Nonce: EthUint64(txArgs.Nonce), ChainID: EthUint64(txArgs.ChainID), To: txArgs.To, + From: from, Value: EthBigInt(txArgs.Value), Type: Eip1559TxType, Gas: EthUint64(txArgs.GasLimit), diff --git a/itests/eth_hash_lookup_test.go b/itests/eth_hash_lookup_test.go index 37d0697962c..0bf32108852 100644 --- a/itests/eth_hash_lookup_test.go +++ b/itests/eth_hash_lookup_test.go @@ -120,7 +120,6 @@ func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { kit.MockProofs(), kit.ThroughRPC(), ) - ens.InterconnectAll().BeginMining(blocktime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -146,9 +145,13 @@ func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { hash, err := ethtypes.EthHashFromCid(sm.Message.Cid()) require.NoError(t, err) - mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) - require.NoError(t, err) - require.Equal(t, hash, mpoolTx.Hash) + // Assert that BLS messages cannot be retrieved from the message pool until it lands + // on-chain via the eth API. + _, err = client.EthGetTransactionByHash(ctx, &hash) + require.Error(t, err) + + // Now start mining. + ens.InterconnectAll().BeginMining(blocktime) // Wait for message to land on chain var receipt *api.EthTxReceipt @@ -177,6 +180,13 @@ func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { require.NotEmpty(t, *chainTx.BlockHash) require.NotNil(t, chainTx.TransactionIndex) require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction + + // verify that we correctly reported the to address. + toId, err := client.StateLookupID(ctx, addr, types.EmptyTSK) + require.NoError(t, err) + toEth, err := client.FilecoinAddressToEthAddress(ctx, toId) + require.NoError(t, err) + require.Equal(t, &toEth, chainTx.To) } // TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash @@ -228,10 +238,6 @@ func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) { hash, err := ethtypes.EthHashFromCid(secpSmsg.Cid()) require.NoError(t, err) - mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) - require.NoError(t, err) - require.Equal(t, hash, mpoolTx.Hash) - _, err = client.StateWaitMsg(ctx, secpSmsg.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) @@ -253,6 +259,13 @@ func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) { require.NotEmpty(t, *chainTx.BlockHash) require.NotNil(t, chainTx.TransactionIndex) require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction + + // verify that we correctly reported the to address. + toId, err := client.StateLookupID(ctx, client.DefaultKey.Address, types.EmptyTSK) + require.NoError(t, err) + toEth, err := client.FilecoinAddressToEthAddress(ctx, toId) + require.NoError(t, err) + require.Equal(t, &toEth, chainTx.To) } // TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index f8c5ba9b56d..22f78e7232c 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -285,9 +285,20 @@ func (a *EthModule) EthGetTransactionByHashLimited(ctx context.Context, txHash * for _, p := range pending { if p.Cid() == c { - tx, err := newEthTxFromSignedMessage(ctx, p, a.StateAPI) + // We only return pending eth-account messages because we can't guarantee + // that the from/to addresses of other messages are conversable to 0x-style + // addresses. So we just ignore them. + // + // This should be "fine" as anyone using an "Ethereum-centric" block + // explorer shouldn't care about seeing pending messages from native + // accounts. + tx, err := ethtypes.EthTxFromSignedEthMessage(p) if err != nil { - return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err) + return nil, fmt.Errorf("could not convert Filecoin message into tx: %w", err) + } + tx.Hash, err = tx.TxHash() + if err != nil { + return nil, fmt.Errorf("could not compute tx hash for eth txn: %w", err) } return &tx, nil } @@ -718,7 +729,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth ) for blocksIncluded < int(params.BlkCount) && ts.Height() > 0 { - msgs, rcpts, err := messagesAndReceipts(ctx, ts, a.Chain, a.StateAPI) + _, msgs, rcpts, err := executeTipset(ctx, ts, a.Chain, a.StateAPI) if err != nil { return ethtypes.EthFeeHistory{}, xerrors.Errorf("failed to retrieve messages and receipts for height %d: %w", ts.Height(), err) } @@ -837,11 +848,16 @@ func (a *EthModule) EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtyp return nil, xerrors.Errorf("failed to get tipset: %w", err) } - _, trace, err := a.StateManager.ExecutionTrace(ctx, ts) + stRoot, trace, err := a.StateManager.ExecutionTrace(ctx, ts) if err != nil { return nil, xerrors.Errorf("failed when calling ExecutionTrace: %w", err) } + st, err := a.StateManager.StateTree(stRoot) + if err != nil { + return nil, xerrors.Errorf("failed load computed state-tree: %w", err) + } + cid, err := ts.Key().Cid() if err != nil { return nil, xerrors.Errorf("failed to get tipset key cid: %w", err) @@ -872,7 +888,7 @@ func (a *EthModule) EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtyp } traces := []*ethtypes.EthTrace{} - err = buildTraces(ctx, &traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), a.StateAPI) + err = buildTraces(&traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), st) if err != nil { return nil, xerrors.Errorf("failed building traces: %w", err) } @@ -904,11 +920,16 @@ func (a *EthModule) EthTraceReplayBlockTransactions(ctx context.Context, blkNum return nil, xerrors.Errorf("failed to get tipset: %w", err) } - _, trace, err := a.StateManager.ExecutionTrace(ctx, ts) + stRoot, trace, err := a.StateManager.ExecutionTrace(ctx, ts) if err != nil { return nil, xerrors.Errorf("failed when calling ExecutionTrace: %w", err) } + st, err := a.StateManager.StateTree(stRoot) + if err != nil { + return nil, xerrors.Errorf("failed load computed state-tree: %w", err) + } + allTraces := make([]*ethtypes.EthTraceReplayBlockTransaction, 0, len(trace)) for _, ir := range trace { // ignore messages from system actor @@ -943,7 +964,7 @@ func (a *EthModule) EthTraceReplayBlockTransactions(ctx context.Context, blkNum VmTrace: nil, } - err = buildTraces(ctx, &t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), a.StateAPI) + err = buildTraces(&t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), st) if err != nil { return nil, xerrors.Errorf("failed building traces: %w", err) } @@ -1184,7 +1205,7 @@ func (e *EthEvent) EthGetLogs(ctx context.Context, filterSpec *ethtypes.EthFilte _ = e.uninstallFilter(ctx, f) - return ethFilterResultFromEvents(ces, e.SubManager.StateAPI) + return ethFilterResultFromEvents(ctx, ces, e.SubManager.StateAPI) } func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { @@ -1199,11 +1220,11 @@ func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilte switch fc := f.(type) { case filterEventCollector: - return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI) + return ethFilterResultFromEvents(ctx, fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI) case filterTipSetCollector: return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx)) case filterMessageCollector: - return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx), e.SubManager.StateAPI) + return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx)) } return nil, xerrors.Errorf("unknown filter type") @@ -1221,7 +1242,7 @@ func (e *EthEvent) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID switch fc := f.(type) { case filterEventCollector: - return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI) + return ethFilterResultFromEvents(ctx, fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI) } return nil, xerrors.Errorf("wrong filter type") diff --git a/node/impl/full/eth_event.go b/node/impl/full/eth_event.go index 69021e08aed..54dd164acf4 100644 --- a/node/impl/full/eth_event.go +++ b/node/impl/full/eth_event.go @@ -93,7 +93,7 @@ func ethLogFromEvent(entries []types.EventEntry) (data []byte, topics []ethtypes return data, topics, true } -func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*ethtypes.EthFilterResult, error) { +func ethFilterResultFromEvents(ctx context.Context, evs []*filter.CollectedEvent, sa StateAPI) (*ethtypes.EthFilterResult, error) { res := ðtypes.EthFilterResult{} for _, ev := range evs { log := ethtypes.EthLog{ @@ -117,7 +117,7 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*etht return nil, err } - log.TransactionHash, err = ethTxHashFromMessageCid(context.TODO(), ev.MsgCid, sa) + log.TransactionHash, err = ethTxHashFromMessageCid(ctx, ev.MsgCid, sa) if err != nil { return nil, err } @@ -155,11 +155,11 @@ func ethFilterResultFromTipSets(tsks []types.TipSetKey) (*ethtypes.EthFilterResu return res, nil } -func ethFilterResultFromMessages(cs []*types.SignedMessage, sa StateAPI) (*ethtypes.EthFilterResult, error) { +func ethFilterResultFromMessages(cs []*types.SignedMessage) (*ethtypes.EthFilterResult, error) { res := ðtypes.EthFilterResult{} for _, c := range cs { - hash, err := ethTxHashFromSignedMessage(context.TODO(), c, sa) + hash, err := ethTxHashFromSignedMessage(c) if err != nil { return nil, err } @@ -321,14 +321,14 @@ func (e *ethSubscription) send(ctx context.Context, v interface{}) { } func (e *ethSubscription) start(ctx context.Context) { - for { + for ctx.Err() == nil { select { case <-ctx.Done(): return case v := <-e.in: switch vt := v.(type) { case *filter.CollectedEvent: - evs, err := ethFilterResultFromEvents([]*filter.CollectedEvent{vt}, e.StateAPI) + evs, err := ethFilterResultFromEvents(ctx, []*filter.CollectedEvent{vt}, e.StateAPI) if err != nil { continue } @@ -344,7 +344,7 @@ func (e *ethSubscription) start(ctx context.Context) { e.send(ctx, ev) case *types.SignedMessage: // mpool txid - evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}, e.StateAPI) + evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}) if err != nil { continue } diff --git a/node/impl/full/eth_trace.go b/node/impl/full/eth_trace.go index fd5c25566cb..9d24394d7e9 100644 --- a/node/impl/full/eth_trace.go +++ b/node/impl/full/eth_trace.go @@ -2,7 +2,6 @@ package full import ( "bytes" - "context" "github.com/multiformats/go-multicodec" cbg "github.com/whyrusleeping/cbor-gen" @@ -12,6 +11,7 @@ import ( "github.com/filecoin-project/go-state-types/builtin/v10/evm" builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" ) @@ -39,18 +39,18 @@ func decodePayload(payload []byte, codec uint64) (ethtypes.EthBytes, error) { } // buildTraces recursively builds the traces for a given ExecutionTrace by walking the subcalls -func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *ethtypes.EthTrace, addr []int, et types.ExecutionTrace, height int64, sa StateAPI) error { +func buildTraces(traces *[]*ethtypes.EthTrace, parent *ethtypes.EthTrace, addr []int, et types.ExecutionTrace, height int64, st *state.StateTree) error { // lookup the eth address from the from/to addresses. Note that this may fail but to support // this we need to include the ActorID in the trace. For now, just log a warning and skip // this trace. // // TODO: Add ActorID in trace, see https://github.com/filecoin-project/lotus/pull/11100#discussion_r1302442288 - from, err := lookupEthAddress(ctx, et.Msg.From, sa) + from, err := lookupEthAddress(et.Msg.From, st) if err != nil { log.Warnf("buildTraces: failed to lookup from address %s: %v", et.Msg.From, err) return nil } - to, err := lookupEthAddress(ctx, et.Msg.To, sa) + to, err := lookupEthAddress(et.Msg.To, st) if err != nil { log.Warnf("buildTraces: failed to lookup to address %s: %w", et.Msg.To, err) return nil @@ -239,7 +239,7 @@ func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *etht *traces = append(*traces, trace) for i, call := range et.Subcalls { - err := buildTraces(ctx, traces, trace, append(addr, i), call, height, sa) + err := buildTraces(traces, trace, append(addr, i), call, height, st) if err != nil { return err } diff --git a/node/impl/full/eth_utils.go b/node/impl/full/eth_utils.go index 2799638ddfb..8bbb58b9bbd 100644 --- a/node/impl/full/eth_utils.go +++ b/node/impl/full/eth_utils.go @@ -21,6 +21,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" @@ -190,7 +191,8 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx bn := ethtypes.EthUint64(ts.Height()) - blkCid, err := ts.Key().Cid() + tsk := ts.Key() + blkCid, err := tsk.Cid() if err != nil { return ethtypes.EthBlock{}, err } @@ -199,11 +201,16 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx return ethtypes.EthBlock{}, err } - msgs, rcpts, err := messagesAndReceipts(ctx, ts, cs, sa) + stRoot, msgs, rcpts, err := executeTipset(ctx, ts, cs, sa) if err != nil { return ethtypes.EthBlock{}, xerrors.Errorf("failed to retrieve messages and receipts: %w", err) } + st, err := sa.StateManager.StateTree(stRoot) + if err != nil { + return ethtypes.EthBlock{}, xerrors.Errorf("failed to load state-tree root %q: %w", stRoot, err) + } + block := ethtypes.NewEthBlock(len(msgs) > 0) gasUsed := int64(0) @@ -225,7 +232,7 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx default: return ethtypes.EthBlock{}, xerrors.Errorf("failed to get signed msg %s: %w", msg.Cid(), err) } - tx, err := newEthTxFromSignedMessage(ctx, smsg, sa) + tx, err := newEthTxFromSignedMessage(smsg, st) if err != nil { return ethtypes.EthBlock{}, xerrors.Errorf("failed to convert msg to ethTx: %w", err) } @@ -251,27 +258,27 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx return block, nil } -func messagesAndReceipts(ctx context.Context, ts *types.TipSet, cs *store.ChainStore, sa StateAPI) ([]types.ChainMsg, []types.MessageReceipt, error) { +func executeTipset(ctx context.Context, ts *types.TipSet, cs *store.ChainStore, sa StateAPI) (cid.Cid, []types.ChainMsg, []types.MessageReceipt, error) { msgs, err := cs.MessagesForTipset(ctx, ts) if err != nil { - return nil, nil, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err) + return cid.Undef, nil, nil, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err) } - _, rcptRoot, err := sa.StateManager.TipSetState(ctx, ts) + stRoot, rcptRoot, err := sa.StateManager.TipSetState(ctx, ts) if err != nil { - return nil, nil, xerrors.Errorf("failed to compute state: %w", err) + return cid.Undef, nil, nil, xerrors.Errorf("failed to compute state: %w", err) } rcpts, err := cs.ReadReceipts(ctx, rcptRoot) if err != nil { - return nil, nil, xerrors.Errorf("error loading receipts for tipset: %v: %w", ts, err) + return cid.Undef, nil, nil, xerrors.Errorf("error loading receipts for tipset: %v: %w", ts, err) } if len(msgs) != len(rcpts) { - return nil, nil, xerrors.Errorf("receipts and message array lengths didn't match for tipset: %v: %w", ts, err) + return cid.Undef, nil, nil, xerrors.Errorf("receipts and message array lengths didn't match for tipset: %v: %w", ts, err) } - return msgs, rcpts, nil + return stRoot, msgs, rcpts, nil } const errorFunctionSelector = "\x08\xc3\x79\xa0" // Error(string) @@ -361,7 +368,7 @@ func parseEthRevert(ret []byte) string { // 3. Otherwise, we fall back to returning a masked ID Ethereum address. If the supplied address is an f0 address, we // use that ID to form the masked ID address. // 4. Otherwise, we fetch the actor's ID from the state tree and form the masked ID with it. -func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (ethtypes.EthAddress, error) { +func lookupEthAddress(addr address.Address, st *state.StateTree) (ethtypes.EthAddress, error) { // BLOCK A: We are trying to get an actual Ethereum address from an f410 address. // Attempt to convert directly, if it's an f4 address. ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr) @@ -370,7 +377,7 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e } // Lookup on the target actor and try to get an f410 address. - if actor, err := sa.StateGetActor(ctx, addr, types.EmptyTSK); err != nil { + if actor, err := st.GetActor(addr); err != nil { return ethtypes.EthAddress{}, err } else if actor.Address != nil { if ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address); err == nil && !ethAddr.IsMaskedID() { @@ -385,7 +392,7 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e } // Otherwise, resolve the ID addr. - idAddr, err := sa.StateLookupID(ctx, addr, types.EmptyTSK) + idAddr, err := st.LookupID(addr) if err != nil { return ethtypes.EthAddress{}, err } @@ -412,7 +419,7 @@ func ethTxHashFromMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethty smsg, err := sa.Chain.GetSignedMessage(ctx, c) if err == nil { // This is an Eth Tx, Secp message, Or BLS message in the mpool - return ethTxHashFromSignedMessage(ctx, smsg, sa) + return ethTxHashFromSignedMessage(smsg) } _, err = sa.Chain.GetMessage(ctx, c) @@ -424,13 +431,14 @@ func ethTxHashFromMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethty return ethtypes.EmptyEthHash, nil } -func ethTxHashFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthHash, error) { +func ethTxHashFromSignedMessage(smsg *types.SignedMessage) (ethtypes.EthHash, error) { if smsg.Signature.Type == crypto.SigTypeDelegated { - ethTx, err := newEthTxFromSignedMessage(ctx, smsg, sa) + tx, err := ethtypes.EthTxFromSignedEthMessage(smsg) if err != nil { - return ethtypes.EmptyEthHash, err + return ethtypes.EthHash{}, xerrors.Errorf("failed to convert from signed message: %w", err) } - return ethTx.Hash, nil + + return tx.TxHash() } else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { return ethtypes.EthHashFromCid(smsg.Cid()) } else { // BLS message @@ -438,7 +446,7 @@ func ethTxHashFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, } } -func newEthTxFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) { +func newEthTxFromSignedMessage(smsg *types.SignedMessage, st *state.StateTree) (ethtypes.EthTx, error) { var tx ethtypes.EthTx var err error @@ -453,21 +461,14 @@ func newEthTxFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, s if err != nil { return ethtypes.EthTx{}, xerrors.Errorf("failed to calculate hash for ethTx: %w", err) } - - fromAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa) - if err != nil { - return ethtypes.EthTx{}, xerrors.Errorf("failed to resolve Ethereum address: %w", err) - } - - tx.From = fromAddr } else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { // Secp Filecoin Message - tx = ethTxFromNativeMessage(ctx, smsg.VMMessage(), sa) + tx = ethTxFromNativeMessage(smsg.VMMessage(), st) tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid()) if err != nil { return tx, err } } else { // BLS Filecoin message - tx = ethTxFromNativeMessage(ctx, smsg.VMMessage(), sa) + tx = ethTxFromNativeMessage(smsg.VMMessage(), st) tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid()) if err != nil { return tx, err @@ -482,10 +483,10 @@ func newEthTxFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, s // - BlockNumber // - TransactionIndex // - Hash -func ethTxFromNativeMessage(ctx context.Context, msg *types.Message, sa StateAPI) ethtypes.EthTx { +func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) ethtypes.EthTx { // We don't care if we error here, conversion is best effort for non-eth transactions - from, _ := lookupEthAddress(ctx, msg.From, sa) - to, _ := lookupEthAddress(ctx, msg.To, sa) + from, _ := lookupEthAddress(msg.From, st) + to, _ := lookupEthAddress(msg.To, st) return ethtypes.EthTx{ To: &to, From: from, @@ -566,7 +567,12 @@ func newEthTxFromMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, tx return ethtypes.EthTx{}, xerrors.Errorf("failed to get signed msg: %w", err) } - tx, err := newEthTxFromSignedMessage(ctx, smsg, sa) + st, err := sa.StateManager.StateTree(ts.ParentState()) + if err != nil { + return ethtypes.EthTx{}, xerrors.Errorf("failed to load message state tree: %w", err) + } + + tx, err := newEthTxFromSignedMessage(smsg, st) if err != nil { return ethtypes.EthTx{}, err } @@ -576,7 +582,6 @@ func newEthTxFromMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, tx ti = ethtypes.EthUint64(txIdx) ) - tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId) tx.BlockHash = &blkHash tx.BlockNumber = &bn tx.TransactionIndex = &ti @@ -629,6 +634,11 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook return api.EthTxReceipt{}, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", lookup.TipSet, err) } + st, err := sa.StateManager.StateTree(ts.ParentState()) + if err != nil { + return api.EthTxReceipt{}, xerrors.Errorf("failed to load the state %s when constructing the eth txn receipt: %w", ts.ParentState(), err) + } + // The tx is located in the parent tipset parentTs, err := cs.LoadTipSet(ctx, ts.Parents()) if err != nil { @@ -684,7 +694,7 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook return api.EthTxReceipt{}, xerrors.Errorf("failed to create ID address: %w", err) } - l.Address, err = lookupEthAddress(ctx, addr, sa) + l.Address, err = lookupEthAddress(addr, st) if err != nil { return api.EthTxReceipt{}, xerrors.Errorf("failed to resolve Ethereum address: %w", err) } diff --git a/node/impl/full/txhashmanager.go b/node/impl/full/txhashmanager.go index 6757cc6dd92..64c488d377c 100644 --- a/node/impl/full/txhashmanager.go +++ b/node/impl/full/txhashmanager.go @@ -11,6 +11,7 @@ import ( "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 { @@ -64,7 +65,7 @@ func (m *EthTxHashManager) Apply(ctx context.Context, from, to *types.TipSet) er continue } - hash, err := ethTxHashFromSignedMessage(ctx, smsg, m.StateAPI) + hash, err := ethTxHashFromSignedMessage(smsg) if err != nil { return err } @@ -84,13 +85,18 @@ func (m *EthTxHashManager) ProcessSignedMessage(ctx context.Context, msg *types. return } - ethTx, err := newEthTxFromSignedMessage(ctx, msg, m.StateAPI) + 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(ethTx.Hash, msg.Cid()) + err = m.TransactionHashLookup.UpsertHash(txHash, msg.Cid()) if err != nil { log.Errorf("error inserting tx mapping to db: %s", err) return