Merge branch 'release/v1.20.0' into iand/issue-9849-filters
This commit is contained in:
commit
21c93f1dc1
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
cli/send.go
17
cli/send.go
@ -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") {
|
||||||
|
@ -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
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -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 = ""
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
65
itests/eth_block_hash_test.go
Normal file
65
itests/eth_block_hash_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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: ð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
|
// 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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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{})),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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{}
|
||||||
|
@ -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()
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
|
@ -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
|
||||||
|
@ -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 = ðTxHashManager
|
|
||||||
|
|
||||||
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: ðTxHashManager,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user