NV18: Filecoin EVM runtime + Actor Events + EthAccount + EAM + f4 addressing (#9998)
Co-authored-by: Steven Allen <steven@stebalien.com> Co-authored-by: Raul Kripalani <raulk@users.noreply.github.com> Co-authored-by: Kevin Li <ychiaoli18@users.noreply.github.com> Co-authored-by: vyzo <vyzo@hackzen.org> Co-authored-by: Ian Davis <nospam@iandavis.com> Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com> Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Co-authored-by: Jennifer Wang <jiayingw703@gmail.com> Co-authored-by: Geoff Stuart <geoff.vball@gmail.com> Co-authored-by: Shrenuj Bansal <shrenuj.bansal@protocol.ai> Co-authored-by: Shrenuj Bansal <108157875+shrenujbansal@users.noreply.github.com> Co-authored-by: Geoff Stuart <geoffrey.stuart@protocol.ai> Co-authored-by: Aayush Rajasekaran <aayushrajasekaran@Aayushs-MacBook-Pro.local> Co-authored-by: ZenGround0 <5515260+ZenGround0@users.noreply.github.com> Co-authored-by: zenground0 <ZenGround0@users.noreply.github.com>
This commit is contained in:
co-authored by
Steven Allen
Raul Kripalani
Kevin Li
vyzo
Ian Davis
Aayush Rajasekaran
Jiaying Wang
Jennifer Wang
Geoff Stuart
Shrenuj Bansal
Shrenuj Bansal
Geoff Stuart
Aayush Rajasekaran
ZenGround0
zenground0
parent
048ccc71bb
commit
cdf3812e40
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/markets/storageadapter"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/exchange"
|
||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||
"github.com/filecoin-project/lotus/chain/market"
|
||||
@@ -151,6 +152,8 @@ var ChainNode = Options(
|
||||
Override(new(full.MpoolModuleAPI), From(new(api.Gateway))),
|
||||
Override(new(full.StateModuleAPI), From(new(api.Gateway))),
|
||||
Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager),
|
||||
// this to make tests pass, but we should consider actually implementing it in the gateway
|
||||
Override(new(full.EthModuleAPI), new(full.EthModuleDummy)),
|
||||
),
|
||||
|
||||
// Full node API / service startup
|
||||
@@ -158,6 +161,7 @@ var ChainNode = Options(
|
||||
Override(new(messagepool.Provider), messagepool.NewProvider),
|
||||
Override(new(messagepool.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
|
||||
Override(new(full.ChainModuleAPI), From(new(full.ChainModule))),
|
||||
Override(new(full.EthModuleAPI), From(new(full.EthModule))),
|
||||
Override(new(full.GasModuleAPI), From(new(full.GasModule))),
|
||||
Override(new(full.MpoolModuleAPI), From(new(full.MpoolModule))),
|
||||
Override(new(full.StateModuleAPI), From(new(full.StateModule))),
|
||||
@@ -241,6 +245,7 @@ func ConfigFullNode(c interface{}) Option {
|
||||
Unset(new(*wallet.LocalWallet)),
|
||||
Override(new(wallet.Default), wallet.NilDefault),
|
||||
),
|
||||
|
||||
// Chain node cluster enabled
|
||||
If(cfg.Cluster.ClusterModeEnabled,
|
||||
Override(new(*gorpc.Client), modules.NewRPCClient),
|
||||
@@ -251,6 +256,10 @@ func ConfigFullNode(c interface{}) Option {
|
||||
Override(new(*modules.RPCHandler), modules.NewRPCHandler),
|
||||
Override(GoRPCServer, modules.NewRPCServer),
|
||||
),
|
||||
|
||||
// Actor event filtering support
|
||||
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
||||
Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent)),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -70,11 +70,12 @@ func defCommon() Common {
|
||||
DirectPeers: nil,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var DefaultDefaultMaxFee = types.MustParseFIL("0.07")
|
||||
var DefaultSimultaneousTransfers = uint64(20)
|
||||
var (
|
||||
DefaultDefaultMaxFee = types.MustParseFIL("0.07")
|
||||
DefaultSimultaneousTransfers = uint64(20)
|
||||
)
|
||||
|
||||
// DefaultFullNode returns the default config
|
||||
func DefaultFullNode() *FullNode {
|
||||
@@ -98,6 +99,14 @@ 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
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +264,10 @@ func DefaultStorageMiner() *StorageMiner {
|
||||
return cfg
|
||||
}
|
||||
|
||||
var _ encoding.TextMarshaler = (*Duration)(nil)
|
||||
var _ encoding.TextUnmarshaler = (*Duration)(nil)
|
||||
var (
|
||||
_ encoding.TextMarshaler = (*Duration)(nil)
|
||||
_ encoding.TextUnmarshaler = (*Duration)(nil)
|
||||
)
|
||||
|
||||
// Duration is a wrapper type for time.Duration
|
||||
// for decoding and encoding from/to TOML
|
||||
|
||||
@@ -29,6 +29,56 @@ 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",
|
||||
@@ -378,6 +428,12 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
|
||||
Name: "Cluster",
|
||||
Type: "UserRaftConfig",
|
||||
|
||||
Comment: ``,
|
||||
},
|
||||
{
|
||||
Name: "ActorEvent",
|
||||
Type: "ActorEventConfig",
|
||||
|
||||
Comment: ``,
|
||||
},
|
||||
},
|
||||
|
||||
+35
-1
@@ -27,6 +27,7 @@ type FullNode struct {
|
||||
Fees FeeConfig
|
||||
Chainstore Chainstore
|
||||
Cluster UserRaftConfig
|
||||
ActorEvent ActorEventConfig
|
||||
}
|
||||
|
||||
// // Common
|
||||
@@ -168,7 +169,6 @@ type DealmakingConfig struct {
|
||||
}
|
||||
|
||||
type IndexProviderConfig struct {
|
||||
|
||||
// Enable set whether to enable indexing announcement to the network and expose endpoints that
|
||||
// allow indexer nodes to process announcements. Enabled by default.
|
||||
Enable bool
|
||||
@@ -658,3 +658,37 @@ type UserRaftConfig struct {
|
||||
// Tracing enables propagation of contexts across binary boundaries.
|
||||
Tracing bool
|
||||
}
|
||||
|
||||
type ActorEventConfig struct {
|
||||
// EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.
|
||||
EnableRealTimeFilterAPI 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
|
||||
|
||||
// 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.
|
||||
FilterTTL Duration
|
||||
|
||||
// MaxFilters specifies the maximum number of filters that may exist at any one time.
|
||||
MaxFilters int
|
||||
|
||||
// MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.
|
||||
MaxFilterResults int
|
||||
|
||||
// MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
|
||||
// the entire chain)
|
||||
MaxFilterHeightRange uint64
|
||||
|
||||
// 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).
|
||||
ActorEventDatabasePath 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
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ type FullNodeAPI struct {
|
||||
full.WalletAPI
|
||||
full.SyncAPI
|
||||
full.RaftAPI
|
||||
full.EthAPI
|
||||
|
||||
DS dtypes.MetadataDS
|
||||
NetworkName dtypes.NetworkName
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
amt4 "github.com/filecoin-project/go-amt-ipld/v4"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
@@ -654,6 +656,33 @@ func (a *ChainAPI) ChainBlockstoreInfo(ctx context.Context) (map[string]interfac
|
||||
return info.Info(), nil
|
||||
}
|
||||
|
||||
// ChainGetEvents returns the events under an event AMT root CID.
|
||||
//
|
||||
// TODO (raulk) make copies of this logic elsewhere use this (e.g. itests, CLI, events filter).
|
||||
func (a *ChainAPI) ChainGetEvents(ctx context.Context, root cid.Cid) ([]types.Event, error) {
|
||||
store := cbor.NewCborStore(a.ExposedBlockstore)
|
||||
evtArr, err := amt4.LoadAMT(ctx, store, root, amt4.UseTreeBitWidth(types.EventAMTBitwidth))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load events amt: %w", err)
|
||||
}
|
||||
|
||||
ret := make([]types.Event, 0, evtArr.Len())
|
||||
var evt types.Event
|
||||
err = evtArr.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error {
|
||||
if u > math.MaxInt {
|
||||
return xerrors.Errorf("too many events")
|
||||
}
|
||||
if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = append(ret, evt)
|
||||
return nil
|
||||
})
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (a *ChainAPI) ChainPrune(ctx context.Context, opts api.PruneOpts) error {
|
||||
pruner, ok := a.BaseBlockstore.(interface {
|
||||
PruneChain(opts api.PruneOpts) error
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package full
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
)
|
||||
|
||||
var ErrImplementMe = errors.New("Not implemented yet")
|
||||
|
||||
type EthModuleDummy struct{}
|
||||
|
||||
func (e *EthModuleDummy) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) {
|
||||
return nil, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) {
|
||||
return ethtypes.EthBlock{}, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) {
|
||||
return ethtypes.EthBlock{}, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||
return nil, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||
return nil, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return ethtypes.EthTx{}, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return ethtypes.EthTx{}, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) {
|
||||
return ethtypes.EthFeeHistory{}, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) {
|
||||
return "", ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) {
|
||||
return false, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrImplementMe
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) {
|
||||
return ethtypes.EthHash{}, ErrImplementMe
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -261,7 +261,7 @@ func gasEstimateGasLimit(
|
||||
msg.GasFeeCap = big.Zero()
|
||||
msg.GasPremium = big.Zero()
|
||||
|
||||
fromA, err := smgr.ResolveToKeyAddress(ctx, msgIn.From, currTs)
|
||||
fromA, err := smgr.ResolveToDeterministicAddress(ctx, msgIn.From, currTs)
|
||||
if err != nil {
|
||||
return -1, xerrors.Errorf("getting key address: %w", err)
|
||||
}
|
||||
@@ -323,7 +323,7 @@ func gasEstimateGasLimit(
|
||||
transitionalMulti = 4.095
|
||||
case 7:
|
||||
// skip, stay at 2.0
|
||||
//transitionalMulti = 1.289
|
||||
// transitionalMulti = 1.289
|
||||
case 11:
|
||||
transitionalMulti = 17.8758
|
||||
case 16:
|
||||
|
||||
@@ -175,7 +175,7 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe
|
||||
}
|
||||
}
|
||||
|
||||
fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msg.From, nil)
|
||||
fromA, err := a.Stmgr.ResolveToDeterministicAddress(ctx, msg.From, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting key address: %w", err)
|
||||
}
|
||||
|
||||
+17
-9
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
@@ -507,7 +508,7 @@ func (m *StateModule) StateAccountKey(ctx context.Context, addr address.Address,
|
||||
return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
|
||||
return m.StateManager.ResolveToKeyAddress(ctx, addr, ts)
|
||||
return m.StateManager.ResolveToDeterministicAddress(ctx, addr, ts)
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
|
||||
@@ -615,16 +616,22 @@ func (m *StateModule) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence
|
||||
|
||||
vmsg := cmsg.VMMessage()
|
||||
|
||||
t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts)
|
||||
if err != nil {
|
||||
switch t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts); {
|
||||
case errors.Is(err, stmgr.ErrMetadataNotFound):
|
||||
// This is not necessarily an error -- EVM methods (and in the future native actors) may
|
||||
// return just bytes, and in the not so distant future we'll have native wasm actors
|
||||
// that are by definition not in the registry.
|
||||
// So in this case, log a debug message and retun the raw bytes.
|
||||
log.Debugf("failed to get return type: %s", err)
|
||||
returndec = recpt.Return
|
||||
case err != nil:
|
||||
return nil, xerrors.Errorf("failed to get return type: %w", err)
|
||||
default:
|
||||
if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
returndec = t
|
||||
}
|
||||
|
||||
if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
returndec = t
|
||||
}
|
||||
|
||||
return &api.MsgLookup{
|
||||
@@ -1800,6 +1807,7 @@ func (a *StateAPI) StateGetNetworkParams(ctx context.Context) (*api.NetworkParam
|
||||
UpgradeOhSnapHeight: build.UpgradeOhSnapHeight,
|
||||
UpgradeSkyrHeight: build.UpgradeSkyrHeight,
|
||||
UpgradeSharkHeight: build.UpgradeSharkHeight,
|
||||
UpgradeHyggeHeight: build.UpgradeHyggeHeight,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (ty
|
||||
}
|
||||
|
||||
func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) {
|
||||
keyAddr, err := a.StateManagerAPI.ResolveToKeyAddress(ctx, k, nil)
|
||||
keyAddr, err := a.StateManagerAPI.ResolveToDeterministicAddress(ctx, k, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byt
|
||||
}
|
||||
|
||||
func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) {
|
||||
keyAddr, err := a.StateManagerAPI.ResolveToKeyAddress(ctx, k, nil)
|
||||
keyAddr, err := a.StateManagerAPI.ResolveToDeterministicAddress(ctx, k, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/multiformats/go-varint"
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/events/filter"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
)
|
||||
|
||||
type EventAPI struct {
|
||||
fx.In
|
||||
|
||||
full.ChainAPI
|
||||
full.StateAPI
|
||||
}
|
||||
|
||||
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) {
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
|
||||
ee := &full.EthEvent{
|
||||
Chain: cs,
|
||||
MaxFilterHeightRange: abi.ChainEpoch(cfg.MaxFilterHeightRange),
|
||||
}
|
||||
|
||||
if !cfg.EnableRealTimeFilterAPI {
|
||||
// all event functionality is disabled
|
||||
// the historic filter API relies on the real time one
|
||||
return ee, nil
|
||||
}
|
||||
|
||||
ee.SubManager = &full.EthSubscriptionManager{
|
||||
Chain: cs,
|
||||
StateAPI: stateapi,
|
||||
ChainAPI: chainapi,
|
||||
}
|
||||
ee.FilterStore = filter.NewMemFilterStore(cfg.MaxFilters)
|
||||
|
||||
// Start garbage collection for filters
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
go ee.GC(ctx, time.Duration(cfg.FilterTTL))
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
// Enable indexing of actor events
|
||||
var eventIndex *filter.EventIndex
|
||||
if cfg.EnableHistoricFilterAPI {
|
||||
var err error
|
||||
eventIndex, err = filter.NewEventIndex(cfg.ActorEventDatabasePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(context.Context) error {
|
||||
return eventIndex.Close()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
ee.EventFilterManager = &filter.EventFilterManager{
|
||||
ChainStore: cs,
|
||||
EventIndex: eventIndex, // will be nil unless EnableHistoricFilterAPI is true
|
||||
AddressResolver: func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
|
||||
// we only want to match using f4 addresses
|
||||
idAddr, err := address.NewIDAddress(uint64(emitter))
|
||||
if err != nil {
|
||||
return address.Undef, false
|
||||
}
|
||||
|
||||
actor, err := sm.LoadActor(ctx, idAddr, ts)
|
||||
if err != nil || actor.Address == nil {
|
||||
return address.Undef, false
|
||||
}
|
||||
|
||||
// if robust address is not f4 then we won't match against it so bail early
|
||||
if actor.Address.Protocol() != address.Delegated {
|
||||
return address.Undef, false
|
||||
}
|
||||
// we have an f4 address, make sure it's assigned by the EAM
|
||||
if namespace, _, err := varint.FromUvarint(actor.Address.Payload()); err != nil || namespace != builtintypes.EthereumAddressManagerActorID {
|
||||
return address.Undef, false
|
||||
}
|
||||
return *actor.Address, true
|
||||
},
|
||||
|
||||
MaxFilterResults: cfg.MaxFilterResults,
|
||||
}
|
||||
ee.TipSetFilterManager = &filter.TipSetFilterManager{
|
||||
MaxFilterResults: cfg.MaxFilterResults,
|
||||
}
|
||||
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
|
||||
MaxFilterResults: cfg.MaxFilterResults,
|
||||
}
|
||||
|
||||
const ChainHeadConfidence = 1
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
ev, err := events.NewEventsWithConfidence(ctx, &evapi, ChainHeadConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// ignore returned tipsets
|
||||
_ = ev.Observe(ee.EventFilterManager)
|
||||
_ = ev.Observe(ee.TipSetFilterManager)
|
||||
|
||||
ch, err := mp.Updates(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go ee.MemPoolFilterManager.WaitForMpoolUpdates(ctx, ch)
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return ee, nil
|
||||
}
|
||||
}
|
||||
+39
@@ -79,6 +79,45 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
||||
rpcServer.Register("Filecoin", hnd)
|
||||
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
|
||||
|
||||
// TODO: use reflect to automatically register all the eth aliases
|
||||
rpcServer.AliasMethod("eth_accounts", "Filecoin.EthAccounts")
|
||||
rpcServer.AliasMethod("eth_blockNumber", "Filecoin.EthBlockNumber")
|
||||
rpcServer.AliasMethod("eth_getBlockTransactionCountByNumber", "Filecoin.EthGetBlockTransactionCountByNumber")
|
||||
rpcServer.AliasMethod("eth_getBlockTransactionCountByHash", "Filecoin.EthGetBlockTransactionCountByHash")
|
||||
|
||||
rpcServer.AliasMethod("eth_getBlockByHash", "Filecoin.EthGetBlockByHash")
|
||||
rpcServer.AliasMethod("eth_getBlockByNumber", "Filecoin.EthGetBlockByNumber")
|
||||
rpcServer.AliasMethod("eth_getTransactionByHash", "Filecoin.EthGetTransactionByHash")
|
||||
rpcServer.AliasMethod("eth_getTransactionCount", "Filecoin.EthGetTransactionCount")
|
||||
rpcServer.AliasMethod("eth_getTransactionReceipt", "Filecoin.EthGetTransactionReceipt")
|
||||
rpcServer.AliasMethod("eth_getTransactionByBlockHashAndIndex", "Filecoin.EthGetTransactionByBlockHashAndIndex")
|
||||
rpcServer.AliasMethod("eth_getTransactionByBlockNumberAndIndex", "Filecoin.EthGetTransactionByBlockNumberAndIndex")
|
||||
|
||||
rpcServer.AliasMethod("eth_getCode", "Filecoin.EthGetCode")
|
||||
rpcServer.AliasMethod("eth_getStorageAt", "Filecoin.EthGetStorageAt")
|
||||
rpcServer.AliasMethod("eth_getBalance", "Filecoin.EthGetBalance")
|
||||
rpcServer.AliasMethod("eth_chainId", "Filecoin.EthChainId")
|
||||
rpcServer.AliasMethod("eth_feeHistory", "Filecoin.EthFeeHistory")
|
||||
rpcServer.AliasMethod("eth_protocolVersion", "Filecoin.EthProtocolVersion")
|
||||
rpcServer.AliasMethod("eth_maxPriorityFeePerGas", "Filecoin.EthMaxPriorityFeePerGas")
|
||||
rpcServer.AliasMethod("eth_gasPrice", "Filecoin.EthGasPrice")
|
||||
rpcServer.AliasMethod("eth_sendRawTransaction", "Filecoin.EthSendRawTransaction")
|
||||
rpcServer.AliasMethod("eth_estimateGas", "Filecoin.EthEstimateGas")
|
||||
rpcServer.AliasMethod("eth_call", "Filecoin.EthCall")
|
||||
|
||||
rpcServer.AliasMethod("eth_getLogs", "Filecoin.EthGetLogs")
|
||||
rpcServer.AliasMethod("eth_getFilterChanges", "Filecoin.EthGetFilterChanges")
|
||||
rpcServer.AliasMethod("eth_getFilterLogs", "Filecoin.EthGetFilterLogs")
|
||||
rpcServer.AliasMethod("eth_newFilter", "Filecoin.EthNewFilter")
|
||||
rpcServer.AliasMethod("eth_newBlockFilter", "Filecoin.EthNewBlockFilter")
|
||||
rpcServer.AliasMethod("eth_newPendingTransactionFilter", "Filecoin.EthNewPendingTransactionFilter")
|
||||
rpcServer.AliasMethod("eth_uninstallFilter", "Filecoin.EthUninstallFilter")
|
||||
rpcServer.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe")
|
||||
rpcServer.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe")
|
||||
|
||||
rpcServer.AliasMethod("net_version", "Filecoin.NetVersion")
|
||||
rpcServer.AliasMethod("net_listening", "Filecoin.NetListening")
|
||||
|
||||
var handler http.Handler = rpcServer
|
||||
if permissioned {
|
||||
handler = &auth.Handler{Verify: a.AuthVerify, Next: rpcServer.ServeHTTP}
|
||||
|
||||
Reference in New Issue
Block a user