Merge branch 'release/v1.20.0' into iand/issue-9849-filters

This commit is contained in:
Raúl Kripalani 2023-01-20 01:11:31 +00:00
commit 21c93f1dc1
28 changed files with 553 additions and 384 deletions

View File

@ -730,6 +730,11 @@ workflows:
suite: itest-eth_balance suite: itest-eth_balance
target: "./itests/eth_balance_test.go" target: "./itests/eth_balance_test.go"
- test:
name: test-itest-eth_block_hash
suite: itest-eth_block_hash
target: "./itests/eth_block_hash_test.go"
- test: - test:
name: test-itest-eth_deploy name: test-itest-eth_deploy
suite: itest-eth_deploy suite: itest-eth_deploy

View File

@ -275,13 +275,13 @@ func (te *TipSetEvents) messages(ctx context.Context) ([]executedMessage, error)
} }
type executedMessage struct { type executedMessage struct {
msg *types.Message msg types.ChainMsg
rct *types.MessageReceipt rct *types.MessageReceipt
// events extracted from receipt // events extracted from receipt
evs []*types.Event evs []*types.Event
} }
func (e *executedMessage) Message() *types.Message { func (e *executedMessage) Message() types.ChainMsg {
return e.msg return e.msg
} }
@ -437,7 +437,7 @@ func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rc
ems := make([]executedMessage, len(msgs)) ems := make([]executedMessage, len(msgs))
for i := 0; i < len(msgs); i++ { for i := 0; i < len(msgs); i++ {
ems[i].msg = msgs[i].VMMessage() ems[i].msg = msgs[i]
var rct types.MessageReceipt var rct types.MessageReceipt
found, err := arr.Get(uint64(i), &rct) found, err := arr.Get(uint64(i), &rct)

View File

@ -13,10 +13,13 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
) )
@ -66,15 +69,24 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, sp
// Sign the message with the nonce // Sign the message with the nonce
msg.Nonce = nonce msg.Nonce = nonce
keyInfo, err := ms.wallet.WalletExport(ctx, msg.From)
if err != nil {
return nil, err
}
sb, err := SigningBytes(msg, key.ActSigType(keyInfo.Type))
if err != nil {
return nil, err
}
mb, err := msg.ToStorageBlock() mb, err := msg.ToStorageBlock()
if err != nil { if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err) return nil, xerrors.Errorf("serializing message: %w", err)
} }
sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{ sig, err := ms.wallet.WalletSign(ctx, msg.From, sb, api.MsgMeta{
Type: api.MTChainMsg, Type: api.MTChainMsg,
Extra: mb.RawData(), Extra: mb.RawData(),
}) })
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w, addr=%s", err, msg.From) return nil, xerrors.Errorf("failed to sign message: %w, addr=%s", err, msg.From)
} }
@ -187,3 +199,19 @@ func (ms *MessageSigner) SaveNonce(ctx context.Context, addr address.Address, no
func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key { func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key {
return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()}) return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()})
} }
func SigningBytes(msg *types.Message, sigType crypto.SigType) ([]byte, error) {
if sigType == crypto.SigTypeDelegated {
txArgs, err := ethtypes.EthTxArgsFromMessage(msg)
if err != nil {
return nil, xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
}
rlpEncodedMsg, err := txArgs.ToRlpUnsignedMsg()
if err != nil {
return nil, xerrors.Errorf("failed to repack eth rlp message: %w", err)
}
return rlpEncodedMsg, nil
}
return msg.Cid().Bytes(), nil
}

View File

@ -384,7 +384,19 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
if err != nil { if err != nil {
return xerrors.Errorf("errored while expanding tipset: %w", err) return xerrors.Errorf("errored while expanding tipset: %w", err)
} }
log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids())
if expanded.Key() != ts.Key() {
log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids())
tsBlk, err := expanded.Key().ToStorageBlock()
if err != nil {
return xerrors.Errorf("failed to get tipset key block: %w", err)
}
if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil {
return xerrors.Errorf("failed to put tipset key block: %w", err)
}
}
if err := cs.MaybeTakeHeavierTipSet(ctx, expanded); err != nil { if err := cs.MaybeTakeHeavierTipSet(ctx, expanded); err != nil {
return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err) return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err)

View File

@ -345,8 +345,8 @@ var EvmInvokeCmd = &cli.Command{
defer closer() defer closer()
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
if argc := cctx.Args().Len(); argc < 2 || argc > 3 { if argc := cctx.Args().Len(); argc != 2 {
return xerrors.Errorf("must pass the address, entry point and (optionally) input data") return xerrors.Errorf("must pass the address and calldata")
} }
addr, err := address.NewFromString(cctx.Args().Get(0)) addr, err := address.NewFromString(cctx.Args().Get(0))
@ -355,7 +355,7 @@ var EvmInvokeCmd = &cli.Command{
} }
var calldata []byte var calldata []byte
calldata, err = hex.DecodeString(cctx.Args().Get(2)) calldata, err = hex.DecodeString(cctx.Args().Get(1))
if err != nil { if err != nil {
return xerrors.Errorf("decoding hex input data: %w", err) return xerrors.Errorf("decoding hex input data: %w", err)
} }
@ -388,7 +388,7 @@ var EvmInvokeCmd = &cli.Command{
To: addr, To: addr,
From: fromAddr, From: fromAddr,
Value: val, Value: val,
Method: abi.MethodNum(2), Method: builtintypes.MethodsEVM.InvokeContract,
Params: calldata, Params: calldata,
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
) )
var sendCmd = &cli.Command{ var sendCmd = &cli.Command{
@ -24,6 +25,10 @@ var sendCmd = &cli.Command{
Name: "from", Name: "from",
Usage: "optionally specify the account to send funds from", Usage: "optionally specify the account to send funds from",
}, },
&cli.StringFlag{
Name: "from-eth-addr",
Usage: "optionally specify the eth addr to send funds from",
},
&cli.StringFlag{ &cli.StringFlag{
Name: "gas-premium", Name: "gas-premium",
Usage: "specify gas price to use in AttoFIL", Usage: "specify gas price to use in AttoFIL",
@ -98,6 +103,18 @@ var sendCmd = &cli.Command{
} }
params.From = addr params.From = addr
} else if from := cctx.String("from-eth-addr"); from != "" {
eaddr, err := ethtypes.ParseEthAddress(from)
if err != nil {
return err
}
faddr, err := eaddr.ToFilecoinAddress()
if err != nil {
fmt.Println("error on conversion to faddr")
return err
}
fmt.Println("f4 addr: ", faddr)
params.From = faddr
} }
if cctx.IsSet("gas-premium") { if cctx.IsSet("gas-premium") {

View File

@ -181,15 +181,16 @@ CATEGORY:
BASIC BASIC
OPTIONS: OPTIONS:
--force Deprecated: use global 'force-send' (default: false) --force Deprecated: use global 'force-send' (default: false)
--from value optionally specify the account to send funds from --from value optionally specify the account to send funds from
--gas-feecap value specify gas fee cap to use in AttoFIL (default: "0") --from-eth-addr value optionally specify the eth addr to send funds from
--gas-limit value specify gas limit (default: 0) --gas-feecap value specify gas fee cap to use in AttoFIL (default: "0")
--gas-premium value specify gas price to use in AttoFIL (default: "0") --gas-limit value specify gas limit (default: 0)
--method value specify method to invoke (default: 0) --gas-premium value specify gas price to use in AttoFIL (default: "0")
--nonce value specify the nonce to use (default: 0) --method value specify method to invoke (default: 0)
--params-hex value specify invocation parameters in hex --nonce value specify the nonce to use (default: 0)
--params-json value specify invocation parameters in json --params-hex value specify invocation parameters in hex
--params-json value specify invocation parameters in json
``` ```

View File

@ -293,63 +293,13 @@
#Tracing = false #Tracing = false
[ActorEvent]
# EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.
#
# type: bool
# env var: LOTUS_ACTOREVENT_ENABLEREALTIMEFILTERAPI
#EnableRealTimeFilterAPI = false
# EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past.
# A queryable index of events will be maintained.
#
# type: bool
# env var: LOTUS_ACTOREVENT_ENABLEHISTORICFILTERAPI
#EnableHistoricFilterAPI = false
# FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
# this time become eligible for automatic deletion.
#
# type: Duration
# env var: LOTUS_ACTOREVENT_FILTERTTL
#FilterTTL = "24h0m0s"
# MaxFilters specifies the maximum number of filters that may exist at any one time.
#
# type: int
# env var: LOTUS_ACTOREVENT_MAXFILTERS
#MaxFilters = 100
# MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.
#
# type: int
# env var: LOTUS_ACTOREVENT_MAXFILTERRESULTS
#MaxFilterResults = 10000
# MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
# the entire chain)
#
# type: uint64
# env var: LOTUS_ACTOREVENT_MAXFILTERHEIGHTRANGE
#MaxFilterHeightRange = 2880
# ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to
# support the historic filter APIs. If the database does not exist it will be created. The directory containing
# the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
# relative to the CWD (current working directory).
#
# type: string
# env var: LOTUS_ACTOREVENT_ACTOREVENTDATABASEPATH
#ActorEventDatabasePath = ""
[Fevm] [Fevm]
# EnableEthHashToFilecoinCidMapping enables storing a mapping of eth transaction hashes to filecoin message Cids # EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
# You will not be able to look up ethereum transactions by their hash if this is disabled. # This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
# #
# type: bool # type: bool
# env var: LOTUS_FEVM_ENABLEETHHASHTOFILECOINCIDMAPPING # env var: LOTUS_FEVM_ENABLEETHRPC
#EnableEthHashToFilecoinCidMapping = false #EnableEthRPC = false
# EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days # EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
# Set to 0 to keep all mappings # Set to 0 to keep all mappings
@ -358,4 +308,56 @@
# env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS # env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS
#EthTxHashMappingLifetimeDays = 0 #EthTxHashMappingLifetimeDays = 0
[Fevm.Events]
# EnableEthRPC enables APIs that
# DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
# The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
#
# type: bool
# env var: LOTUS_FEVM_EVENTS_DISABLEREALTIMEFILTERAPI
#DisableRealTimeFilterAPI = false
# DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
# that occurred in the past. HistoricFilterAPI maintains a queryable index of events.
# The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
#
# type: bool
# env var: LOTUS_FEVM_EVENTS_DISABLEHISTORICFILTERAPI
#DisableHistoricFilterAPI = false
# FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
# this time become eligible for automatic deletion.
#
# type: Duration
# env var: LOTUS_FEVM_EVENTS_FILTERTTL
#FilterTTL = "24h0m0s"
# MaxFilters specifies the maximum number of filters that may exist at any one time.
#
# type: int
# env var: LOTUS_FEVM_EVENTS_MAXFILTERS
#MaxFilters = 100
# MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.
#
# type: int
# env var: LOTUS_FEVM_EVENTS_MAXFILTERRESULTS
#MaxFilterResults = 10000
# MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
# the entire chain)
#
# type: uint64
# env var: LOTUS_FEVM_EVENTS_MAXFILTERHEIGHTRANGE
#MaxFilterHeightRange = 2880
# DatabasePath is the full path to a sqlite database that will be used to index actor events to
# support the historic filter APIs. If the database does not exist it will be created. The directory containing
# the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
# relative to the CWD (current working directory).
#
# type: string
# env var: LOTUS_FEVM_EVENTS_DATABASEPATH
#DatabasePath = ""

View File

@ -33,7 +33,7 @@ func TestDealPadding(t *testing.T) {
dh := kit.NewDealHarness(t, client, miner, miner) dh := kit.NewDealHarness(t, client, miner, miner)
ctx := context.Background() ctx := context.Background()
client.WaitTillChain(ctx, kit.BlockMinedBy(miner.ActorAddr)) client.WaitTillChain(ctx, kit.BlocksMinedByAll(miner.ActorAddr))
// Create a random file, would originally be a 256-byte sector // Create a random file, would originally be a 256-byte sector
res, inFile := client.CreateImportFile(ctx, 1, 200) res, inFile := client.CreateImportFile(ctx, 1, 200)

View File

@ -52,7 +52,7 @@ func TestFirstDealEnablesMining(t *testing.T) {
providerMined := make(chan struct{}) providerMined := make(chan struct{})
go func() { go func() {
_ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) _ = client.WaitTillChain(ctx, kit.BlocksMinedByAll(provider.ActorAddr))
close(providerMined) close(providerMined)
}() }()

View File

@ -0,0 +1,65 @@
package itests
import (
"context"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/itests/kit"
)
// TestEthBlockHashesCorrect_MultiBlockTipset validates that blocks retrieved through
// EthGetBlockByNumber are identical to blocks retrieved through
// EthGetBlockByHash, when using the block hash returned by the former.
//
// Specifically, it checks the system behaves correctly with multiblock tipsets.
//
// Catches regressions around https://github.com/filecoin-project/lotus/issues/10061.
func TestEthBlockHashesCorrect_MultiBlockTipset(t *testing.T) {
// miner is connected to the first node, and we want to observe the chain
// from the second node.
blocktime := 100 * time.Millisecond
n1, m1, m2, ens := kit.EnsembleOneTwo(t,
kit.MockProofs(),
kit.ThroughRPC(),
)
ens.InterconnectAll().BeginMining(blocktime)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
n1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(25)))
defer cancel()
var n2 kit.TestFullNode
ens.FullNode(&n2, kit.ThroughRPC()).Start().Connect(n2, n1)
// find the first tipset where all miners mined a block.
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute)
n2.WaitTillChain(ctx, kit.BlocksMinedByAll(m1.ActorAddr, m2.ActorAddr))
defer cancel()
head, err := n2.ChainHead(context.Background())
require.NoError(t, err)
// let the chain run a little bit longer to minimise the chance of reorgs
n2.WaitTillChain(ctx, kit.HeightAtLeast(head.Height()+50))
head, err = n2.ChainHead(context.Background())
require.NoError(t, err)
for i := 1; i <= int(head.Height()); i++ {
hex := fmt.Sprintf("0x%x", i)
ethBlockA, err := n2.EthGetBlockByNumber(ctx, hex, true)
require.NoError(t, err)
ethBlockB, err := n2.EthGetBlockByHash(ctx, ethBlockA.Hash, true)
require.NoError(t, err)
require.Equal(t, ethBlockA, ethBlockB)
}
}

View File

@ -20,7 +20,6 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/kit"
"github.com/filecoin-project/lotus/node/config"
) )
// TestDeployment smoke tests the deployment of a contract via the // TestDeployment smoke tests the deployment of a contract via the
@ -36,13 +35,7 @@ func TestDeployment(t *testing.T) {
client, _, ens := kit.EnsembleMinimal( client, _, ens := kit.EnsembleMinimal(
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC())
kit.WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true
return nil
}),
kit.EthTxHashLookup(),
)
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -100,6 +93,7 @@ func TestDeployment(t *testing.T) {
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, mpoolTx)
// require that the hashes are identical // require that the hashes are identical
require.Equal(t, hash, mpoolTx.Hash) require.Equal(t, hash, mpoolTx.Hash)

View File

@ -9,7 +9,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"path/filepath"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -86,7 +85,7 @@ func TestEthNewPendingTransactionFilter(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC())
ens.InterconnectAll().BeginMining(10 * time.Millisecond) ens.InterconnectAll().BeginMining(10 * time.Millisecond)
// create a new address where to send funds. // create a new address where to send funds.
@ -190,7 +189,7 @@ func TestEthNewBlockFilter(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC())
ens.InterconnectAll().BeginMining(10 * time.Millisecond) ens.InterconnectAll().BeginMining(10 * time.Millisecond)
// create a new address where to send funds. // create a new address where to send funds.
@ -294,7 +293,7 @@ func TestEthNewFilterCatchAll(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI(), kit.EthTxHashLookup()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -373,9 +372,8 @@ func TestEthGetLogsAll(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
dbpath := filepath.Join(t.TempDir(), "actorevents.db")
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.HistoricFilterAPI(dbpath)) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -418,9 +416,8 @@ func TestEthGetLogsByTopic(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
dbpath := filepath.Join(t.TempDir(), "actorevents.db")
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.HistoricFilterAPI(dbpath)) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
invocations := 1 invocations := 1
@ -457,7 +454,7 @@ func TestEthSubscribeLogs(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -517,9 +514,8 @@ func TestEthGetLogs(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
dbpath := filepath.Join(t.TempDir(), "actorevents.db")
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.HistoricFilterAPI(dbpath)) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -1078,9 +1074,8 @@ func TestEthGetLogsWithBlockRanges(t *testing.T) {
kit.QuietAllLogsExcept("events", "messagepool") kit.QuietAllLogsExcept("events", "messagepool")
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
dbpath := filepath.Join(t.TempDir(), "actorevents.db")
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.HistoricFilterAPI(dbpath)) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -1908,15 +1903,98 @@ func ParseEthLog(in map[string]interface{}) (*ethtypes.EthLog, error) {
return el, err return el, err
} }
func decodeLogBytes(orig []byte) []byte { func invokeContractAndWaitUntilAllOnChain(t *testing.T, client *kit.TestFullNode, iterations int) (ethtypes.EthAddress, map[ethtypes.EthHash]msgInTipset) {
if len(orig) == 0 { require := require.New(t)
return orig
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
blockTime := 100 * time.Millisecond
// install contract
contractHex, err := os.ReadFile("contracts/events.bin")
require.NoError(err)
contract, err := hex.DecodeString(string(contractHex))
require.NoError(err)
fromAddr, err := client.WalletDefaultAddress(ctx)
require.NoError(err)
result := client.EVM().DeployContract(ctx, fromAddr, contract)
idAddr, err := address.NewIDAddress(result.ActorID)
require.NoError(err)
t.Logf("actor ID address is %s", idAddr)
msgChan := make(chan msgInTipset, iterations)
waitAllCh := make(chan struct{})
go func() {
headChangeCh, err := client.ChainNotify(ctx)
require.NoError(err)
<-headChangeCh // skip hccurrent
count := 0
for {
select {
case headChanges := <-headChangeCh:
for _, change := range headChanges {
if change.Type == store.HCApply || change.Type == store.HCRevert {
msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key())
require.NoError(err)
count += len(msgs)
for _, m := range msgs {
select {
case msgChan <- msgInTipset{msg: m, ts: change.Val, reverted: change.Type == store.HCRevert}:
default:
}
}
if count == iterations {
close(msgChan)
close(waitAllCh)
return
}
}
}
}
}
}()
time.Sleep(blockTime * 6)
for i := 0; i < iterations; i++ {
// log a four topic event with data
ret := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x02}, nil)
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
} }
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))
if err != nil { select {
return orig case <-waitAllCh:
case <-time.After(time.Minute):
t.Errorf("timeout to wait for pack messages")
} }
return decoded
received := make(map[ethtypes.EthHash]msgInTipset)
for m := range msgChan {
eh, err := ethtypes.EthHashFromCid(m.msg.Cid)
require.NoError(err)
received[eh] = m
}
require.Equal(iterations, len(received), "all messages on chain")
head, err := client.ChainHead(ctx)
require.NoError(err)
actor, err := client.StateGetActor(ctx, idAddr, head.Key())
require.NoError(err)
require.NotNil(actor.Address)
ethContractAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address)
require.NoError(err)
return ethContractAddr, received
} }
func paddedEthBytes(orig []byte) ethtypes.EthBytes { func paddedEthBytes(orig []byte) ethtypes.EthBytes {
@ -2050,3 +2128,14 @@ func (e *ethFilterBuilder) Topic4OneOf(hs ...ethtypes.EthHash) *ethFilterBuilder
e.filter.Topics[3] = hs e.filter.Topics[3] = hs
return e return e
} }
func decodeLogBytes(orig []byte) []byte {
if len(orig) == 0 {
return orig
}
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))
if err != nil {
return orig
}
return decoded
}

View File

@ -16,7 +16,6 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/kit"
"github.com/filecoin-project/lotus/node/config"
) )
// TestTransactionHashLookup tests to see if lotus correctly stores a mapping from ethereum transaction hash to // TestTransactionHashLookup tests to see if lotus correctly stores a mapping from ethereum transaction hash to
@ -29,7 +28,6 @@ func TestTransactionHashLookup(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)
@ -112,86 +110,6 @@ func TestTransactionHashLookup(t *testing.T) {
require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction
} }
// TestTransactionHashLookupNoDb tests to see if looking up eth transactions by hash breaks without the lookup table
func TestTransactionHashLookupNoDb(t *testing.T) {
kit.QuietMiningLogs()
blocktime := 1 * time.Second
client, _, ens := kit.EnsembleMinimal(
t,
kit.MockProofs(),
kit.ThroughRPC(),
kit.WithCfgOpt(func(cfg *config.FullNode) error {
cfg.Fevm.EnableEthHashToFilecoinCidMapping = false
return nil
}),
)
ens.InterconnectAll().BeginMining(blocktime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
// install contract
contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex")
require.NoError(t, err)
contract, err := hex.DecodeString(string(contractHex))
require.NoError(t, err)
// create a new Ethereum account
key, ethAddr, deployer := client.EVM().NewAccount()
// send some funds to the f410 address
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
From: &ethAddr,
Data: contract,
})
require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
require.NoError(t, err)
// now deploy a contract from the embryo, and validate it went well
tx := ethtypes.EthTxArgs{
ChainID: build.Eip155ChainId,
Value: big.Zero(),
Nonce: 0,
MaxFeePerGas: types.NanoFil,
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
GasLimit: int(gaslimit),
Input: contract,
V: big.Zero(),
R: big.Zero(),
S: big.Zero(),
}
client.EVM().SignTransaction(&tx, key.PrivateKey)
rawTxHash, err := tx.TxHash()
require.NoError(t, err)
hash := client.EVM().SubmitTransaction(ctx, &tx)
require.Equal(t, rawTxHash, hash)
// We shouldn't be able to find the tx
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
require.NoError(t, err)
require.Nil(t, mpoolTx)
// Wait for message to land on chain, we can't know exactly when because we can't find it.
time.Sleep(20 * blocktime)
receipt, err := client.EthGetTransactionReceipt(ctx, hash)
require.NoError(t, err)
require.Nil(t, receipt)
// We still shouldn't be able to find the tx
chainTx, err := client.EthGetTransactionByHash(ctx, &hash)
require.NoError(t, err)
require.Nil(t, chainTx)
}
// TestTransactionHashLookupBlsFilecoinMessage tests to see if lotus can find a BLS Filecoin Message using the transaction hash // TestTransactionHashLookupBlsFilecoinMessage tests to see if lotus can find a BLS Filecoin Message using the transaction hash
func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) {
kit.QuietMiningLogs() kit.QuietMiningLogs()
@ -201,7 +119,6 @@ func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)
@ -271,7 +188,6 @@ func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)
@ -348,7 +264,6 @@ func TestTransactionHashLookupNonexistentMessage(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)
@ -379,7 +294,6 @@ func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)
@ -476,7 +390,6 @@ func TestEthGetMessageCidByTransactionHashSecp(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)
@ -547,7 +460,6 @@ func TestEthGetMessageCidByTransactionHashBLS(t *testing.T) {
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC(),
kit.EthTxHashLookup(),
) )
ens.InterconnectAll().BeginMining(blocktime) ens.InterconnectAll().BeginMining(blocktime)

View File

@ -21,7 +21,7 @@ import (
func TestValueTransferValidSignature(t *testing.T) { func TestValueTransferValidSignature(t *testing.T) {
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
@ -106,7 +106,7 @@ func TestLegacyTransaction(t *testing.T) {
func TestContractDeploymentValidSignature(t *testing.T) { func TestContractDeploymentValidSignature(t *testing.T) {
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
@ -167,7 +167,7 @@ func TestContractDeploymentValidSignature(t *testing.T) {
func TestContractInvocation(t *testing.T) { func TestContractInvocation(t *testing.T) {
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)

View File

@ -132,3 +132,10 @@ func TestFEVMDelegateCall(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, result, expectedResultActor) require.Equal(t, result, expectedResultActor)
} }
func TestEVMRpcDisable(t *testing.T) {
client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC())
_, err := client.EthBlockNumber(context.Background())
require.ErrorContains(t, err, "module disabled, enable with Fevm.EnableEthRPC")
}

View File

@ -135,13 +135,21 @@ func HeightAtLeast(target abi.ChainEpoch) ChainPredicate {
} }
} }
// BlockMinedBy returns a ChainPredicate that is satisfied when we observe the // BlocksMinedByAll returns a ChainPredicate that is satisfied when we observe a
// first block mined by the specified miner. // tipset including blocks from all the specified miners, in no particular order.
func BlockMinedBy(miner address.Address) ChainPredicate { func BlocksMinedByAll(miner ...address.Address) ChainPredicate {
return func(ts *types.TipSet) bool { return func(ts *types.TipSet) bool {
seen := make([]bool, len(miner))
var done int
for _, b := range ts.Blocks() { for _, b := range ts.Blocks() {
if b.Miner == miner { for i, m := range miner {
return true if b.Miner != m || seen[i] {
continue
}
seen[i] = true
if done++; done == len(miner) {
return true
}
} }
} }
return false return false

View File

@ -58,6 +58,15 @@ var DefaultNodeOpts = nodeOpts{
sectors: DefaultPresealsPerBootstrapMiner, sectors: DefaultPresealsPerBootstrapMiner,
sectorSize: abi.SectorSize(2 << 10), // 2KiB. sectorSize: abi.SectorSize(2 << 10), // 2KiB.
cfgOpts: []CfgOption{
func(cfg *config.FullNode) error {
// test defaults
cfg.Fevm.EnableEthRPC = true
return nil
},
},
workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed}, workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed},
workerStorageOpt: func(store paths.Store) paths.Store { return store }, workerStorageOpt: func(store paths.Store) paths.Store { return store },
} }
@ -281,25 +290,16 @@ func SplitstoreMessges() NodeOpt {
}) })
} }
func RealTimeFilterAPI() NodeOpt { func WithEthRPC() NodeOpt {
return WithCfgOpt(func(cfg *config.FullNode) error { return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true cfg.Fevm.EnableEthRPC = true
return nil return nil
}) })
} }
func HistoricFilterAPI(dbpath string) NodeOpt { func DisableEthRPC() NodeOpt {
return WithCfgOpt(func(cfg *config.FullNode) error { return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true cfg.Fevm.EnableEthRPC = false
cfg.ActorEvent.EnableHistoricFilterAPI = true
cfg.ActorEvent.ActorEventDatabasePath = dbpath
return nil
})
}
func EthTxHashLookup() NodeOpt {
return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.Fevm.EnableEthHashToFilecoinCidMapping = true
return nil return nil
}) })
} }

View File

@ -68,7 +68,7 @@ func (delegatedSigner) Verify(sig []byte, a address.Address, msg []byte) error {
} }
if maybeaddr != a { if maybeaddr != a {
return fmt.Errorf("signature did not match") return fmt.Errorf("signature did not match maybeaddr: %s, signer: %s", maybeaddr, a)
} }
return nil return nil

View File

@ -259,9 +259,10 @@ func ConfigFullNode(c interface{}) Option {
// Actor event filtering support // Actor event filtering support
Override(new(events.EventAPI), From(new(modules.EventAPI))), Override(new(events.EventAPI), From(new(modules.EventAPI))),
// in lite-mode Eth event api is provided by gateway // in lite-mode Eth event api is provided by gateway
ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))), ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.Fevm))),
Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)), If(cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm))),
If(!cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), &full.EthModuleDummy{})),
) )
} }

View File

@ -99,17 +99,17 @@ func DefaultFullNode() *FullNode {
}, },
}, },
Cluster: *DefaultUserRaftConfig(), Cluster: *DefaultUserRaftConfig(),
ActorEvent: ActorEventConfig{
EnableRealTimeFilterAPI: false,
EnableHistoricFilterAPI: false,
FilterTTL: Duration(time.Hour * 24),
MaxFilters: 100,
MaxFilterResults: 10000,
MaxFilterHeightRange: 2880, // conservative limit of one day
},
Fevm: FevmConfig{ Fevm: FevmConfig{
EnableEthHashToFilecoinCidMapping: false, EnableEthRPC: false,
EthTxHashMappingLifetimeDays: 0, EthTxHashMappingLifetimeDays: 0,
Events: Events{
DisableRealTimeFilterAPI: false,
DisableHistoricFilterAPI: false,
FilterTTL: Duration(time.Hour * 24),
MaxFilters: 100,
MaxFilterResults: 10000,
MaxFilterHeightRange: 2880, // conservative limit of one day
},
}, },
} }
} }

View File

@ -29,56 +29,6 @@ var Doc = map[string][]DocField{
Comment: ``, Comment: ``,
}, },
}, },
"ActorEventConfig": []DocField{
{
Name: "EnableRealTimeFilterAPI",
Type: "bool",
Comment: `EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.`,
},
{
Name: "EnableHistoricFilterAPI",
Type: "bool",
Comment: `EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past.
A queryable index of events will be maintained.`,
},
{
Name: "FilterTTL",
Type: "Duration",
Comment: `FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
this time become eligible for automatic deletion.`,
},
{
Name: "MaxFilters",
Type: "int",
Comment: `MaxFilters specifies the maximum number of filters that may exist at any one time.`,
},
{
Name: "MaxFilterResults",
Type: "int",
Comment: `MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.`,
},
{
Name: "MaxFilterHeightRange",
Type: "uint64",
Comment: `MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
the entire chain)`,
},
{
Name: "ActorEventDatabasePath",
Type: "string",
Comment: `ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to
support the historic filter APIs. If the database does not exist it will be created. The directory containing
the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
relative to the CWD (current working directory).`,
},
},
"Backup": []DocField{ "Backup": []DocField{
{ {
Name: "DisableMetadataLog", Name: "DisableMetadataLog",
@ -391,6 +341,59 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``, Comment: ``,
}, },
}, },
"Events": []DocField{
{
Name: "DisableRealTimeFilterAPI",
Type: "bool",
Comment: `EnableEthRPC enables APIs that
DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.`,
},
{
Name: "DisableHistoricFilterAPI",
Type: "bool",
Comment: `DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
that occurred in the past. HistoricFilterAPI maintains a queryable index of events.
The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.`,
},
{
Name: "FilterTTL",
Type: "Duration",
Comment: `FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
this time become eligible for automatic deletion.`,
},
{
Name: "MaxFilters",
Type: "int",
Comment: `MaxFilters specifies the maximum number of filters that may exist at any one time.`,
},
{
Name: "MaxFilterResults",
Type: "int",
Comment: `MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.`,
},
{
Name: "MaxFilterHeightRange",
Type: "uint64",
Comment: `MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
the entire chain)`,
},
{
Name: "DatabasePath",
Type: "string",
Comment: `DatabasePath is the full path to a sqlite database that will be used to index actor events to
support the historic filter APIs. If the database does not exist it will be created. The directory containing
the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
relative to the CWD (current working directory).`,
},
},
"FeeConfig": []DocField{ "FeeConfig": []DocField{
{ {
Name: "DefaultMaxFee", Name: "DefaultMaxFee",
@ -401,11 +404,11 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
}, },
"FevmConfig": []DocField{ "FevmConfig": []DocField{
{ {
Name: "EnableEthHashToFilecoinCidMapping", Name: "EnableEthRPC",
Type: "bool", Type: "bool",
Comment: `EnableEthHashToFilecoinCidMapping enables storing a mapping of eth transaction hashes to filecoin message Cids Comment: `EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
You will not be able to look up ethereum transactions by their hash if this is disabled.`, This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`,
}, },
{ {
Name: "EthTxHashMappingLifetimeDays", Name: "EthTxHashMappingLifetimeDays",
@ -414,6 +417,12 @@ You will not be able to look up ethereum transactions by their hash if this is d
Comment: `EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days Comment: `EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
Set to 0 to keep all mappings`, Set to 0 to keep all mappings`,
}, },
{
Name: "Events",
Type: "Events",
Comment: ``,
},
}, },
"FullNode": []DocField{ "FullNode": []DocField{
{ {
@ -446,12 +455,6 @@ Set to 0 to keep all mappings`,
Comment: ``, Comment: ``,
}, },
{
Name: "ActorEvent",
Type: "ActorEventConfig",
Comment: ``,
},
{ {
Name: "Fevm", Name: "Fevm",
Type: "FevmConfig", Type: "FevmConfig",

View File

@ -27,7 +27,6 @@ type FullNode struct {
Fees FeeConfig Fees FeeConfig
Chainstore Chainstore Chainstore Chainstore
Cluster UserRaftConfig Cluster UserRaftConfig
ActorEvent ActorEventConfig
Fevm FevmConfig Fevm FevmConfig
} }
@ -660,13 +659,28 @@ type UserRaftConfig struct {
Tracing bool Tracing bool
} }
type ActorEventConfig struct { type FevmConfig struct {
// EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted. // EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
EnableRealTimeFilterAPI bool // This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
EnableEthRPC bool
// EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past. // EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
// A queryable index of events will be maintained. // Set to 0 to keep all mappings
EnableHistoricFilterAPI bool EthTxHashMappingLifetimeDays int
Events Events
}
type Events struct {
// EnableEthRPC enables APIs that
// DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
// The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
DisableRealTimeFilterAPI bool
// DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
// that occurred in the past. HistoricFilterAPI maintains a queryable index of events.
// The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
DisableHistoricFilterAPI bool
// FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than // FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
// this time become eligible for automatic deletion. // this time become eligible for automatic deletion.
@ -682,23 +696,14 @@ type ActorEventConfig struct {
// the entire chain) // the entire chain)
MaxFilterHeightRange uint64 MaxFilterHeightRange uint64
// ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to // DatabasePath is the full path to a sqlite database that will be used to index actor events to
// support the historic filter APIs. If the database does not exist it will be created. The directory containing // support the historic filter APIs. If the database does not exist it will be created. The directory containing
// the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as // the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
// relative to the CWD (current working directory). // relative to the CWD (current working directory).
ActorEventDatabasePath string DatabasePath string
// Others, not implemented yet: // Others, not implemented yet:
// Set a limit on the number of active websocket subscriptions (may be zero) // Set a limit on the number of active websocket subscriptions (may be zero)
// Set a timeout for subscription clients // Set a timeout for subscription clients
// Set upper bound on index size // Set upper bound on index size
} }
type FevmConfig struct {
// EnableEthHashToFilecoinCidMapping enables storing a mapping of eth transaction hashes to filecoin message Cids
// You will not be able to look up ethereum transactions by their hash if this is disabled.
EnableEthHashToFilecoinCidMapping bool
// EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
// Set to 0 to keep all mappings
EthTxHashMappingLifetimeDays int
}

View File

@ -4,106 +4,118 @@ import (
"context" "context"
"errors" "errors"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/chain/types/ethtypes"
) )
var ErrImplementMe = errors.New("Not implemented yet") var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthRPC / LOTUS_FEVM_ENABLEETHPRC")
type EthModuleDummy struct{} type EthModuleDummy struct{}
func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) { func (e *EthModuleDummy) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) {
return nil, ErrImplementMe return nil, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) { func (e *EthModuleDummy) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) {
return ethtypes.EthBlock{}, ErrImplementMe return ethtypes.EthBlock{}, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) { func (e *EthModuleDummy) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) {
return ethtypes.EthBlock{}, ErrImplementMe return ethtypes.EthBlock{}, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) { func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
return nil, ErrImplementMe return nil, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
return nil, ErrImplementMe return nil, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
return ethtypes.EthTx{}, ErrImplementMe return ethtypes.EthTx{}, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
return ethtypes.EthTx{}, ErrImplementMe return ethtypes.EthTx{}, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) { func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
return nil, ErrImplementMe return nil, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
return nil, ErrImplementMe return nil, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
return ethtypes.EthBigIntZero, ErrImplementMe return ethtypes.EthBigIntZero, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) { func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) {
return ethtypes.EthFeeHistory{}, ErrImplementMe return ethtypes.EthFeeHistory{}, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) { func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) {
return "", ErrImplementMe return "", ErrModuleDisabled
} }
func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) { func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) {
return false, ErrImplementMe return false, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) { func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) {
return ethtypes.EthBigIntZero, ErrImplementMe return ethtypes.EthBigIntZero, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe return 0, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
return nil, ErrImplementMe return nil, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) { func (e *EthModuleDummy) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) {
return ethtypes.EthBigIntZero, ErrImplementMe return ethtypes.EthBigIntZero, ErrModuleDisabled
} }
func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) { func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) {
return ethtypes.EthHash{}, ErrImplementMe return ethtypes.EthHash{}, ErrModuleDisabled
} }
var _ EthModuleAPI = &EthModuleDummy{}

View File

@ -257,14 +257,11 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
return nil, nil return nil, nil
} }
c := cid.Undef c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash)
if a.EthTxHashManager != nil { if err != nil {
var err error log.Debug("could not find transaction hash %s in lookup table", txHash.String())
c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash)
if err != nil {
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
}
} }
// This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message // This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message
if c == cid.Undef { if c == cid.Undef {
c = txHash.ToCid() c = txHash.ToCid()
@ -306,25 +303,22 @@ func (a *EthModule) EthGetMessageCidByTransactionHash(ctx context.Context, txHas
return nil, nil return nil, nil
} }
c := cid.Undef c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash)
if a.EthTxHashManager != nil { // We fall out of the first condition and continue
var err error if errors.Is(err, ethhashlookup.ErrNotFound) {
c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) log.Debug("could not find transaction hash %s in lookup table", txHash.String())
// We fall out of the first condition and continue } else if err != nil {
if errors.Is(err, ethhashlookup.ErrNotFound) { return nil, xerrors.Errorf("database error: %w", err)
log.Debug("could not find transaction hash %s in lookup table", txHash.String()) } else {
} else if err != nil { return &c, nil
return nil, xerrors.Errorf("database error: %w", err)
} else {
return &c, nil
}
} }
// This isn't an eth transaction we have the mapping for, so let's try looking it up as a filecoin message // This isn't an eth transaction we have the mapping for, so let's try looking it up as a filecoin message
if c == cid.Undef { if c == cid.Undef {
c = txHash.ToCid() c = txHash.ToCid()
} }
_, err := a.StateAPI.Chain.GetSignedMessage(ctx, c) _, err = a.StateAPI.Chain.GetSignedMessage(ctx, c)
if err == nil { if err == nil {
// This is an Eth Tx, Secp message, Or BLS message in the mpool // This is an Eth Tx, Secp message, Or BLS message in the mpool
return &c, nil return &c, nil
@ -369,14 +363,11 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
} }
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
c := cid.Undef c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash)
if a.EthTxHashManager != nil { if err != nil {
var err error log.Debug("could not find transaction hash %s in lookup table", txHash.String())
c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash)
if err != nil {
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
}
} }
// This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message // This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message
if c == cid.Undef { if c == cid.Undef {
c = txHash.ToCid() c = txHash.ToCid()

View File

@ -11,9 +11,11 @@ import (
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/messagesigner"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
) )
@ -51,12 +53,20 @@ func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, ms
return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr)
} }
keyInfo, err := a.Wallet.WalletExport(ctx, k)
if err != nil {
return nil, err
}
sb, err := messagesigner.SigningBytes(msg, key.ActSigType(keyInfo.Type))
if err != nil {
return nil, err
}
mb, err := msg.ToStorageBlock() mb, err := msg.ToStorageBlock()
if err != nil { if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err) return nil, xerrors.Errorf("serializing message: %w", err)
} }
sig, err := a.Wallet.WalletSign(ctx, keyAddr, mb.Cid().Bytes(), api.MsgMeta{ sig, err := a.Wallet.WalletSign(ctx, keyAddr, sb, api.MsgMeta{
Type: api.MTChainMsg, Type: api.MTChainMsg,
Extra: mb.RawData(), Extra: mb.RawData(),
}) })

View File

@ -2,6 +2,7 @@ package modules
import ( import (
"context" "context"
"path/filepath"
"time" "time"
"github.com/multiformats/go-varint" "github.com/multiformats/go-varint"
@ -20,6 +21,7 @@ import (
"github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/impl/full"
"github.com/filecoin-project/lotus/node/modules/helpers" "github.com/filecoin-project/lotus/node/modules/helpers"
"github.com/filecoin-project/lotus/node/repo"
) )
type EventAPI struct { type EventAPI struct {
@ -31,16 +33,16 @@ type EventAPI struct {
var _ events.EventAPI = &EventAPI{} var _ events.EventAPI = &EventAPI{}
func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) { func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) { return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) {
ctx := helpers.LifecycleCtx(mctx, lc) ctx := helpers.LifecycleCtx(mctx, lc)
ee := &full.EthEvent{ ee := &full.EthEvent{
Chain: cs, Chain: cs,
MaxFilterHeightRange: abi.ChainEpoch(cfg.MaxFilterHeightRange), MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange),
} }
if !cfg.EnableRealTimeFilterAPI { if !cfg.EnableEthRPC || cfg.Events.DisableRealTimeFilterAPI {
// all event functionality is disabled // all event functionality is disabled
// the historic filter API relies on the real time one // the historic filter API relies on the real time one
return ee, nil return ee, nil
@ -51,21 +53,32 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy
StateAPI: stateapi, StateAPI: stateapi,
ChainAPI: chainapi, ChainAPI: chainapi,
} }
ee.FilterStore = filter.NewMemFilterStore(cfg.MaxFilters) ee.FilterStore = filter.NewMemFilterStore(cfg.Events.MaxFilters)
// Start garbage collection for filters // Start garbage collection for filters
lc.Append(fx.Hook{ lc.Append(fx.Hook{
OnStart: func(context.Context) error { OnStart: func(context.Context) error {
go ee.GC(ctx, time.Duration(cfg.FilterTTL)) go ee.GC(ctx, time.Duration(cfg.Events.FilterTTL))
return nil return nil
}, },
}) })
// Enable indexing of actor events // Enable indexing of actor events
var eventIndex *filter.EventIndex var eventIndex *filter.EventIndex
if cfg.EnableHistoricFilterAPI { if !cfg.Events.DisableHistoricFilterAPI {
var dbPath string
if cfg.Events.DatabasePath == "" {
sqlitePath, err := r.SqlitePath()
if err != nil {
return nil, err
}
dbPath = filepath.Join(sqlitePath, "events.db")
} else {
dbPath = cfg.Events.DatabasePath
}
var err error var err error
eventIndex, err = filter.NewEventIndex(cfg.ActorEventDatabasePath) eventIndex, err = filter.NewEventIndex(dbPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -103,13 +116,13 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy
return *actor.Address, true return *actor.Address, true
}, },
MaxFilterResults: cfg.MaxFilterResults, MaxFilterResults: cfg.Events.MaxFilterResults,
} }
ee.TipSetFilterManager = &filter.TipSetFilterManager{ ee.TipSetFilterManager = &filter.TipSetFilterManager{
MaxFilterResults: cfg.MaxFilterResults, MaxFilterResults: cfg.Events.MaxFilterResults,
} }
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{ ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
MaxFilterResults: cfg.MaxFilterResults, MaxFilterResults: cfg.Events.MaxFilterResults,
} }
const ChainHeadConfidence = 1 const ChainHeadConfidence = 1

View File

@ -19,26 +19,12 @@ import (
func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI, full.MpoolAPI) (*full.EthModule, error) { func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI, full.MpoolAPI) (*full.EthModule, error) {
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI, mpoolapi full.MpoolAPI) (*full.EthModule, error) { return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI, mpoolapi full.MpoolAPI) (*full.EthModule, error) {
em := &full.EthModule{ sqlitePath, err := r.SqlitePath()
Chain: cs,
Mpool: mp,
StateManager: sm,
ChainAPI: chainapi,
MpoolAPI: mpoolapi,
StateAPI: stateapi,
}
if !cfg.EnableEthHashToFilecoinCidMapping {
// mapping functionality disabled. Nothing to do here
return em, nil
}
dbPath, err := r.SqlitePath()
if err != nil { if err != nil {
return nil, err return nil, err
} }
transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(filepath.Join(dbPath, "txhash.db")) transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(filepath.Join(sqlitePath, "txhash.db"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -54,8 +40,6 @@ func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRep
TransactionHashLookup: transactionHashLookup, TransactionHashLookup: transactionHashLookup,
} }
em.EthTxHashManager = &ethTxHashManager
const ChainHeadConfidence = 1 const ChainHeadConfidence = 1
ctx := helpers.LifecycleCtx(mctx, lc) ctx := helpers.LifecycleCtx(mctx, lc)
@ -80,6 +64,16 @@ func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRep
}, },
}) })
return em, nil return &full.EthModule{
Chain: cs,
Mpool: mp,
StateManager: sm,
ChainAPI: chainapi,
MpoolAPI: mpoolapi,
StateAPI: stateapi,
EthTxHashManager: &ethTxHashManager,
}, nil
} }
} }