From 1724d1666e17225af88afa974ace9032095bc5fa Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 19 Jan 2023 11:02:09 -0500 Subject: [PATCH 01/13] fix: should not serve non v0 api in v1 --- node/rpc.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/rpc.go b/node/rpc.go index a96e6e3ac..1dab2a61f 100644 --- a/node/rpc.go +++ b/node/rpc.go @@ -94,8 +94,9 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server fnapi = api.PermissionedFullAPI(fnapi) } + var v0 v0api.FullNode = &(struct{ v0api.FullNode }{&v0api.WrapperV1Full{FullNode: fnapi}}) serveRpc("/rpc/v1", fnapi) - serveRpc("/rpc/v0", &v0api.WrapperV1Full{FullNode: fnapi}) + serveRpc("/rpc/v0", v0) // Import handler handleImportFunc := handleImport(a.(*impl.FullNodeAPI)) From 5518e64574ee2cd8d14cbe04646fecf553b3399b Mon Sep 17 00:00:00 2001 From: Aayush Date: Thu, 19 Jan 2023 11:30:37 -0500 Subject: [PATCH 02/13] fix: chain: put tipsetkey upon expansion of tipset --- chain/store/store.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/chain/store/store.go b/chain/store/store.go index 5ed037ee5..6dc17d766 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -384,7 +384,19 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error { if err != nil { 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 { return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err) From 178aaf6ac42fe1d41bbff95342fbf6b1d718d20c Mon Sep 17 00:00:00 2001 From: ZenGround0 <5515260+ZenGround0@users.noreply.github.com> Date: Thu, 19 Jan 2023 11:41:11 -0500 Subject: [PATCH 03/13] fix broke invoke (#10031) Co-authored-by: zenground0 --- cli/evm.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/evm.go b/cli/evm.go index 739f56f8b..738788448 100644 --- a/cli/evm.go +++ b/cli/evm.go @@ -345,8 +345,8 @@ var EvmInvokeCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if argc := cctx.Args().Len(); argc < 2 || argc > 3 { - return xerrors.Errorf("must pass the address, entry point and (optionally) input data") + if argc := cctx.Args().Len(); argc != 2 { + return xerrors.Errorf("must pass the address and calldata") } addr, err := address.NewFromString(cctx.Args().Get(0)) @@ -355,7 +355,7 @@ var EvmInvokeCmd = &cli.Command{ } var calldata []byte - calldata, err = hex.DecodeString(cctx.Args().Get(2)) + calldata, err = hex.DecodeString(cctx.Args().Get(1)) if err != nil { return xerrors.Errorf("decoding hex input data: %w", err) } @@ -388,7 +388,7 @@ var EvmInvokeCmd = &cli.Command{ To: addr, From: fromAddr, Value: val, - Method: abi.MethodNum(2), + Method: builtintypes.MethodsEVM.InvokeContract, Params: calldata, } From 66f5ee4ae9a46cb56377a420bcc46cb7b3fbd24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Jan 2023 18:06:59 +0100 Subject: [PATCH 04/13] config: Fevm.EnableEthPRC --- documentation/en/default-lotus-config.toml | 7 +- itests/eth_deploy_test.go | 2 +- itests/eth_filter_test.go | 2 +- itests/eth_hash_lookup_test.go | 95 ++-------------------- itests/eth_transactions_test.go | 6 +- itests/kit/node_opts.go | 4 +- node/builder_chain.go | 3 +- node/config/def.go | 4 +- node/config/doc_gen.go | 5 +- node/config/types.go | 6 +- node/impl/full/dummy.go | 62 ++++++++------ node/impl/full/eth.go | 2 +- node/modules/ethmodule.go | 5 -- 13 files changed, 64 insertions(+), 139 deletions(-) diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index fbdbc852c..a12dbf2ec 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -344,12 +344,11 @@ [Fevm] - # 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. + # EnableEthPRC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. # # type: bool - # env var: LOTUS_FEVM_ENABLEETHHASHTOFILECOINCIDMAPPING - #EnableEthHashToFilecoinCidMapping = false + # env var: LOTUS_FEVM_ENABLEETHPRC + #EnableEthPRC = false # 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 diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index f73076d02..b5f0b647c 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -41,7 +41,7 @@ func TestDeployment(t *testing.T) { cfg.ActorEvent.EnableRealTimeFilterAPI = true return nil }), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blockTime) diff --git a/itests/eth_filter_test.go b/itests/eth_filter_test.go index 3d2d3064a..ad2034af6 100644 --- a/itests/eth_filter_test.go +++ b/itests/eth_filter_test.go @@ -204,7 +204,7 @@ func TestEthNewFilterCatchAll(t *testing.T) { kit.QuietMiningLogs() 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.RealTimeFilterAPI(), kit.EthRPC()) ens.InterconnectAll().BeginMining(blockTime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/itests/eth_hash_lookup_test.go b/itests/eth_hash_lookup_test.go index bad705fe1..4fe77b2bc 100644 --- a/itests/eth_hash_lookup_test.go +++ b/itests/eth_hash_lookup_test.go @@ -16,7 +16,6 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" "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 @@ -29,7 +28,7 @@ func TestTransactionHashLookup(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -112,86 +111,6 @@ func TestTransactionHashLookup(t *testing.T) { 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: ðAddr, - 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 func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { kit.QuietMiningLogs() @@ -201,7 +120,7 @@ func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -271,7 +190,7 @@ func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -348,7 +267,7 @@ func TestTransactionHashLookupNonexistentMessage(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -379,7 +298,7 @@ func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -476,7 +395,7 @@ func TestEthGetMessageCidByTransactionHashSecp(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -547,7 +466,7 @@ func TestEthGetMessageCidByTransactionHashBLS(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthTxHashLookup(), + kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) diff --git a/itests/eth_transactions_test.go b/itests/eth_transactions_test.go index 052aae3cf..8a86a7c05 100644 --- a/itests/eth_transactions_test.go +++ b/itests/eth_transactions_test.go @@ -21,7 +21,7 @@ import ( func TestValueTransferValidSignature(t *testing.T) { blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthRPC()) ens.InterconnectAll().BeginMining(blockTime) @@ -106,7 +106,7 @@ func TestLegacyTransaction(t *testing.T) { func TestContractDeploymentValidSignature(t *testing.T) { blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthRPC()) ens.InterconnectAll().BeginMining(blockTime) @@ -167,7 +167,7 @@ func TestContractDeploymentValidSignature(t *testing.T) { func TestContractInvocation(t *testing.T) { blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthRPC()) ens.InterconnectAll().BeginMining(blockTime) diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index efaed8861..d093bb9c2 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -297,9 +297,9 @@ func HistoricFilterAPI(dbpath string) NodeOpt { }) } -func EthTxHashLookup() NodeOpt { +func EthRPC() NodeOpt { return WithCfgOpt(func(cfg *config.FullNode) error { - cfg.Fevm.EnableEthHashToFilecoinCidMapping = true + cfg.Fevm.EnableEthPRC = true return nil }) } diff --git a/node/builder_chain.go b/node/builder_chain.go index 221150be1..e13ab2c63 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -261,7 +261,8 @@ func ConfigFullNode(c interface{}) Option { // in lite-mode Eth event api is provided by gateway ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))), - Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)), + If(cfg.Fevm.EnableEthPRC, Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm))), + If(!cfg.Fevm.EnableEthPRC, Override(new(full.EthModuleAPI), &full.EthModuleDummy{})), ) } diff --git a/node/config/def.go b/node/config/def.go index 12efc408f..c170462f8 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -108,8 +108,8 @@ func DefaultFullNode() *FullNode { MaxFilterHeightRange: 2880, // conservative limit of one day }, Fevm: FevmConfig{ - EnableEthHashToFilecoinCidMapping: false, - EthTxHashMappingLifetimeDays: 0, + EnableEthPRC: false, + EthTxHashMappingLifetimeDays: 0, }, } } diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index c4cf08471..b52f7294f 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -401,11 +401,10 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# }, "FevmConfig": []DocField{ { - Name: "EnableEthHashToFilecoinCidMapping", + Name: "EnableEthPRC", Type: "bool", - Comment: `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.`, + Comment: `EnableEthPRC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.`, }, { Name: "EthTxHashMappingLifetimeDays", diff --git a/node/config/types.go b/node/config/types.go index 38671929d..018d8838c 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -695,9 +695,9 @@ type ActorEventConfig struct { } 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 + // EnableEthPRC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. + EnableEthPRC 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 diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 865e14c9a..3a75e6637 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -4,106 +4,118 @@ import ( "context" "errors" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types/ethtypes" ) -var ErrImplementMe = errors.New("Not implemented yet") +var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthPRC / LOTUS_FEVM_ENABLEETHPRC") 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) { - return 0, ErrImplementMe + return 0, ErrModuleDisabled } 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) { - return 0, ErrImplementMe + return 0, ErrModuleDisabled } 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) { - return ethtypes.EthBlock{}, ErrImplementMe + return ethtypes.EthBlock{}, ErrModuleDisabled } 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) { - return nil, ErrImplementMe + return nil, ErrModuleDisabled } 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) { - return nil, ErrImplementMe + return nil, ErrModuleDisabled } 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) { - return ethtypes.EthTx{}, ErrImplementMe + return ethtypes.EthTx{}, ErrModuleDisabled } 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) { - return nil, ErrImplementMe + return nil, ErrModuleDisabled } 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) { - return ethtypes.EthFeeHistory{}, ErrImplementMe + return ethtypes.EthFeeHistory{}, ErrModuleDisabled } 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) { - return "", ErrImplementMe + return "", ErrModuleDisabled } 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) { - return 0, ErrImplementMe + return 0, ErrModuleDisabled } 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) { - return 0, ErrImplementMe + return 0, ErrModuleDisabled } 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) { - return ethtypes.EthBigIntZero, ErrImplementMe + return ethtypes.EthBigIntZero, ErrModuleDisabled } func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) { - return ethtypes.EthHash{}, ErrImplementMe + return ethtypes.EthHash{}, ErrModuleDisabled } + +var _ EthModuleAPI = &EthModuleDummy{} diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 755aacba1..8c0b43578 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -258,7 +258,7 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype } c := cid.Undef - if a.EthTxHashManager != nil { + if a.EthTxHashManager != nil { // todo rm checks var err error c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) if err != nil { diff --git a/node/modules/ethmodule.go b/node/modules/ethmodule.go index 904d09421..e90775b54 100644 --- a/node/modules/ethmodule.go +++ b/node/modules/ethmodule.go @@ -28,11 +28,6 @@ func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRep StateAPI: stateapi, } - if !cfg.EnableEthHashToFilecoinCidMapping { - // mapping functionality disabled. Nothing to do here - return em, nil - } - dbPath, err := r.SqlitePath() if err != nil { return nil, err From 60dbd59aa0766b3e6b8de20cf7117123239530dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Jan 2023 19:00:52 +0100 Subject: [PATCH 05/13] itests: Default enable Eth rpc --- itests/eth_deploy_test.go | 4 +--- itests/eth_filter_test.go | 2 +- itests/eth_hash_lookup_test.go | 7 ------- itests/eth_transactions_test.go | 6 +++--- itests/fevm_test.go | 7 +++++++ itests/kit/node_opts.go | 13 +++++++++++-- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index b5f0b647c..7a4860b06 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -40,9 +40,7 @@ func TestDeployment(t *testing.T) { kit.WithCfgOpt(func(cfg *config.FullNode) error { cfg.ActorEvent.EnableRealTimeFilterAPI = true return nil - }), - kit.EthRPC(), - ) + })) ens.InterconnectAll().BeginMining(blockTime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/itests/eth_filter_test.go b/itests/eth_filter_test.go index ad2034af6..39431e10f 100644 --- a/itests/eth_filter_test.go +++ b/itests/eth_filter_test.go @@ -204,7 +204,7 @@ func TestEthNewFilterCatchAll(t *testing.T) { kit.QuietMiningLogs() blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI(), kit.EthRPC()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI()) ens.InterconnectAll().BeginMining(blockTime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/itests/eth_hash_lookup_test.go b/itests/eth_hash_lookup_test.go index 4fe77b2bc..37d069796 100644 --- a/itests/eth_hash_lookup_test.go +++ b/itests/eth_hash_lookup_test.go @@ -28,7 +28,6 @@ func TestTransactionHashLookup(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -120,7 +119,6 @@ func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -190,7 +188,6 @@ func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -267,7 +264,6 @@ func TestTransactionHashLookupNonexistentMessage(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -298,7 +294,6 @@ func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -395,7 +390,6 @@ func TestEthGetMessageCidByTransactionHashSecp(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) @@ -466,7 +460,6 @@ func TestEthGetMessageCidByTransactionHashBLS(t *testing.T) { t, kit.MockProofs(), kit.ThroughRPC(), - kit.EthRPC(), ) ens.InterconnectAll().BeginMining(blocktime) diff --git a/itests/eth_transactions_test.go b/itests/eth_transactions_test.go index 8a86a7c05..0c8f1baa5 100644 --- a/itests/eth_transactions_test.go +++ b/itests/eth_transactions_test.go @@ -21,7 +21,7 @@ import ( func TestValueTransferValidSignature(t *testing.T) { blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthRPC()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) @@ -106,7 +106,7 @@ func TestLegacyTransaction(t *testing.T) { func TestContractDeploymentValidSignature(t *testing.T) { blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthRPC()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) @@ -167,7 +167,7 @@ func TestContractDeploymentValidSignature(t *testing.T) { func TestContractInvocation(t *testing.T) { blockTime := 100 * time.Millisecond - client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthRPC()) + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 5872c62e8..9111d1d28 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -132,3 +132,10 @@ func TestFEVMDelegateCall(t *testing.T) { require.NoError(t, err) 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.EnableEthPRC") +} diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index d093bb9c2..8f9b305dd 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -58,6 +58,15 @@ var DefaultNodeOpts = nodeOpts{ sectors: DefaultPresealsPerBootstrapMiner, sectorSize: abi.SectorSize(2 << 10), // 2KiB. + cfgOpts: []CfgOption{ + func(cfg *config.FullNode) error { + // test defaults + + cfg.Fevm.EnableEthPRC = true + return nil + }, + }, + workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed}, workerStorageOpt: func(store paths.Store) paths.Store { return store }, } @@ -297,9 +306,9 @@ func HistoricFilterAPI(dbpath string) NodeOpt { }) } -func EthRPC() NodeOpt { +func DisableEthRPC() NodeOpt { return WithCfgOpt(func(cfg *config.FullNode) error { - cfg.Fevm.EnableEthPRC = true + cfg.Fevm.EnableEthPRC = false return nil }) } From 1e845c61a2cf42c3389be845834a2b91e7fd6089 Mon Sep 17 00:00:00 2001 From: raulk Date: Thu, 19 Jan 2023 18:25:23 +0000 Subject: [PATCH 06/13] add integration test to catch tipset CID flakiness. (#10071) --- .circleci/config.yml | 5 +++ itests/deals_padding_test.go | 2 +- itests/deals_power_test.go | 2 +- itests/eth_block_hash_test.go | 65 +++++++++++++++++++++++++++++++++++ itests/eth_deploy_test.go | 1 + itests/kit/node_full.go | 18 +++++++--- 6 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 itests/eth_block_hash_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index db625b2be..9315461f8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -730,6 +730,11 @@ workflows: suite: itest-eth_balance 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: name: test-itest-eth_deploy suite: itest-eth_deploy diff --git a/itests/deals_padding_test.go b/itests/deals_padding_test.go index 3535a1227..aaca45360 100644 --- a/itests/deals_padding_test.go +++ b/itests/deals_padding_test.go @@ -33,7 +33,7 @@ func TestDealPadding(t *testing.T) { dh := kit.NewDealHarness(t, client, miner, miner) 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 res, inFile := client.CreateImportFile(ctx, 1, 200) diff --git a/itests/deals_power_test.go b/itests/deals_power_test.go index 1ca28c6fd..57483cde7 100644 --- a/itests/deals_power_test.go +++ b/itests/deals_power_test.go @@ -52,7 +52,7 @@ func TestFirstDealEnablesMining(t *testing.T) { providerMined := make(chan struct{}) go func() { - _ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) + _ = client.WaitTillChain(ctx, kit.BlocksMinedByAll(provider.ActorAddr)) close(providerMined) }() diff --git a/itests/eth_block_hash_test.go b/itests/eth_block_hash_test.go new file mode 100644 index 000000000..ac6506bb2 --- /dev/null +++ b/itests/eth_block_hash_test.go @@ -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) + } +} diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index f73076d02..0d7ab1829 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -100,6 +100,7 @@ func TestDeployment(t *testing.T) { mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) require.NoError(t, err) + require.NotNil(t, mpoolTx) // require that the hashes are identical require.Equal(t, hash, mpoolTx.Hash) diff --git a/itests/kit/node_full.go b/itests/kit/node_full.go index 12db91c68..4546f5a03 100644 --- a/itests/kit/node_full.go +++ b/itests/kit/node_full.go @@ -135,13 +135,21 @@ func HeightAtLeast(target abi.ChainEpoch) ChainPredicate { } } -// BlockMinedBy returns a ChainPredicate that is satisfied when we observe the -// first block mined by the specified miner. -func BlockMinedBy(miner address.Address) ChainPredicate { +// BlocksMinedByAll returns a ChainPredicate that is satisfied when we observe a +// tipset including blocks from all the specified miners, in no particular order. +func BlocksMinedByAll(miner ...address.Address) ChainPredicate { return func(ts *types.TipSet) bool { + seen := make([]bool, len(miner)) + var done int for _, b := range ts.Blocks() { - if b.Miner == miner { - return true + for i, m := range miner { + if b.Miner != m || seen[i] { + continue + } + seen[i] = true + if done++; done == len(miner) { + return true + } } } return false From e194cbc715217c72ea3c63be334910e2dacd4248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Jan 2023 19:30:18 +0100 Subject: [PATCH 07/13] impl: Cleanup EthTxHashManager handling --- node/impl/full/eth.go | 45 ++++++++++++++++----------------------- node/modules/ethmodule.go | 23 ++++++++++---------- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 8c0b43578..1cf3475de 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -257,14 +257,11 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype return nil, nil } - c := cid.Undef - if a.EthTxHashManager != nil { // todo rm checks - var err error - c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) - if err != nil { - 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 if c == cid.Undef { c = txHash.ToCid() @@ -306,25 +303,22 @@ func (a *EthModule) EthGetMessageCidByTransactionHash(ctx context.Context, txHas return nil, nil } - c := cid.Undef - if a.EthTxHashManager != nil { - var err error - c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) - // We fall out of the first condition and continue - if errors.Is(err, ethhashlookup.ErrNotFound) { - log.Debug("could not find transaction hash %s in lookup table", txHash.String()) - } else if err != nil { - return nil, xerrors.Errorf("database error: %w", err) - } else { - return &c, nil - } + c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) + // We fall out of the first condition and continue + if errors.Is(err, ethhashlookup.ErrNotFound) { + log.Debug("could not find transaction hash %s in lookup table", txHash.String()) + } else if err != 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 if c == cid.Undef { c = txHash.ToCid() } - _, err := a.StateAPI.Chain.GetSignedMessage(ctx, c) + _, err = a.StateAPI.Chain.GetSignedMessage(ctx, c) if err == nil { // This is an Eth Tx, Secp message, Or BLS message in the mpool 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) { - c := cid.Undef - if a.EthTxHashManager != nil { - var err error - c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash) - if err != nil { - 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 if c == cid.Undef { c = txHash.ToCid() diff --git a/node/modules/ethmodule.go b/node/modules/ethmodule.go index e90775b54..92d4dab3e 100644 --- a/node/modules/ethmodule.go +++ b/node/modules/ethmodule.go @@ -19,15 +19,6 @@ 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) { 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{ - Chain: cs, - Mpool: mp, - StateManager: sm, - ChainAPI: chainapi, - MpoolAPI: mpoolapi, - StateAPI: stateapi, - } - dbPath, err := r.SqlitePath() if err != nil { return nil, err @@ -49,8 +40,6 @@ func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRep TransactionHashLookup: transactionHashLookup, } - em.EthTxHashManager = ðTxHashManager - const ChainHeadConfidence = 1 ctx := helpers.LifecycleCtx(mctx, lc) @@ -75,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: ðTxHashManager, + }, nil } } From eaccb571a561e4e9b827f74d7fa73a5cf6b661f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Jan 2023 21:35:19 +0100 Subject: [PATCH 08/13] fix: config: Fix eth rpc typo (#10076) --- documentation/en/default-lotus-config.toml | 6 +++--- itests/fevm_test.go | 2 +- itests/kit/node_opts.go | 4 ++-- node/builder_chain.go | 4 ++-- node/config/def.go | 2 +- node/config/doc_gen.go | 4 ++-- node/config/types.go | 4 ++-- node/impl/full/dummy.go | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index a12dbf2ec..27c2a689b 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -344,11 +344,11 @@ [Fevm] - # EnableEthPRC enables eth_ rpc, and 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. # # type: bool - # env var: LOTUS_FEVM_ENABLEETHPRC - #EnableEthPRC = false + # env var: LOTUS_FEVM_ENABLEETHRPC + #EnableEthRPC = false # 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 diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 9111d1d28..e05b0e2cc 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -137,5 +137,5 @@ 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.EnableEthPRC") + require.ErrorContains(t, err, "module disabled, enable with Fevm.EnableEthRPC") } diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index 8f9b305dd..617dbe79f 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -62,7 +62,7 @@ var DefaultNodeOpts = nodeOpts{ func(cfg *config.FullNode) error { // test defaults - cfg.Fevm.EnableEthPRC = true + cfg.Fevm.EnableEthRPC = true return nil }, }, @@ -308,7 +308,7 @@ func HistoricFilterAPI(dbpath string) NodeOpt { func DisableEthRPC() NodeOpt { return WithCfgOpt(func(cfg *config.FullNode) error { - cfg.Fevm.EnableEthPRC = false + cfg.Fevm.EnableEthRPC = false return nil }) } diff --git a/node/builder_chain.go b/node/builder_chain.go index e13ab2c63..13533ba50 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -261,8 +261,8 @@ func ConfigFullNode(c interface{}) Option { // in lite-mode Eth event api is provided by gateway ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))), - If(cfg.Fevm.EnableEthPRC, Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm))), - If(!cfg.Fevm.EnableEthPRC, Override(new(full.EthModuleAPI), &full.EthModuleDummy{})), + If(cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm))), + If(!cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), &full.EthModuleDummy{})), ) } diff --git a/node/config/def.go b/node/config/def.go index c170462f8..57e38b6c5 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -108,7 +108,7 @@ func DefaultFullNode() *FullNode { MaxFilterHeightRange: 2880, // conservative limit of one day }, Fevm: FevmConfig{ - EnableEthPRC: false, + EnableEthRPC: false, EthTxHashMappingLifetimeDays: 0, }, } diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index b52f7294f..a0703eba7 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -401,10 +401,10 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# }, "FevmConfig": []DocField{ { - Name: "EnableEthPRC", + Name: "EnableEthRPC", Type: "bool", - Comment: `EnableEthPRC enables eth_ rpc, and 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.`, }, { Name: "EthTxHashMappingLifetimeDays", diff --git a/node/config/types.go b/node/config/types.go index 018d8838c..d39eb1a14 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -695,8 +695,8 @@ type ActorEventConfig struct { } type FevmConfig struct { - // EnableEthPRC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. - EnableEthPRC bool + // EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. + EnableEthRPC 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 diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 3a75e6637..aa1450212 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -10,7 +10,7 @@ import ( "github.com/filecoin-project/lotus/chain/types/ethtypes" ) -var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthPRC / LOTUS_FEVM_ENABLEETHPRC") +var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthRPC / LOTUS_FEVM_ENABLEETHPRC") type EthModuleDummy struct{} From 2335bed58a4f3dfaf87f5ecea2d32407aac1c5ea Mon Sep 17 00:00:00 2001 From: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Date: Thu, 19 Jan 2023 15:36:03 -0500 Subject: [PATCH 09/13] Revert "fix: should not serve non v0 apis in v0" (#10073) --- node/rpc.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/node/rpc.go b/node/rpc.go index 1dab2a61f..a96e6e3ac 100644 --- a/node/rpc.go +++ b/node/rpc.go @@ -94,9 +94,8 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server fnapi = api.PermissionedFullAPI(fnapi) } - var v0 v0api.FullNode = &(struct{ v0api.FullNode }{&v0api.WrapperV1Full{FullNode: fnapi}}) serveRpc("/rpc/v1", fnapi) - serveRpc("/rpc/v0", v0) + serveRpc("/rpc/v0", &v0api.WrapperV1Full{FullNode: fnapi}) // Import handler handleImportFunc := handleImport(a.(*impl.FullNodeAPI)) From 522e96f01638debc4bcaad53faf57e99aeb4bd49 Mon Sep 17 00:00:00 2001 From: Shrenuj Bansal <108157875+shrenujbansal@users.noreply.github.com> Date: Thu, 19 Jan 2023 17:57:48 -0500 Subject: [PATCH 10/13] fix: msg signing with delegated keys and send cli changes (#10056) * fix msg signing with delegated keys and send cli changes * make gen and docsgen * address comments --- chain/messagesigner/messagesigner.go | 30 +++++++++++++++++++++++++++- cli/send.go | 17 ++++++++++++++++ documentation/en/cli-lotus.md | 19 +++++++++--------- lib/sigs/delegated/init.go | 2 +- node/impl/full/wallet.go | 12 ++++++++++- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/chain/messagesigner/messagesigner.go b/chain/messagesigner/messagesigner.go index 96457e9f8..6a622dd57 100644 --- a/chain/messagesigner/messagesigner.go +++ b/chain/messagesigner/messagesigner.go @@ -13,10 +13,13 @@ import ( "golang.org/x/xerrors" "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/chain/messagepool" "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" ) @@ -66,15 +69,24 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, sp // Sign the message with the 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() if err != nil { 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, Extra: mb.RawData(), }) + if err != nil { 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 { 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 +} diff --git a/cli/send.go b/cli/send.go index 4268f8eb2..3e390584d 100644 --- a/cli/send.go +++ b/cli/send.go @@ -13,6 +13,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" ) var sendCmd = &cli.Command{ @@ -24,6 +25,10 @@ var sendCmd = &cli.Command{ Name: "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{ Name: "gas-premium", Usage: "specify gas price to use in AttoFIL", @@ -98,6 +103,18 @@ var sendCmd = &cli.Command{ } 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") { diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 616a4a356..5e0c7a305 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -181,15 +181,16 @@ CATEGORY: BASIC OPTIONS: - --force Deprecated: use global 'force-send' (default: false) - --from value optionally specify the account to send funds from - --gas-feecap value specify gas fee cap to use in AttoFIL (default: "0") - --gas-limit value specify gas limit (default: 0) - --gas-premium value specify gas price to use in AttoFIL (default: "0") - --method value specify method to invoke (default: 0) - --nonce value specify the nonce to use (default: 0) - --params-hex value specify invocation parameters in hex - --params-json value specify invocation parameters in json + --force Deprecated: use global 'force-send' (default: false) + --from value optionally specify the account to send funds from + --from-eth-addr value optionally specify the eth addr to send funds from + --gas-feecap value specify gas fee cap to use in AttoFIL (default: "0") + --gas-limit value specify gas limit (default: 0) + --gas-premium value specify gas price to use in AttoFIL (default: "0") + --method value specify method to invoke (default: 0) + --nonce value specify the nonce to use (default: 0) + --params-hex value specify invocation parameters in hex + --params-json value specify invocation parameters in json ``` diff --git a/lib/sigs/delegated/init.go b/lib/sigs/delegated/init.go index 4db83b3e7..81886ceaa 100644 --- a/lib/sigs/delegated/init.go +++ b/lib/sigs/delegated/init.go @@ -68,7 +68,7 @@ func (delegatedSigner) Verify(sig []byte, a address.Address, msg []byte) error { } 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 diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index 67bb96101..0927e5aca 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -11,9 +11,11 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "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/types" "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/chain/wallet/key" "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) } + 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() if err != nil { 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, Extra: mb.RawData(), }) From 6601d9031daa1dfb58b97c7d1184b0208190f435 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Thu, 19 Jan 2023 17:44:58 -0500 Subject: [PATCH 11/13] Set default path for eth event db, set it to enabled by default if EnableEthRPC is set --- documentation/en/default-lotus-config.toml | 94 +++++++++++++---- itests/eth_deploy_test.go | 7 +- itests/eth_filter_test.go | 15 ++- itests/kit/node_opts.go | 13 +-- node/builder_chain.go | 2 +- node/config/def.go | 16 +-- node/config/doc_gen.go | 116 +++++++++++---------- node/config/types.go | 42 ++++---- node/modules/actorevent.go | 35 +++++-- node/modules/ethmodule.go | 4 +- 10 files changed, 206 insertions(+), 138 deletions(-) diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index 27c2a689b..378c5be73 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -293,58 +293,62 @@ #Tracing = false -[ActorEvent] - # EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted. +[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_ACTOREVENT_ENABLEREALTIMEFILTERAPI - #EnableRealTimeFilterAPI = false + # env var: LOTUS_EVENTS_DISABLEREALTIMEFILTERAPI + #DisableRealTimeFilterAPI = 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. + # 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_ACTOREVENT_ENABLEHISTORICFILTERAPI - #EnableHistoricFilterAPI = false + # env var: LOTUS_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_ACTOREVENT_FILTERTTL - #FilterTTL = "24h0m0s" + # env var: LOTUS_EVENTS_FILTERTTL + #FilterTTL = "0s" # MaxFilters specifies the maximum number of filters that may exist at any one time. # # type: int - # env var: LOTUS_ACTOREVENT_MAXFILTERS - #MaxFilters = 100 + # env var: LOTUS_EVENTS_MAXFILTERS + #MaxFilters = 0 # 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 + # env var: LOTUS_EVENTS_MAXFILTERRESULTS + #MaxFilterResults = 0 # 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 + # env var: LOTUS_EVENTS_MAXFILTERHEIGHTRANGE + #MaxFilterHeightRange = 0 - # 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 # 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 = "" + # env var: LOTUS_EVENTS_DATABASEPATH + #DatabasePath = "" [Fevm] # EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. + # This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above. # # type: bool # env var: LOTUS_FEVM_ENABLEETHRPC @@ -357,4 +361,56 @@ # env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS #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 = "" + diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index bc939762e..98038de7b 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -20,7 +20,6 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/itests/kit" - "github.com/filecoin-project/lotus/node/config" ) // TestDeployment smoke tests the deployment of a contract via the @@ -36,11 +35,7 @@ func TestDeployment(t *testing.T) { client, _, ens := kit.EnsembleMinimal( t, kit.MockProofs(), - kit.ThroughRPC(), - kit.WithCfgOpt(func(cfg *config.FullNode) error { - cfg.ActorEvent.EnableRealTimeFilterAPI = true - return nil - })) + kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/itests/eth_filter_test.go b/itests/eth_filter_test.go index 39431e10f..a44601b32 100644 --- a/itests/eth_filter_test.go +++ b/itests/eth_filter_test.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "encoding/json" "os" - "path/filepath" "strconv" "strings" "testing" @@ -30,7 +29,7 @@ func TestEthNewPendingTransactionFilter(t *testing.T) { kit.QuietMiningLogs() - 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) // create a new address where to send funds. @@ -124,7 +123,7 @@ func TestEthNewBlockFilter(t *testing.T) { kit.QuietMiningLogs() - 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) // create a new address where to send funds. @@ -204,7 +203,7 @@ func TestEthNewFilterCatchAll(t *testing.T) { kit.QuietMiningLogs() blockTime := 100 * time.Millisecond - 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(blockTime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) @@ -569,9 +568,8 @@ func TestEthGetLogsAll(t *testing.T) { kit.QuietMiningLogs() 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(), kit.WithEthRPC()) ens.InterconnectAll().BeginMining(blockTime) ethContractAddr, received := invokeContractAndWaitUntilAllOnChain(t, client, 10) @@ -632,9 +630,8 @@ func TestEthGetLogsByTopic(t *testing.T) { kit.QuietMiningLogs() 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(), kit.WithEthRPC()) ens.InterconnectAll().BeginMining(blockTime) invocations := 1 @@ -696,7 +693,7 @@ func TestEthSubscribeLogs(t *testing.T) { kit.QuietMiningLogs() blockTime := 100 * time.Millisecond - 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(blockTime) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index 617dbe79f..5d418c5be 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -290,18 +290,9 @@ func SplitstoreMessges() NodeOpt { }) } -func RealTimeFilterAPI() NodeOpt { +func WithEthRPC() NodeOpt { return WithCfgOpt(func(cfg *config.FullNode) error { - cfg.ActorEvent.EnableRealTimeFilterAPI = true - return nil - }) -} - -func HistoricFilterAPI(dbpath string) NodeOpt { - return WithCfgOpt(func(cfg *config.FullNode) error { - cfg.ActorEvent.EnableRealTimeFilterAPI = true - cfg.ActorEvent.EnableHistoricFilterAPI = true - cfg.ActorEvent.ActorEventDatabasePath = dbpath + cfg.Fevm.EnableEthRPC = true return nil }) } diff --git a/node/builder_chain.go b/node/builder_chain.go index 13533ba50..545c061b2 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -259,7 +259,7 @@ func ConfigFullNode(c interface{}) Option { // Actor event filtering support Override(new(events.EventAPI), From(new(modules.EventAPI))), // 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))), If(cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm))), If(!cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), &full.EthModuleDummy{})), diff --git a/node/config/def.go b/node/config/def.go index 57e38b6c5..663408d39 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -99,17 +99,17 @@ func DefaultFullNode() *FullNode { }, }, 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{ EnableEthRPC: false, EthTxHashMappingLifetimeDays: 0, + Events: EventsConfig{ + DisableRealTimeFilterAPI: false, + DisableHistoricFilterAPI: false, + FilterTTL: Duration(time.Hour * 24), + MaxFilters: 100, + MaxFilterResults: 10000, + MaxFilterHeightRange: 2880, // conservative limit of one day + }, }, } } diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index a0703eba7..052d1924d 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -29,56 +29,6 @@ var Doc = map[string][]DocField{ 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{ { Name: "DisableMetadataLog", @@ -391,6 +341,59 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# Comment: ``, }, }, + "EventsConfig": []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{ { Name: "DefaultMaxFee", @@ -404,7 +407,8 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# Name: "EnableEthRPC", Type: "bool", - Comment: `EnableEthRPC enables eth_ rpc, and 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. +This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`, }, { Name: "EthTxHashMappingLifetimeDays", @@ -413,6 +417,12 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# 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`, }, + { + Name: "Events", + Type: "EventsConfig", + + Comment: ``, + }, }, "FullNode": []DocField{ { @@ -446,8 +456,8 @@ Set to 0 to keep all mappings`, Comment: ``, }, { - Name: "ActorEvent", - Type: "ActorEventConfig", + Name: "Events", + Type: "EventsConfig", Comment: ``, }, diff --git a/node/config/types.go b/node/config/types.go index d39eb1a14..546c24655 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -27,7 +27,7 @@ type FullNode struct { Fees FeeConfig Chainstore Chainstore Cluster UserRaftConfig - ActorEvent ActorEventConfig + Events EventsConfig Fevm FevmConfig } @@ -660,13 +660,28 @@ type UserRaftConfig struct { Tracing bool } -type ActorEventConfig struct { - // EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted. - EnableRealTimeFilterAPI bool +type FevmConfig struct { + // EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. + // 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. - // A queryable index of events will be maintained. - EnableHistoricFilterAPI 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 + + Events EventsConfig +} + +type EventsConfig 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 // this time become eligible for automatic deletion. @@ -682,23 +697,14 @@ type ActorEventConfig struct { // the entire chain) 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 // 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). - ActorEventDatabasePath string + DatabasePath string // Others, not implemented yet: // Set a limit on the number of active websocket subscriptions (may be zero) // Set a timeout for subscription clients // Set upper bound on index size } - -type FevmConfig struct { - // EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. - EnableEthRPC 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 -} diff --git a/node/modules/actorevent.go b/node/modules/actorevent.go index 1c574cb68..eb5afb8e6 100644 --- a/node/modules/actorevent.go +++ b/node/modules/actorevent.go @@ -2,6 +2,7 @@ package modules import ( "context" + "path/filepath" "time" "github.com/multiformats/go-varint" @@ -20,6 +21,7 @@ import ( "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/repo" ) type EventAPI struct { @@ -31,16 +33,16 @@ type EventAPI struct { 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) { - 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) { +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, 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) ee := &full.EthEvent{ 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 // the historic filter API relies on the real time one return ee, nil @@ -51,21 +53,32 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy StateAPI: stateapi, ChainAPI: chainapi, } - ee.FilterStore = filter.NewMemFilterStore(cfg.MaxFilters) + ee.FilterStore = filter.NewMemFilterStore(cfg.Events.MaxFilters) // Start garbage collection for filters lc.Append(fx.Hook{ OnStart: func(context.Context) error { - go ee.GC(ctx, time.Duration(cfg.FilterTTL)) + go ee.GC(ctx, time.Duration(cfg.Events.FilterTTL)) return nil }, }) // Enable indexing of actor events 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 - eventIndex, err = filter.NewEventIndex(cfg.ActorEventDatabasePath) + eventIndex, err = filter.NewEventIndex(dbPath) if err != nil { return nil, err } @@ -103,13 +116,13 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy return *actor.Address, true }, - MaxFilterResults: cfg.MaxFilterResults, + MaxFilterResults: cfg.Events.MaxFilterResults, } ee.TipSetFilterManager = &filter.TipSetFilterManager{ - MaxFilterResults: cfg.MaxFilterResults, + MaxFilterResults: cfg.Events.MaxFilterResults, } ee.MemPoolFilterManager = &filter.MemPoolFilterManager{ - MaxFilterResults: cfg.MaxFilterResults, + MaxFilterResults: cfg.Events.MaxFilterResults, } const ChainHeadConfidence = 1 diff --git a/node/modules/ethmodule.go b/node/modules/ethmodule.go index 92d4dab3e..9889233f4 100644 --- a/node/modules/ethmodule.go +++ b/node/modules/ethmodule.go @@ -19,12 +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) { 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) { - dbPath, err := r.SqlitePath() + sqlitePath, err := r.SqlitePath() if err != nil { return nil, err } - transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(filepath.Join(dbPath, "txhash.db")) + transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(filepath.Join(sqlitePath, "txhash.db")) if err != nil { return nil, err } From 2c566875273788d2101280aab429d985dc61ba8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 20 Jan 2023 00:17:55 +0000 Subject: [PATCH 12/13] fix: events: put the _signed_ message through the pipeline. We were putting the unsigned/VM message through the pipeline. The events index was storing the _unsigned_ message CID. However, the Eth tx hash index maps signed Delegated-signature message CIDs to transaction hashes, i.e. it uses the _signed_ message CID. As a result, eth_getLogs and other log-related methods were unable to resolve the transaction hash from the index properly, and would end up returning 0x00..00 in the transactionHash field. --- chain/events/filter/event.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chain/events/filter/event.go b/chain/events/filter/event.go index a19f49a50..779b0c186 100644 --- a/chain/events/filter/event.go +++ b/chain/events/filter/event.go @@ -266,13 +266,13 @@ func (te *TipSetEvents) messages(ctx context.Context) ([]executedMessage, error) } type executedMessage struct { - msg *types.Message + msg types.ChainMsg rct *types.MessageReceipt // events extracted from receipt evs []*types.Event } -func (e *executedMessage) Message() *types.Message { +func (e *executedMessage) Message() types.ChainMsg { return e.msg } @@ -428,7 +428,7 @@ func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rc ems := make([]executedMessage, len(msgs)) for i := 0; i < len(msgs); i++ { - ems[i].msg = msgs[i].VMMessage() + ems[i].msg = msgs[i] var rct types.MessageReceipt found, err := arr.Get(uint64(i), &rct) From 63d4c10b9eb4a0fea54111d75c3ad19abf40c8c0 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 19 Jan 2023 19:53:21 -0500 Subject: [PATCH 13/13] remove extra event doc --- documentation/en/default-lotus-config.toml | 53 ---------------------- node/config/def.go | 2 +- node/config/doc_gen.go | 10 +--- node/config/types.go | 5 +- 4 files changed, 5 insertions(+), 65 deletions(-) diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index 378c5be73..41d7e6aca 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -293,59 +293,6 @@ #Tracing = false -[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_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_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_EVENTS_FILTERTTL - #FilterTTL = "0s" - - # MaxFilters specifies the maximum number of filters that may exist at any one time. - # - # type: int - # env var: LOTUS_EVENTS_MAXFILTERS - #MaxFilters = 0 - - # MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter. - # - # type: int - # env var: LOTUS_EVENTS_MAXFILTERRESULTS - #MaxFilterResults = 0 - - # 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_EVENTS_MAXFILTERHEIGHTRANGE - #MaxFilterHeightRange = 0 - - # 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_EVENTS_DATABASEPATH - #DatabasePath = "" - - [Fevm] # EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. # This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above. diff --git a/node/config/def.go b/node/config/def.go index 663408d39..9a24449ba 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -102,7 +102,7 @@ func DefaultFullNode() *FullNode { Fevm: FevmConfig{ EnableEthRPC: false, EthTxHashMappingLifetimeDays: 0, - Events: EventsConfig{ + Events: Events{ DisableRealTimeFilterAPI: false, DisableHistoricFilterAPI: false, FilterTTL: Duration(time.Hour * 24), diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index 052d1924d..8b79bed4f 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -341,7 +341,7 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# Comment: ``, }, }, - "EventsConfig": []DocField{ + "Events": []DocField{ { Name: "DisableRealTimeFilterAPI", Type: "bool", @@ -419,7 +419,7 @@ Set to 0 to keep all mappings`, }, { Name: "Events", - Type: "EventsConfig", + Type: "Events", Comment: ``, }, @@ -455,12 +455,6 @@ Set to 0 to keep all mappings`, Comment: ``, }, - { - Name: "Events", - Type: "EventsConfig", - - Comment: ``, - }, { Name: "Fevm", Type: "FevmConfig", diff --git a/node/config/types.go b/node/config/types.go index 546c24655..690e8caee 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -27,7 +27,6 @@ type FullNode struct { Fees FeeConfig Chainstore Chainstore Cluster UserRaftConfig - Events EventsConfig Fevm FevmConfig } @@ -669,10 +668,10 @@ type FevmConfig struct { // Set to 0 to keep all mappings EthTxHashMappingLifetimeDays int - Events EventsConfig + Events Events } -type EventsConfig struct { +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.