Merge branch 'master' into adlrocha/consistent-bcast
This commit is contained in:
+7
-1
@@ -24,12 +24,14 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/index"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/journal/alerting"
|
||||
"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"
|
||||
@@ -66,9 +68,10 @@ var (
|
||||
ConnectionManagerKey = special{9} // Libp2p option
|
||||
AutoNATSvcKey = special{10} // Libp2p option
|
||||
BandwidthReporterKey = special{11} // Libp2p option
|
||||
ConnGaterKey = special{12} // libp2p option
|
||||
ConnGaterKey = special{12} // Libp2p option
|
||||
DAGStoreKey = special{13} // constructor returns multiple values
|
||||
ResourceManagerKey = special{14} // Libp2p option
|
||||
UserAgentKey = special{15} // Libp2p option
|
||||
)
|
||||
|
||||
type invoke int
|
||||
@@ -125,6 +128,8 @@ const (
|
||||
|
||||
SetApiEndpointKey
|
||||
|
||||
StoreEventsKey
|
||||
|
||||
_nInvokes // keep this last
|
||||
)
|
||||
|
||||
@@ -386,6 +391,7 @@ func Test() Option {
|
||||
Unset(new(*peermgr.PeerMgr)),
|
||||
Override(new(beacon.Schedule), testing.RandomBeacon),
|
||||
Override(new(*storageadapter.DealPublisher), storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{})),
|
||||
Override(new(index.MsgIndex), modules.DummyMsgIndex),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+30
-1
@@ -17,8 +17,10 @@ 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/index"
|
||||
"github.com/filecoin-project/lotus/chain/market"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/messagesigner"
|
||||
@@ -75,7 +77,7 @@ var ChainNode = Options(
|
||||
// Consensus: Chain storage/access
|
||||
Override(new(chain.Genesis), chain.LoadGenesis),
|
||||
Override(new(store.WeightFunc), filcns.Weight),
|
||||
Override(new(stmgr.Executor), filcns.NewTipSetExecutor()),
|
||||
Override(new(stmgr.Executor), consensus.NewTipSetExecutor(filcns.RewardFunc)),
|
||||
Override(new(consensus.Consensus), filcns.NewFilecoinExpectedConsensus),
|
||||
Override(new(*store.ChainStore), modules.ChainStore),
|
||||
Override(new(*stmgr.StateManager), modules.StateManager),
|
||||
@@ -151,6 +153,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),
|
||||
Override(new(full.EthModuleAPI), From(new(api.Gateway))),
|
||||
Override(new(full.EthEventAPI), From(new(api.Gateway))),
|
||||
),
|
||||
|
||||
// Full node API / service startup
|
||||
@@ -216,6 +220,11 @@ func ConfigFullNode(c interface{}) Option {
|
||||
Override(SetupFallbackBlockstoresKey, modules.InitFallbackBlockstores),
|
||||
),
|
||||
|
||||
// If the Eth JSON-RPC is enabled, enable storing events at the ChainStore.
|
||||
// This is the case even if real-time and historic filtering are disabled,
|
||||
// as it enables us to serve logs in eth_getTransactionReceipt.
|
||||
If(cfg.Fevm.EnableEthRPC, Override(StoreEventsKey, modules.EnableStoringEvents)),
|
||||
|
||||
Override(new(dtypes.ClientImportMgr), modules.ClientImportMgr),
|
||||
|
||||
Override(new(dtypes.ClientBlockstore), modules.ClientBlockstore),
|
||||
@@ -241,6 +250,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 +261,25 @@ 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))),
|
||||
|
||||
// in lite-mode Eth api is provided by gateway
|
||||
ApplyIf(isFullNode,
|
||||
If(cfg.Fevm.EnableEthRPC,
|
||||
Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)),
|
||||
Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.Fevm)),
|
||||
),
|
||||
If(!cfg.Fevm.EnableEthRPC,
|
||||
Override(new(full.EthModuleAPI), &full.EthModuleDummy{}),
|
||||
Override(new(full.EthEventAPI), &full.EthModuleDummy{}),
|
||||
),
|
||||
),
|
||||
|
||||
// enable message index for full node when configured by the user, otherwise use dummy.
|
||||
If(cfg.Index.EnableMsgIndex, Override(new(index.MsgIndex), modules.MsgIndex)),
|
||||
If(!cfg.Index.EnableMsgIndex, Override(new(index.MsgIndex), modules.DummyMsgIndex)),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
provider "github.com/ipni/index-provider"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -12,7 +13,6 @@ import (
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket/impl/storedask"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
provider "github.com/filecoin-project/index-provider"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/v1api"
|
||||
|
||||
+26
-9
@@ -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 {
|
||||
@@ -88,16 +89,30 @@ func DefaultFullNode() *FullNode {
|
||||
SimultaneousTransfersForRetrieval: DefaultSimultaneousTransfers,
|
||||
},
|
||||
Chainstore: Chainstore{
|
||||
EnableSplitstore: false,
|
||||
EnableSplitstore: true,
|
||||
Splitstore: Splitstore{
|
||||
ColdStoreType: "messages",
|
||||
ColdStoreType: "discard",
|
||||
HotStoreType: "badger",
|
||||
MarkSetType: "badger",
|
||||
|
||||
HotStoreFullGCFrequency: 20,
|
||||
HotStoreFullGCFrequency: 20,
|
||||
HotStoreMaxSpaceThreshold: 150_000_000_000,
|
||||
HotstoreMaxSpaceSafetyBuffer: 50_000_000_000,
|
||||
},
|
||||
},
|
||||
Cluster: *DefaultUserRaftConfig(),
|
||||
Fevm: FevmConfig{
|
||||
EnableEthRPC: false,
|
||||
EthTxHashMappingLifetimeDays: 0,
|
||||
Events: Events{
|
||||
DisableRealTimeFilterAPI: false,
|
||||
DisableHistoricFilterAPI: false,
|
||||
FilterTTL: Duration(time.Hour * 24),
|
||||
MaxFilters: 100,
|
||||
MaxFilterResults: 10000,
|
||||
MaxFilterHeightRange: 2880, // conservative limit of one day
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +156,7 @@ func DefaultStorageMiner() *StorageMiner {
|
||||
},
|
||||
|
||||
Proving: ProvingConfig{
|
||||
ParallelCheckLimit: 128,
|
||||
ParallelCheckLimit: 32,
|
||||
PartitionCheckTimeout: Duration(20 * time.Minute),
|
||||
SingleCheckTimeout: Duration(10 * time.Minute),
|
||||
},
|
||||
@@ -255,8 +270,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
|
||||
|
||||
@@ -341,6 +341,59 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
|
||||
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{
|
||||
{
|
||||
Name: "DefaultMaxFee",
|
||||
@@ -349,6 +402,28 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
|
||||
Comment: ``,
|
||||
},
|
||||
},
|
||||
"FevmConfig": []DocField{
|
||||
{
|
||||
Name: "EnableEthRPC",
|
||||
Type: "bool",
|
||||
|
||||
Comment: `EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
|
||||
This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`,
|
||||
},
|
||||
{
|
||||
Name: "EthTxHashMappingLifetimeDays",
|
||||
Type: "int",
|
||||
|
||||
Comment: `EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||
Set to 0 to keep all mappings`,
|
||||
},
|
||||
{
|
||||
Name: "Events",
|
||||
Type: "Events",
|
||||
|
||||
Comment: ``,
|
||||
},
|
||||
},
|
||||
"FullNode": []DocField{
|
||||
{
|
||||
Name: "Client",
|
||||
@@ -380,6 +455,26 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
|
||||
|
||||
Comment: ``,
|
||||
},
|
||||
{
|
||||
Name: "Fevm",
|
||||
Type: "FevmConfig",
|
||||
|
||||
Comment: ``,
|
||||
},
|
||||
{
|
||||
Name: "Index",
|
||||
Type: "IndexConfig",
|
||||
|
||||
Comment: ``,
|
||||
},
|
||||
},
|
||||
"IndexConfig": []DocField{
|
||||
{
|
||||
Name: "EnableMsgIndex",
|
||||
Type: "bool",
|
||||
|
||||
Comment: `EnableMsgIndex enables indexing of messages on chain.`,
|
||||
},
|
||||
},
|
||||
"IndexProviderConfig": []DocField{
|
||||
{
|
||||
@@ -1205,6 +1300,35 @@ the compaction boundary; default is 0.`,
|
||||
A value of 0 disables, while a value 1 will do full GC in every compaction.
|
||||
Default is 20 (about once a week).`,
|
||||
},
|
||||
{
|
||||
Name: "HotStoreMaxSpaceTarget",
|
||||
Type: "uint64",
|
||||
|
||||
Comment: `HotStoreMaxSpaceTarget sets a target max disk size for the hotstore. Splitstore GC
|
||||
will run moving GC if disk utilization gets within a threshold (150 GB) of the target.
|
||||
Splitstore GC will NOT run moving GC if the total size of the move would get
|
||||
within 50 GB of the target, and instead will run a more aggressive online GC.
|
||||
If both HotStoreFullGCFrequency and HotStoreMaxSpaceTarget are set then splitstore
|
||||
GC will trigger moving GC if either configuration condition is met.
|
||||
A reasonable minimum is 2x fully GCed hotstore size + 50 G buffer.
|
||||
At this minimum size moving GC happens every time, any smaller and moving GC won't
|
||||
be able to run. In spring 2023 this minimum is ~550 GB.`,
|
||||
},
|
||||
{
|
||||
Name: "HotStoreMaxSpaceThreshold",
|
||||
Type: "uint64",
|
||||
|
||||
Comment: `When HotStoreMaxSpaceTarget is set Moving GC will be triggered when total moving size
|
||||
exceeds HotstoreMaxSpaceTarget - HotstoreMaxSpaceThreshold`,
|
||||
},
|
||||
{
|
||||
Name: "HotstoreMaxSpaceSafetyBuffer",
|
||||
Type: "uint64",
|
||||
|
||||
Comment: `Safety buffer to prevent moving GC from overflowing disk when HotStoreMaxSpaceTarget
|
||||
is set. Moving GC will not occur when total moving size exceeds
|
||||
HotstoreMaxSpaceTarget - HotstoreMaxSpaceSafetyBuffer`,
|
||||
},
|
||||
},
|
||||
"StorageMiner": []DocField{
|
||||
{
|
||||
|
||||
+122
-9
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
@@ -17,17 +18,46 @@ import (
|
||||
|
||||
// FromFile loads config from a specified file overriding defaults specified in
|
||||
// the def parameter. If file does not exist or is empty defaults are assumed.
|
||||
func FromFile(path string, def interface{}) (interface{}, error) {
|
||||
func FromFile(path string, opts ...LoadCfgOpt) (interface{}, error) {
|
||||
var loadOpts cfgLoadOpts
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
if err = opt(&loadOpts); err != nil {
|
||||
return nil, xerrors.Errorf("failed to apply load cfg option: %w", err)
|
||||
}
|
||||
}
|
||||
var def interface{}
|
||||
if loadOpts.defaultCfg != nil {
|
||||
def, err = loadOpts.defaultCfg()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("no config found")
|
||||
}
|
||||
}
|
||||
// check for loadability
|
||||
file, err := os.Open(path)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
if loadOpts.canFallbackOnDefault != nil {
|
||||
if err := loadOpts.canFallbackOnDefault(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return def, nil
|
||||
case err != nil:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer file.Close() //nolint:errcheck // The file is RO
|
||||
return FromReader(file, def)
|
||||
defer file.Close() //nolint:errcheck,staticcheck // The file is RO
|
||||
cfgBs, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to read config for validation checks %w", err)
|
||||
}
|
||||
buf := bytes.NewBuffer(cfgBs)
|
||||
if loadOpts.validate != nil {
|
||||
if err := loadOpts.validate(buf.String()); err != nil {
|
||||
return nil, xerrors.Errorf("config failed validation: %w", err)
|
||||
}
|
||||
}
|
||||
return FromReader(buf, def)
|
||||
}
|
||||
|
||||
// FromReader loads config from a reader instance.
|
||||
@@ -46,7 +76,88 @@ func FromReader(reader io.Reader, def interface{}) (interface{}, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func ConfigUpdate(cfgCur, cfgDef interface{}, comment bool) ([]byte, error) {
|
||||
type cfgLoadOpts struct {
|
||||
defaultCfg func() (interface{}, error)
|
||||
canFallbackOnDefault func() error
|
||||
validate func(string) error
|
||||
}
|
||||
|
||||
type LoadCfgOpt func(opts *cfgLoadOpts) error
|
||||
|
||||
func SetDefault(f func() (interface{}, error)) LoadCfgOpt {
|
||||
return func(opts *cfgLoadOpts) error {
|
||||
opts.defaultCfg = f
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetCanFallbackOnDefault(f func() error) LoadCfgOpt {
|
||||
return func(opts *cfgLoadOpts) error {
|
||||
opts.canFallbackOnDefault = f
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetValidate(f func(string) error) LoadCfgOpt {
|
||||
return func(opts *cfgLoadOpts) error {
|
||||
opts.validate = f
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func NoDefaultForSplitstoreTransition() error {
|
||||
return xerrors.Errorf("FullNode config not found and fallback to default disallowed while we transition to splitstore discard default. Use `lotus config default` to set this repo up with a default config. Be sure to set `EnableSplitstore` to `false` if you are running a full archive node")
|
||||
}
|
||||
|
||||
// Match the EnableSplitstore field
|
||||
func MatchEnableSplitstoreField(s string) bool {
|
||||
enableSplitstoreRx := regexp.MustCompile(`(?m)^\s*EnableSplitstore\s*=`)
|
||||
return enableSplitstoreRx.MatchString(s)
|
||||
}
|
||||
|
||||
func ValidateSplitstoreSet(cfgRaw string) error {
|
||||
if !MatchEnableSplitstoreField(cfgRaw) {
|
||||
return xerrors.Errorf("Config does not contain explicit set of EnableSplitstore field, refusing to load. Please explicitly set EnableSplitstore. Set it to false if you are running a full archival node")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type cfgUpdateOpts struct {
|
||||
comment bool
|
||||
keepUncommented func(string) bool
|
||||
}
|
||||
|
||||
// UpdateCfgOpt is a functional option for updating the config
|
||||
type UpdateCfgOpt func(opts *cfgUpdateOpts) error
|
||||
|
||||
// KeepUncommented sets a function for matching default valeus that should remain uncommented during
|
||||
// a config update that comments out default values.
|
||||
func KeepUncommented(f func(string) bool) UpdateCfgOpt {
|
||||
return func(opts *cfgUpdateOpts) error {
|
||||
opts.keepUncommented = f
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Commented(commented bool) UpdateCfgOpt {
|
||||
return func(opts *cfgUpdateOpts) error {
|
||||
opts.comment = commented
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultKeepUncommented() UpdateCfgOpt {
|
||||
return KeepUncommented(MatchEnableSplitstoreField)
|
||||
}
|
||||
|
||||
// ConfigUpdate takes in a config and a default config and optionally comments out default values
|
||||
func ConfigUpdate(cfgCur, cfgDef interface{}, opts ...UpdateCfgOpt) ([]byte, error) {
|
||||
var updateOpts cfgUpdateOpts
|
||||
for _, opt := range opts {
|
||||
if err := opt(&updateOpts); err != nil {
|
||||
return nil, xerrors.Errorf("failed to apply update cfg option to ConfigUpdate's config: %w", err)
|
||||
}
|
||||
}
|
||||
var nodeStr, defStr string
|
||||
if cfgDef != nil {
|
||||
buf := new(bytes.Buffer)
|
||||
@@ -68,7 +179,7 @@ func ConfigUpdate(cfgCur, cfgDef interface{}, comment bool) ([]byte, error) {
|
||||
nodeStr = buf.String()
|
||||
}
|
||||
|
||||
if comment {
|
||||
if updateOpts.comment {
|
||||
// create a map of default lines, so we can comment those out later
|
||||
defLines := strings.Split(defStr, "\n")
|
||||
defaults := map[string]struct{}{}
|
||||
@@ -130,8 +241,10 @@ func ConfigUpdate(cfgCur, cfgDef interface{}, comment bool) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// if there is the same line in the default config, comment it out it output
|
||||
if _, found := defaults[strings.TrimSpace(nodeLines[i])]; (cfgDef == nil || found) && len(line) > 0 {
|
||||
// filter lines from options
|
||||
optsFilter := updateOpts.keepUncommented != nil && updateOpts.keepUncommented(line)
|
||||
// if there is the same line in the default config, comment it out in output
|
||||
if _, found := defaults[strings.TrimSpace(nodeLines[i])]; (cfgDef == nil || found) && len(line) > 0 && !optsFilter {
|
||||
line = pad + "#" + line[len(pad):]
|
||||
}
|
||||
outLines = append(outLines, line)
|
||||
@@ -159,5 +272,5 @@ func ConfigUpdate(cfgCur, cfgDef interface{}, comment bool) ([]byte, error) {
|
||||
}
|
||||
|
||||
func ConfigComment(t interface{}) ([]byte, error) {
|
||||
return ConfigUpdate(t, nil, true)
|
||||
return ConfigUpdate(t, nil, Commented(true), DefaultKeepUncommented())
|
||||
}
|
||||
|
||||
@@ -11,19 +11,21 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func fullNodeDefault() (interface{}, error) { return DefaultFullNode(), nil }
|
||||
|
||||
func TestDecodeNothing(t *testing.T) {
|
||||
//stm: @NODE_CONFIG_LOAD_FILE_002
|
||||
assert := assert.New(t)
|
||||
|
||||
{
|
||||
cfg, err := FromFile(os.DevNull, DefaultFullNode())
|
||||
cfg, err := FromFile(os.DevNull, SetDefault(fullNodeDefault))
|
||||
assert.Nil(err, "error should be nil")
|
||||
assert.Equal(DefaultFullNode(), cfg,
|
||||
"config from empty file should be the same as default")
|
||||
}
|
||||
|
||||
{
|
||||
cfg, err := FromFile("./does-not-exist.toml", DefaultFullNode())
|
||||
cfg, err := FromFile("./does-not-exist.toml", SetDefault(fullNodeDefault))
|
||||
assert.Nil(err, "error should be nil")
|
||||
assert.Equal(DefaultFullNode(), cfg,
|
||||
"config from not exisiting file should be the same as default")
|
||||
@@ -58,9 +60,82 @@ func TestParitalConfig(t *testing.T) {
|
||||
assert.NoError(err, "closing tmp file should not error")
|
||||
defer os.Remove(fname) //nolint:errcheck
|
||||
|
||||
cfg, err := FromFile(fname, DefaultFullNode())
|
||||
cfg, err := FromFile(fname, SetDefault(fullNodeDefault))
|
||||
assert.Nil(err, "error should be nil")
|
||||
assert.Equal(expected, cfg,
|
||||
"config from reader should contain changes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSplitstoreSet(t *testing.T) {
|
||||
cfgSet := `
|
||||
EnableSplitstore = false
|
||||
`
|
||||
assert.NoError(t, ValidateSplitstoreSet(cfgSet))
|
||||
cfgSloppySet := `
|
||||
EnableSplitstore = true
|
||||
`
|
||||
assert.NoError(t, ValidateSplitstoreSet(cfgSloppySet))
|
||||
|
||||
// Missing altogether
|
||||
cfgMissing := `
|
||||
[Chainstore]
|
||||
# type: bool
|
||||
# env var: LOTUS_CHAINSTORE_ENABLESPLITSTORE
|
||||
# oops its mising
|
||||
|
||||
[Chainstore.Splitstore]
|
||||
ColdStoreType = "discard"
|
||||
`
|
||||
err := ValidateSplitstoreSet(cfgMissing)
|
||||
assert.Error(t, err)
|
||||
cfgCommentedOut := `
|
||||
# EnableSplitstore = false
|
||||
`
|
||||
err = ValidateSplitstoreSet(cfgCommentedOut)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// Default config keeps EnableSplitstore field uncommented
|
||||
func TestKeepEnableSplitstoreUncommented(t *testing.T) {
|
||||
cfgStr, err := ConfigComment(DefaultFullNode())
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, MatchEnableSplitstoreField(string(cfgStr)))
|
||||
|
||||
cfgStrFromDef, err := ConfigUpdate(DefaultFullNode(), DefaultFullNode(), Commented(true), DefaultKeepUncommented())
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, MatchEnableSplitstoreField(string(cfgStrFromDef)))
|
||||
}
|
||||
|
||||
// Loading a config with commented EnableSplitstore fails when setting validator
|
||||
func TestValidateConfigSetsEnableSplitstore(t *testing.T) {
|
||||
cfgCommentedOutEnableSS, err := ConfigUpdate(DefaultFullNode(), DefaultFullNode(), Commented(true))
|
||||
assert.NoError(t, err)
|
||||
// assert that this config comments out EnableSplitstore
|
||||
assert.False(t, MatchEnableSplitstoreField(string(cfgCommentedOutEnableSS)))
|
||||
|
||||
// write config with commented out EnableSplitstore to file
|
||||
f, err := ioutil.TempFile("", "config.toml")
|
||||
fname := f.Name()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
err = f.Close()
|
||||
assert.NoError(t, err)
|
||||
os.Remove(fname) //nolint:errcheck
|
||||
}()
|
||||
_, err = f.WriteString(string(cfgCommentedOutEnableSS))
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = FromFile(fname, SetDefault(fullNodeDefault), SetValidate(ValidateSplitstoreSet))
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// Loading without a config file and a default fails if the default fallback is disabled
|
||||
func TestFailToFallbackToDefault(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "dirWithNoFiles")
|
||||
assert.NoError(t, err)
|
||||
defer assert.NoError(t, os.RemoveAll(dir))
|
||||
nonExistantFileName := dir + "/notarealfile"
|
||||
_, err = FromFile(nonExistantFileName, SetDefault(fullNodeDefault), SetCanFallbackOnDefault(NoDefaultForSplitstoreTransition))
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
+75
-1
@@ -27,6 +27,8 @@ type FullNode struct {
|
||||
Fees FeeConfig
|
||||
Chainstore Chainstore
|
||||
Cluster UserRaftConfig
|
||||
Fevm FevmConfig
|
||||
Index IndexConfig
|
||||
}
|
||||
|
||||
// // Common
|
||||
@@ -168,7 +170,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
|
||||
@@ -601,6 +602,25 @@ type Splitstore struct {
|
||||
// A value of 0 disables, while a value 1 will do full GC in every compaction.
|
||||
// Default is 20 (about once a week).
|
||||
HotStoreFullGCFrequency uint64
|
||||
// HotStoreMaxSpaceTarget sets a target max disk size for the hotstore. Splitstore GC
|
||||
// will run moving GC if disk utilization gets within a threshold (150 GB) of the target.
|
||||
// Splitstore GC will NOT run moving GC if the total size of the move would get
|
||||
// within 50 GB of the target, and instead will run a more aggressive online GC.
|
||||
// If both HotStoreFullGCFrequency and HotStoreMaxSpaceTarget are set then splitstore
|
||||
// GC will trigger moving GC if either configuration condition is met.
|
||||
// A reasonable minimum is 2x fully GCed hotstore size + 50 G buffer.
|
||||
// At this minimum size moving GC happens every time, any smaller and moving GC won't
|
||||
// be able to run. In spring 2023 this minimum is ~550 GB.
|
||||
HotStoreMaxSpaceTarget uint64
|
||||
|
||||
// When HotStoreMaxSpaceTarget is set Moving GC will be triggered when total moving size
|
||||
// exceeds HotstoreMaxSpaceTarget - HotstoreMaxSpaceThreshold
|
||||
HotStoreMaxSpaceThreshold uint64
|
||||
|
||||
// Safety buffer to prevent moving GC from overflowing disk when HotStoreMaxSpaceTarget
|
||||
// is set. Moving GC will not occur when total moving size exceeds
|
||||
// HotstoreMaxSpaceTarget - HotstoreMaxSpaceSafetyBuffer
|
||||
HotstoreMaxSpaceSafetyBuffer uint64
|
||||
}
|
||||
|
||||
// // Full Node
|
||||
@@ -658,3 +678,57 @@ type UserRaftConfig struct {
|
||||
// Tracing enables propagation of contexts across binary boundaries.
|
||||
Tracing bool
|
||||
}
|
||||
|
||||
type FevmConfig struct {
|
||||
// EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
|
||||
// This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
|
||||
EnableEthRPC bool
|
||||
|
||||
// EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||
// Set to 0 to keep all mappings
|
||||
EthTxHashMappingLifetimeDays int
|
||||
|
||||
Events 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
|
||||
// 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
|
||||
|
||||
// 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).
|
||||
DatabasePath string
|
||||
|
||||
// Others, not implemented yet:
|
||||
// Set a limit on the number of active websocket subscriptions (may be zero)
|
||||
// Set a timeout for subscription clients
|
||||
// Set upper bound on index size
|
||||
}
|
||||
|
||||
type IndexConfig struct {
|
||||
// EnableMsgIndex enables indexing of messages on chain.
|
||||
EnableMsgIndex bool
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ func (t *HelloMessage) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
return fmt.Errorf("int64 negative overflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
@@ -250,7 +250,7 @@ func (t *LatencyMessage) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
return fmt.Errorf("int64 negative overflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
@@ -275,7 +275,7 @@ func (t *LatencyMessage) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
return fmt.Errorf("int64 negative overflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
|
||||
@@ -158,6 +158,9 @@ func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error {
|
||||
if err := cborutil.WriteCborRPC(s, hmsg); err != nil {
|
||||
return xerrors.Errorf("writing rpc to peer: %w", err)
|
||||
}
|
||||
if err := s.CloseWrite(); err != nil {
|
||||
log.Warnw("CloseWrite err", "error", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer s.Close() //nolint:errcheck
|
||||
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
format "github.com/ipfs/go-ipld-format"
|
||||
"github.com/ipfs/go-libipfs/files"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/ipfs/go-merkledag"
|
||||
unixfile "github.com/ipfs/go-unixfs/file"
|
||||
@@ -44,7 +44,7 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/go-commp-utils/writer"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer/v2"
|
||||
"github.com/filecoin-project/go-fil-markets/discovery"
|
||||
rm "github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
@@ -1302,8 +1302,8 @@ func (a *API) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Addre
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range ps {
|
||||
if strings.HasPrefix(s, dealProtoPrefix) {
|
||||
res.DealProtocols = append(res.DealProtocols, s)
|
||||
if strings.HasPrefix(string(s), dealProtoPrefix) {
|
||||
res.DealProtocols = append(res.DealProtocols, string(s))
|
||||
}
|
||||
}
|
||||
sort.Strings(res.DealProtocols)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
"github.com/ipfs/go-libipfs/files"
|
||||
"github.com/ipfs/go-merkledag"
|
||||
unixfile "github.com/ipfs/go-unixfs/file"
|
||||
"github.com/ipld/go-car"
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
var testdata embed.FS
|
||||
|
||||
func TestImportLocal(t *testing.T) {
|
||||
//stm: @CLIENT_STORAGE_DEALS_IMPORT_LOCAL_001, @CLIENT_RETRIEVAL_FIND_001
|
||||
// stm: @CLIENT_STORAGE_DEALS_IMPORT_LOCAL_001, @CLIENT_RETRIEVAL_FIND_001
|
||||
ds := dssync.MutexWrap(datastore.NewMapDatastore())
|
||||
dir := t.TempDir()
|
||||
im := imports.NewManager(ds, dir)
|
||||
@@ -46,7 +46,7 @@ func TestImportLocal(t *testing.T) {
|
||||
b, err := testdata.ReadFile("testdata/payload.txt")
|
||||
require.NoError(t, err)
|
||||
|
||||
//stm: @CLIENT_STORAGE_DEALS_LIST_IMPORTS_001
|
||||
// stm: @CLIENT_STORAGE_DEALS_LIST_IMPORTS_001
|
||||
root, err := a.ClientImportLocal(ctx, bytes.NewReader(b))
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, cid.Undef, root)
|
||||
@@ -59,7 +59,7 @@ func TestImportLocal(t *testing.T) {
|
||||
require.Equal(t, root, *it.Root)
|
||||
require.True(t, strings.HasPrefix(it.CARPath, dir))
|
||||
|
||||
//stm: @CLIENT_DATA_HAS_LOCAL_001
|
||||
// stm: @CLIENT_DATA_HAS_LOCAL_001
|
||||
local, err := a.ClientHasLocal(ctx, root)
|
||||
require.NoError(t, err)
|
||||
require.True(t, local)
|
||||
|
||||
@@ -35,6 +35,7 @@ type FullNodeAPI struct {
|
||||
full.WalletAPI
|
||||
full.SyncAPI
|
||||
full.RaftAPI
|
||||
full.EthAPI
|
||||
|
||||
DS dtypes.MetadataDS
|
||||
NetworkName dtypes.NetworkName
|
||||
|
||||
+100
-16
@@ -5,17 +5,22 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-cid"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
blocks "github.com/ipfs/go-libipfs/blocks"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/ipfs/go-merkledag"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
@@ -24,6 +29,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"
|
||||
|
||||
@@ -36,6 +42,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/oldpath"
|
||||
"github.com/filecoin-project/lotus/lib/oldpath/oldresolver"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
var log = logging.Logger("fullnode")
|
||||
@@ -87,6 +94,8 @@ type ChainAPI struct {
|
||||
|
||||
// BaseBlockstore is the underlying blockstore
|
||||
BaseBlockstore dtypes.BaseBlockstore
|
||||
|
||||
Repo repo.LockedRepo
|
||||
}
|
||||
|
||||
func (m *ChainModule) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) {
|
||||
@@ -184,25 +193,14 @@ func (a *ChainAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Cid) ([]
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TODO: need to get the number of messages better than this
|
||||
pts, err := a.Chain.LoadTipSet(ctx, types.NewTipSetKey(b.Parents...))
|
||||
receipts, err := a.Chain.ReadReceipts(ctx, b.ParentMessageReceipts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cm, err := a.Chain.MessagesForTipset(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []*types.MessageReceipt
|
||||
for i := 0; i < len(cm); i++ {
|
||||
r, err := a.Chain.GetParentReceipt(ctx, b, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, r)
|
||||
out := make([]*types.MessageReceipt, len(receipts))
|
||||
for i := range receipts {
|
||||
out[i] = &receipts[i]
|
||||
}
|
||||
|
||||
return out, nil
|
||||
@@ -587,6 +585,54 @@ func (m *ChainModule) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.M
|
||||
return cm.VMMessage(), nil
|
||||
}
|
||||
|
||||
func (a ChainAPI) ChainExportRangeInternal(ctx context.Context, head, tail types.TipSetKey, cfg api.ChainExportConfig) error {
|
||||
headTs, err := a.Chain.GetTipSetFromKey(ctx, head)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset %s: %w", head, err)
|
||||
}
|
||||
tailTs, err := a.Chain.GetTipSetFromKey(ctx, tail)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset %s: %w", tail, err)
|
||||
}
|
||||
if headTs.Height() < tailTs.Height() {
|
||||
return xerrors.Errorf("Height of head-tipset (%d) must be greater or equal to the height of the tail-tipset (%d)", headTs.Height(), tailTs.Height())
|
||||
}
|
||||
|
||||
fileName := filepath.Join(a.Repo.Path(), fmt.Sprintf("snapshot_%d_%d_%d.car", tailTs.Height(), headTs.Height(), time.Now().Unix()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infow("Exporting chain range", "path", fileName)
|
||||
// buffer writes to the chain export file.
|
||||
bw := bufio.NewWriterSize(f, cfg.WriteBufferSize)
|
||||
|
||||
defer func() {
|
||||
if err := bw.Flush(); err != nil {
|
||||
log.Errorw("failed to flush buffer", "error", err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Errorw("failed to close file", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := a.Chain.ExportRange(ctx,
|
||||
bw,
|
||||
headTs, tailTs,
|
||||
cfg.IncludeMessages, cfg.IncludeReceipts, cfg.IncludeStateRoots,
|
||||
cfg.NumWorkers,
|
||||
); err != nil {
|
||||
return fmt.Errorf("exporting chain range: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
ts, err := a.Chain.GetTipSetFromKey(ctx, tsk)
|
||||
if err != nil {
|
||||
@@ -654,6 +700,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
|
||||
@@ -664,3 +737,14 @@ func (a *ChainAPI) ChainPrune(ctx context.Context, opts api.PruneOpts) error {
|
||||
|
||||
return pruner.PruneChain(opts)
|
||||
}
|
||||
|
||||
func (a *ChainAPI) ChainHotGC(ctx context.Context, opts api.HotGCOpts) error {
|
||||
pruner, ok := a.BaseBlockstore.(interface {
|
||||
GCHotStore(api.HotGCOpts) error
|
||||
})
|
||||
if !ok {
|
||||
return xerrors.Errorf("base blockstore does not support hot GC (%T)", a.BaseBlockstore)
|
||||
}
|
||||
|
||||
return pruner.GCHotStore(opts)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
package full
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
)
|
||||
|
||||
var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthRPC / LOTUS_FEVM_ENABLEETHRPC")
|
||||
|
||||
type EthModuleDummy struct{}
|
||||
|
||||
func (e *EthModuleDummy) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) {
|
||||
return address.Undef, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) {
|
||||
return ethtypes.EthBlock{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) {
|
||||
return ethtypes.EthBlock{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return ethtypes.EthTx{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return ethtypes.EthTx{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) {
|
||||
return ethtypes.EthFeeHistory{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) {
|
||||
return "", ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) {
|
||||
return false, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) {
|
||||
return ethtypes.EthHash{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) Web3ClientVersion(ctx context.Context) (string, error) {
|
||||
return "", ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) {
|
||||
return ðtypes.EthFilterResult{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
return ðtypes.EthFilterResult{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
return ðtypes.EthFilterResult{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {
|
||||
return ethtypes.EthFilterID{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) {
|
||||
return ethtypes.EthFilterID{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) {
|
||||
return ethtypes.EthFilterID{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) {
|
||||
return false, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||
return ethtypes.EthSubscriptionID{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) {
|
||||
return false, ErrModuleDisabled
|
||||
}
|
||||
|
||||
var _ EthModuleAPI = &EthModuleDummy{}
|
||||
var _ EthEventAPI = &EthModuleDummy{}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
package full
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
)
|
||||
|
||||
func TestEthLogFromEvent(t *testing.T) {
|
||||
// basic empty
|
||||
data, topics, ok := ethLogFromEvent(nil)
|
||||
require.True(t, ok)
|
||||
require.Nil(t, data)
|
||||
require.Nil(t, topics)
|
||||
|
||||
// basic topic
|
||||
data, topics, ok = ethLogFromEvent([]types.EventEntry{{
|
||||
Flags: 0,
|
||||
Key: "t1",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}})
|
||||
require.True(t, ok)
|
||||
require.Nil(t, data)
|
||||
require.Len(t, topics, 1)
|
||||
require.Equal(t, topics[0], ethtypes.EthHash{})
|
||||
|
||||
// basic topic with data
|
||||
data, topics, ok = ethLogFromEvent([]types.EventEntry{{
|
||||
Flags: 0,
|
||||
Key: "t1",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}, {
|
||||
Flags: 0,
|
||||
Key: "d",
|
||||
Codec: cid.Raw,
|
||||
Value: []byte{0x0},
|
||||
}})
|
||||
require.True(t, ok)
|
||||
require.Equal(t, data, []byte{0x0})
|
||||
require.Len(t, topics, 1)
|
||||
require.Equal(t, topics[0], ethtypes.EthHash{})
|
||||
|
||||
// skip topic
|
||||
_, _, ok = ethLogFromEvent([]types.EventEntry{{
|
||||
Flags: 0,
|
||||
Key: "t2",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}})
|
||||
require.False(t, ok)
|
||||
|
||||
// duplicate topic
|
||||
_, _, ok = ethLogFromEvent([]types.EventEntry{{
|
||||
Flags: 0,
|
||||
Key: "t1",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}, {
|
||||
Flags: 0,
|
||||
Key: "t1",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}})
|
||||
require.False(t, ok)
|
||||
|
||||
// duplicate data
|
||||
_, _, ok = ethLogFromEvent([]types.EventEntry{{
|
||||
Flags: 0,
|
||||
Key: "d",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}, {
|
||||
Flags: 0,
|
||||
Key: "d",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}})
|
||||
require.False(t, ok)
|
||||
|
||||
// unknown key is fine
|
||||
data, topics, ok = ethLogFromEvent([]types.EventEntry{{
|
||||
Flags: 0,
|
||||
Key: "t5",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}, {
|
||||
Flags: 0,
|
||||
Key: "t1",
|
||||
Codec: cid.Raw,
|
||||
Value: make([]byte, 32),
|
||||
}})
|
||||
require.True(t, ok)
|
||||
require.Nil(t, data)
|
||||
require.Len(t, topics, 1)
|
||||
require.Equal(t, topics[0], ethtypes.EthHash{})
|
||||
}
|
||||
|
||||
func TestReward(t *testing.T) {
|
||||
baseFee := big.NewInt(100)
|
||||
testcases := []struct {
|
||||
maxFeePerGas, maxPriorityFeePerGas big.Int
|
||||
answer big.Int
|
||||
}{
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(200)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(300), answer: big.NewInt(300)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(500), answer: big.NewInt(500)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(600), answer: big.NewInt(500)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(1000), answer: big.NewInt(500)},
|
||||
{maxFeePerGas: big.NewInt(50), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(-50)},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
msg := &types.Message{GasFeeCap: tc.maxFeePerGas, GasPremium: tc.maxPriorityFeePerGas}
|
||||
reward := msg.EffectiveGasPremium(baseFee)
|
||||
require.Equal(t, 0, reward.Int.Cmp(tc.answer.Int), reward, tc.answer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewardPercentiles(t *testing.T) {
|
||||
testcases := []struct {
|
||||
percentiles []float64
|
||||
txGasRewards gasRewardSorter
|
||||
answer []int64
|
||||
}{
|
||||
{
|
||||
percentiles: []float64{25, 50, 75},
|
||||
txGasRewards: []gasRewardTuple{},
|
||||
answer: []int64{MinGasPremium, MinGasPremium, MinGasPremium},
|
||||
},
|
||||
{
|
||||
percentiles: []float64{25, 50, 75, 100},
|
||||
txGasRewards: []gasRewardTuple{
|
||||
{gasUsed: int64(0), premium: big.NewInt(300)},
|
||||
{gasUsed: int64(100), premium: big.NewInt(200)},
|
||||
{gasUsed: int64(350), premium: big.NewInt(100)},
|
||||
{gasUsed: int64(500), premium: big.NewInt(600)},
|
||||
{gasUsed: int64(300), premium: big.NewInt(700)},
|
||||
},
|
||||
answer: []int64{200, 700, 700, 700},
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
rewards, totalGasUsed := calculateRewardsAndGasUsed(tc.percentiles, tc.txGasRewards)
|
||||
var gasUsed int64
|
||||
for _, tx := range tc.txGasRewards {
|
||||
gasUsed += tx.gasUsed
|
||||
}
|
||||
ans := []ethtypes.EthBigInt{}
|
||||
for _, bi := range tc.answer {
|
||||
ans = append(ans, ethtypes.EthBigInt(big.NewInt(bi)))
|
||||
}
|
||||
require.Equal(t, totalGasUsed, gasUsed)
|
||||
require.Equal(t, len(ans), len(tc.percentiles))
|
||||
require.Equal(t, ans, rewards)
|
||||
}
|
||||
}
|
||||
+83
-58
@@ -4,9 +4,10 @@ import (
|
||||
"context"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
lru "github.com/hashicorp/golang-lru/v2"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -61,7 +62,7 @@ type GasAPI struct {
|
||||
|
||||
func NewGasPriceCache() *GasPriceCache {
|
||||
// 50 because we usually won't access more than 40
|
||||
c, err := lru.New2Q(50)
|
||||
c, err := lru.New2Q[types.TipSetKey, []GasMeta](50)
|
||||
if err != nil {
|
||||
// err only if parameter is bad
|
||||
panic(err)
|
||||
@@ -73,7 +74,7 @@ func NewGasPriceCache() *GasPriceCache {
|
||||
}
|
||||
|
||||
type GasPriceCache struct {
|
||||
c *lru.TwoQueueCache
|
||||
c *lru.TwoQueueCache[types.TipSetKey, []GasMeta]
|
||||
}
|
||||
|
||||
type GasMeta struct {
|
||||
@@ -84,7 +85,7 @@ type GasMeta struct {
|
||||
func (g *GasPriceCache) GetTSGasStats(ctx context.Context, cstore *store.ChainStore, ts *types.TipSet) ([]GasMeta, error) {
|
||||
i, has := g.c.Get(ts.Key())
|
||||
if has {
|
||||
return i.([]GasMeta), nil
|
||||
return i, nil
|
||||
}
|
||||
|
||||
var prices []GasMeta
|
||||
@@ -248,6 +249,58 @@ func (m *GasModule) GasEstimateGasLimit(ctx context.Context, msgIn *types.Messag
|
||||
}
|
||||
return gasEstimateGasLimit(ctx, m.Chain, m.Stmgr, m.Mpool, msgIn, ts)
|
||||
}
|
||||
|
||||
// gasEstimateCallWithGas invokes a message "msgIn" on the earliest available tipset with pending
|
||||
// messages in the message pool. The function returns the result of the message invocation, the
|
||||
// pending messages, the tipset used for the invocation, and an error if occurred.
|
||||
// The returned information can be used to make subsequent calls to CallWithGas with the same parameters.
|
||||
func gasEstimateCallWithGas(
|
||||
ctx context.Context,
|
||||
cstore *store.ChainStore,
|
||||
smgr *stmgr.StateManager,
|
||||
mpool *messagepool.MessagePool,
|
||||
msgIn *types.Message,
|
||||
currTs *types.TipSet,
|
||||
) (*api.InvocResult, []types.ChainMsg, *types.TipSet, error) {
|
||||
msg := *msgIn
|
||||
fromA, err := smgr.ResolveToDeterministicAddress(ctx, msgIn.From, currTs)
|
||||
if err != nil {
|
||||
return nil, []types.ChainMsg{}, nil, xerrors.Errorf("getting key address: %w", err)
|
||||
}
|
||||
|
||||
pending, ts := mpool.PendingFor(ctx, fromA)
|
||||
priorMsgs := make([]types.ChainMsg, 0, len(pending))
|
||||
for _, m := range pending {
|
||||
if m.Message.Nonce == msg.Nonce {
|
||||
break
|
||||
}
|
||||
priorMsgs = append(priorMsgs, m)
|
||||
}
|
||||
|
||||
applyTsMessages := true
|
||||
if os.Getenv("LOTUS_SKIP_APPLY_TS_MESSAGE_CALL_WITH_GAS") == "1" {
|
||||
applyTsMessages = false
|
||||
}
|
||||
|
||||
// Try calling until we find a height with no migration.
|
||||
var res *api.InvocResult
|
||||
for {
|
||||
res, err = smgr.CallWithGas(ctx, &msg, priorMsgs, ts, applyTsMessages)
|
||||
if err != stmgr.ErrExpensiveFork {
|
||||
break
|
||||
}
|
||||
ts, err = cstore.GetTipSetFromKey(ctx, ts.Parents())
|
||||
if err != nil {
|
||||
return nil, []types.ChainMsg{}, nil, xerrors.Errorf("getting parent tipset: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, []types.ChainMsg{}, nil, xerrors.Errorf("CallWithGas failed: %w", err)
|
||||
}
|
||||
|
||||
return res, priorMsgs, ts, nil
|
||||
}
|
||||
|
||||
func gasEstimateGasLimit(
|
||||
ctx context.Context,
|
||||
cstore *store.ChainStore,
|
||||
@@ -261,35 +314,11 @@ func gasEstimateGasLimit(
|
||||
msg.GasFeeCap = big.Zero()
|
||||
msg.GasPremium = big.Zero()
|
||||
|
||||
fromA, err := smgr.ResolveToKeyAddress(ctx, msgIn.From, currTs)
|
||||
res, _, ts, err := gasEstimateCallWithGas(ctx, cstore, smgr, mpool, &msg, currTs)
|
||||
if err != nil {
|
||||
return -1, xerrors.Errorf("getting key address: %w", err)
|
||||
return -1, xerrors.Errorf("gas estimation failed: %w", err)
|
||||
}
|
||||
|
||||
pending, ts := mpool.PendingFor(ctx, fromA)
|
||||
priorMsgs := make([]types.ChainMsg, 0, len(pending))
|
||||
for _, m := range pending {
|
||||
if m.Message.Nonce == msg.Nonce {
|
||||
break
|
||||
}
|
||||
priorMsgs = append(priorMsgs, m)
|
||||
}
|
||||
|
||||
// Try calling until we find a height with no migration.
|
||||
var res *api.InvocResult
|
||||
for {
|
||||
res, err = smgr.CallWithGas(ctx, &msg, priorMsgs, ts)
|
||||
if err != stmgr.ErrExpensiveFork {
|
||||
break
|
||||
}
|
||||
ts, err = cstore.GetTipSetFromKey(ctx, ts.Parents())
|
||||
if err != nil {
|
||||
return -1, xerrors.Errorf("getting parent tipset: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return -1, xerrors.Errorf("CallWithGas failed: %w", err)
|
||||
}
|
||||
if res.MsgRct.ExitCode == exitcode.SysErrOutOfGas {
|
||||
return -1, &api.ErrOutOfGas{}
|
||||
}
|
||||
@@ -300,12 +329,19 @@ func gasEstimateGasLimit(
|
||||
|
||||
ret := res.MsgRct.GasUsed
|
||||
|
||||
log.Infow("GasEstimateMessageGas CallWithGas Result", "GasUsed", ret, "ExitCode", res.MsgRct.ExitCode)
|
||||
|
||||
transitionalMulti := 1.0
|
||||
// Overestimate gas around the upgrade
|
||||
if ts.Height() <= build.UpgradeSkyrHeight && (build.UpgradeSkyrHeight-ts.Height() <= 20) {
|
||||
transitionalMulti = 2.0
|
||||
|
||||
if ts.Height() <= build.UpgradeHyggeHeight && (build.UpgradeHyggeHeight-ts.Height() <= 20) {
|
||||
func() {
|
||||
|
||||
// Bare transfers get about 3x more expensive: https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0057.md#product-considerations
|
||||
if msgIn.Method == builtin.MethodSend {
|
||||
transitionalMulti = 3.0
|
||||
return
|
||||
}
|
||||
|
||||
st, err := smgr.ParentState(ts)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -317,42 +353,31 @@ func gasEstimateGasLimit(
|
||||
|
||||
if lbuiltin.IsStorageMinerActor(act.Code) {
|
||||
switch msgIn.Method {
|
||||
case 5:
|
||||
transitionalMulti = 3.954
|
||||
case 3:
|
||||
transitionalMulti = 1.92
|
||||
case 4:
|
||||
transitionalMulti = 1.72
|
||||
case 6:
|
||||
transitionalMulti = 4.095
|
||||
transitionalMulti = 1.06
|
||||
case 7:
|
||||
// skip, stay at 2.0
|
||||
//transitionalMulti = 1.289
|
||||
case 11:
|
||||
transitionalMulti = 17.8758
|
||||
transitionalMulti = 1.2
|
||||
case 16:
|
||||
transitionalMulti = 2.1704
|
||||
case 25:
|
||||
transitionalMulti = 3.1177
|
||||
transitionalMulti = 1.19
|
||||
case 18:
|
||||
transitionalMulti = 1.73
|
||||
case 23:
|
||||
transitionalMulti = 1.73
|
||||
case 26:
|
||||
transitionalMulti = 2.3322
|
||||
transitionalMulti = 1.15
|
||||
case 27:
|
||||
transitionalMulti = 1.18
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// skip storage market, 80th percentie for everything ~1.9, leave it at 2.0
|
||||
}()
|
||||
}
|
||||
ret = (ret * int64(transitionalMulti*1024)) >> 10
|
||||
|
||||
// Special case for PaymentChannel collect, which is deleting actor
|
||||
// We ignore errors in this special case since they CAN occur,
|
||||
// and we just want to detect existing payment channel actors
|
||||
st, err := smgr.ParentState(ts)
|
||||
if err == nil {
|
||||
act, err := st.GetActor(msg.To)
|
||||
if err == nil && lbuiltin.IsPaymentChannelActor(act.Code) && msgIn.Method == builtin.MethodsPaych.Collect {
|
||||
// add the refunded gas for DestroyActor back into the gas used
|
||||
ret += 76e3
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/messagesigner"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
@@ -36,7 +37,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,17 +47,21 @@ 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)
|
||||
}
|
||||
|
||||
sb, err := messagesigner.SigningBytes(msg, keyAddr.Protocol())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mb, err := msg.ToStorageBlock()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("serializing message: %w", err)
|
||||
}
|
||||
|
||||
sig, err := a.Wallet.WalletSign(ctx, keyAddr, mb.Cid().Bytes(), api.MsgMeta{
|
||||
sig, err := a.Wallet.WalletSign(ctx, keyAddr, sb, api.MsgMeta{
|
||||
Type: api.MTChainMsg,
|
||||
Extra: mb.RawData(),
|
||||
})
|
||||
|
||||
@@ -91,8 +91,12 @@ func (a *NetAPI) NetPeerInfo(_ context.Context, p peer.ID) (*api.ExtendedPeerInf
|
||||
|
||||
protocols, err := a.Host.Peerstore().GetProtocols(p)
|
||||
if err == nil {
|
||||
sort.Strings(protocols)
|
||||
info.Protocols = protocols
|
||||
protocolStrings := make([]string, 0, len(protocols))
|
||||
for _, protocol := range protocols {
|
||||
protocolStrings = append(protocolStrings, string(protocol))
|
||||
}
|
||||
sort.Strings(protocolStrings)
|
||||
info.Protocols = protocolStrings
|
||||
}
|
||||
|
||||
if cm := a.Host.ConnManager().GetTagInfo(p); cm != nil {
|
||||
|
||||
+4
-16
@@ -25,8 +25,8 @@ import (
|
||||
"github.com/filecoin-project/dagstore/shard"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
gst "github.com/filecoin-project/go-data-transfer/transport/graphsync"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer/v2"
|
||||
gst "github.com/filecoin-project/go-data-transfer/v2/transport/graphsync"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
@@ -539,20 +539,8 @@ func (sm *StorageMinerAPI) MarketListDeals(ctx context.Context) ([]*api.MarketDe
|
||||
return sm.listDeals(ctx)
|
||||
}
|
||||
|
||||
func (sm *StorageMinerAPI) MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) {
|
||||
var out []retrievalmarket.ProviderDealState
|
||||
deals := sm.RetrievalProvider.ListDeals()
|
||||
|
||||
for _, deal := range deals {
|
||||
if deal.ChannelID != nil {
|
||||
if deal.ChannelID.Initiator == "" || deal.ChannelID.Responder == "" {
|
||||
deal.ChannelID = nil // don't try to push unparsable peer IDs over jsonrpc
|
||||
}
|
||||
}
|
||||
out = append(out, deal)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
func (sm *StorageMinerAPI) MarketListRetrievalDeals(ctx context.Context) ([]struct{}, error) {
|
||||
return []struct{}{}, nil
|
||||
}
|
||||
|
||||
func (sm *StorageMinerAPI) MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error) {
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"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"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
type EventAPI struct {
|
||||
fx.In
|
||||
|
||||
full.ChainAPI
|
||||
full.StateAPI
|
||||
}
|
||||
|
||||
var _ events.EventAPI = &EventAPI{}
|
||||
|
||||
func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) {
|
||||
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) {
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
|
||||
ee := &full.EthEvent{
|
||||
Chain: cs,
|
||||
MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange),
|
||||
SubscribtionCtx: ctx,
|
||||
}
|
||||
|
||||
if !cfg.EnableEthRPC || cfg.Events.DisableRealTimeFilterAPI {
|
||||
// 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.Events.MaxFilters)
|
||||
|
||||
// Start garbage collection for filters
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
go ee.GC(ctx, time.Duration(cfg.Events.FilterTTL))
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
// Enable indexing of actor events
|
||||
var eventIndex *filter.EventIndex
|
||||
if !cfg.Events.DisableHistoricFilterAPI {
|
||||
var dbPath string
|
||||
if cfg.Events.DatabasePath == "" {
|
||||
sqlitePath, err := r.SqlitePath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbPath = filepath.Join(sqlitePath, "events.db")
|
||||
} else {
|
||||
dbPath = cfg.Events.DatabasePath
|
||||
}
|
||||
|
||||
var err error
|
||||
eventIndex, err = filter.NewEventIndex(dbPath)
|
||||
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.Events.MaxFilterResults,
|
||||
}
|
||||
ee.TipSetFilterManager = &filter.TipSetFilterManager{
|
||||
MaxFilterResults: cfg.Events.MaxFilterResults,
|
||||
}
|
||||
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
|
||||
MaxFilterResults: cfg.Events.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
|
||||
}
|
||||
}
|
||||
@@ -82,11 +82,14 @@ func SplitBlockstore(cfg *config.Chainstore) func(lc fx.Lifecycle, r repo.Locked
|
||||
}
|
||||
|
||||
cfg := &splitstore.Config{
|
||||
MarkSetType: cfg.Splitstore.MarkSetType,
|
||||
DiscardColdBlocks: cfg.Splitstore.ColdStoreType == "discard",
|
||||
UniversalColdBlocks: cfg.Splitstore.ColdStoreType == "universal",
|
||||
HotStoreMessageRetention: cfg.Splitstore.HotStoreMessageRetention,
|
||||
HotStoreFullGCFrequency: cfg.Splitstore.HotStoreFullGCFrequency,
|
||||
MarkSetType: cfg.Splitstore.MarkSetType,
|
||||
DiscardColdBlocks: cfg.Splitstore.ColdStoreType == "discard",
|
||||
UniversalColdBlocks: cfg.Splitstore.ColdStoreType == "universal",
|
||||
HotStoreMessageRetention: cfg.Splitstore.HotStoreMessageRetention,
|
||||
HotStoreFullGCFrequency: cfg.Splitstore.HotStoreFullGCFrequency,
|
||||
HotstoreMaxSpaceTarget: cfg.Splitstore.HotStoreMaxSpaceTarget,
|
||||
HotstoreMaxSpaceThreshold: cfg.Splitstore.HotStoreMaxSpaceThreshold,
|
||||
HotstoreMaxSpaceSafetyBuffer: cfg.Splitstore.HotstoreMaxSpaceSafetyBuffer,
|
||||
}
|
||||
ss, err := splitstore.Open(path, ds, hot, cold, cfg)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-bitswap"
|
||||
"github.com/ipfs/go-bitswap/network"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-libipfs/bitswap"
|
||||
"github.com/ipfs/go-libipfs/bitswap/network"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
"go.uber.org/fx"
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/exchange"
|
||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||
"github.com/filecoin-project/lotus/chain/index"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -69,7 +70,7 @@ func MessagePool(lc fx.Lifecycle, mctx helpers.MetricsCtx, us stmgr.UpgradeSched
|
||||
return mp.Close()
|
||||
},
|
||||
})
|
||||
protector.AddProtector(mp.ForEachPendingMessage)
|
||||
protector.AddProtector(mp.TryForEachPendingMessage)
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ func NetworkName(mctx helpers.MetricsCtx,
|
||||
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us, nil)
|
||||
sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us, nil, nil, index.DummyMsgIndex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -181,3 +182,7 @@ func NewSlashFilter(ds dtypes.MetadataDS) *slashfilter.SlashFilter {
|
||||
func UpgradeSchedule() stmgr.UpgradeSchedule {
|
||||
return filcns.DefaultUpgradeSchedule()
|
||||
}
|
||||
|
||||
func EnableStoringEvents(cs *store.ChainStore) {
|
||||
cs.StoreEvents(true)
|
||||
}
|
||||
|
||||
+4
-14
@@ -13,10 +13,10 @@ import (
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-data-transfer/channelmonitor"
|
||||
dtimpl "github.com/filecoin-project/go-data-transfer/impl"
|
||||
dtnet "github.com/filecoin-project/go-data-transfer/network"
|
||||
dtgstransport "github.com/filecoin-project/go-data-transfer/transport/graphsync"
|
||||
"github.com/filecoin-project/go-data-transfer/v2/channelmonitor"
|
||||
dtimpl "github.com/filecoin-project/go-data-transfer/v2/impl"
|
||||
dtnet "github.com/filecoin-project/go-data-transfer/v2/network"
|
||||
dtgstransport "github.com/filecoin-project/go-data-transfer/v2/transport/graphsync"
|
||||
"github.com/filecoin-project/go-fil-markets/discovery"
|
||||
discoveryimpl "github.com/filecoin-project/go-fil-markets/discovery/impl"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
rmnet "github.com/filecoin-project/go-fil-markets/retrievalmarket/network"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
storageimpl "github.com/filecoin-project/go-fil-markets/storagemarket/impl"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation"
|
||||
smnet "github.com/filecoin-project/go-fil-markets/storagemarket/network"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
@@ -95,15 +94,6 @@ func ClientBlockstore() dtypes.ClientBlockstore {
|
||||
return blockstore.WrapIDStore(blockstore.FromDatastore(datastore.NewMapDatastore()))
|
||||
}
|
||||
|
||||
// RegisterClientValidator is an initialization hook that registers the client
|
||||
// request validator with the data transfer module as the validator for
|
||||
// StorageDataTransferVoucher types
|
||||
func RegisterClientValidator(crv dtypes.ClientRequestValidator, dtm dtypes.ClientDataTransfer) {
|
||||
if err := dtm.RegisterVoucherType(&requestvalidation.StorageDataTransferVoucher{}, (*requestvalidation.UnifiedRequestValidator)(crv)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientGraphsyncDataTransfer returns a data transfer manager that just
|
||||
// uses the clients's Client DAG service for transfers
|
||||
func NewClientGraphsyncDataTransfer(lc fx.Lifecycle, h host.Host, gs dtypes.Graphsync, ds dtypes.MetadataDS, r repo.LockedRepo) (dtypes.ClientDataTransfer, error) {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"github.com/ipfs/go-graphsync"
|
||||
exchange "github.com/ipfs/go-ipfs-exchange-interface"
|
||||
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
dtnet "github.com/filecoin-project/go-data-transfer/network"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer/v2"
|
||||
dtnet "github.com/filecoin-project/go-data-transfer/v2/network"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation"
|
||||
"github.com/filecoin-project/go-statestore"
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/ethhashlookup"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"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/node/config"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
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) {
|
||||
sqlitePath, err := r.SqlitePath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(sqlitePath, "txhash.db")
|
||||
|
||||
// Check if the db exists, if not, we'll back-fill some entries
|
||||
_, err = os.Stat(dbPath)
|
||||
dbAlreadyExists := err == nil
|
||||
|
||||
transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(ctx context.Context) error {
|
||||
return transactionHashLookup.Close()
|
||||
},
|
||||
})
|
||||
|
||||
ethTxHashManager := full.EthTxHashManager{
|
||||
StateAPI: stateapi,
|
||||
TransactionHashLookup: transactionHashLookup,
|
||||
}
|
||||
|
||||
if !dbAlreadyExists {
|
||||
err = ethTxHashManager.PopulateExistingMappings(mctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
const ChainHeadConfidence = 1
|
||||
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
ev, err := events.NewEventsWithConfidence(ctx, &evapi, ChainHeadConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Tipset listener
|
||||
_ = ev.Observe(ðTxHashManager)
|
||||
|
||||
ch, err := mp.Updates(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go full.WaitForMpoolUpdates(ctx, ch, ðTxHashManager)
|
||||
go full.EthTxHashGC(ctx, cfg.EthTxHashMappingLifetimeDays, ðTxHashManager)
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return &full.EthModule{
|
||||
Chain: cs,
|
||||
Mpool: mp,
|
||||
StateManager: sm,
|
||||
|
||||
ChainAPI: chainapi,
|
||||
MpoolAPI: mpoolapi,
|
||||
StateAPI: stateapi,
|
||||
|
||||
EthTxHashManager: ðTxHashManager,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,13 @@ func Host(mctx helpers.MetricsCtx, lc fx.Lifecycle, params P2PHostIn) (RawHost,
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func UserAgentOption(agent string) func() (opts Libp2pOpts, err error) {
|
||||
return func() (opts Libp2pOpts, err error) {
|
||||
opts.Opts = append(opts.Opts, libp2p.UserAgent(agent))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func MockHost(mn mocknet.Mocknet, id peer.ID, ps peerstore.Peerstore) (RawHost, error) {
|
||||
return mn.AddPeerWithPeerstore(id, ps)
|
||||
}
|
||||
|
||||
+32
-26
@@ -7,6 +7,7 @@ import (
|
||||
"math/bits"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
@@ -14,10 +15,9 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs"
|
||||
rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.opencensus.io/tag"
|
||||
"go.uber.org/fx"
|
||||
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
var rcmgrMetricsOnce sync.Once
|
||||
|
||||
func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo) (network.ResourceManager, error) {
|
||||
return func(lc fx.Lifecycle, repo repo.LockedRepo) (network.ResourceManager, error) {
|
||||
isFullNode := repo.RepoType().Type() == "FullNode"
|
||||
@@ -32,7 +34,7 @@ func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo)
|
||||
if (isFullNode && envvar == "0") || // only set NullResourceManager if envvar is explicitly "0"
|
||||
(!isFullNode && envvar != "1") { // set NullResourceManager *unless* envvar is explicitly "1"
|
||||
log.Info("libp2p resource manager is disabled")
|
||||
return network.NullResourceManager, nil
|
||||
return &network.NullResourceManager{}, nil
|
||||
}
|
||||
|
||||
log.Info("libp2p resource manager is enabled")
|
||||
@@ -52,37 +54,41 @@ func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo)
|
||||
// For every extra 1GB of memory we have available, increase our limit by 1GiB
|
||||
defaultLimits.SystemLimitIncrease.Memory = 1 << 30
|
||||
defaultLimitConfig := defaultLimits.AutoScale()
|
||||
if defaultLimitConfig.System.Memory > 4<<30 {
|
||||
|
||||
changes := rcmgr.PartialLimitConfig{}
|
||||
|
||||
if defaultLimitConfig.ToPartialLimitConfig().System.Memory > 4<<30 {
|
||||
// Cap our memory limit
|
||||
defaultLimitConfig.System.Memory = 4 << 30
|
||||
changes.System.Memory = 4 << 30
|
||||
}
|
||||
|
||||
maxconns := int(connMgrHi)
|
||||
if 2*maxconns > defaultLimitConfig.System.ConnsInbound {
|
||||
if rcmgr.LimitVal(2*maxconns) > defaultLimitConfig.ToPartialLimitConfig().System.ConnsInbound {
|
||||
// adjust conns to 2x to allow for two conns per peer (TCP+QUIC)
|
||||
defaultLimitConfig.System.ConnsInbound = logScale(2 * maxconns)
|
||||
defaultLimitConfig.System.ConnsOutbound = logScale(2 * maxconns)
|
||||
defaultLimitConfig.System.Conns = logScale(4 * maxconns)
|
||||
changes.System.ConnsInbound = rcmgr.LimitVal(logScale(2 * maxconns))
|
||||
changes.System.ConnsOutbound = rcmgr.LimitVal(logScale(2 * maxconns))
|
||||
changes.System.Conns = rcmgr.LimitVal(logScale(4 * maxconns))
|
||||
|
||||
defaultLimitConfig.System.StreamsInbound = logScale(16 * maxconns)
|
||||
defaultLimitConfig.System.StreamsOutbound = logScale(64 * maxconns)
|
||||
defaultLimitConfig.System.Streams = logScale(64 * maxconns)
|
||||
changes.System.StreamsInbound = rcmgr.LimitVal(logScale(16 * maxconns))
|
||||
changes.System.StreamsOutbound = rcmgr.LimitVal(logScale(64 * maxconns))
|
||||
changes.System.Streams = rcmgr.LimitVal(logScale(64 * maxconns))
|
||||
|
||||
if 2*maxconns > defaultLimitConfig.System.FD {
|
||||
defaultLimitConfig.System.FD = logScale(2 * maxconns)
|
||||
if rcmgr.LimitVal(2*maxconns) > defaultLimitConfig.ToPartialLimitConfig().System.FD {
|
||||
changes.System.FD = rcmgr.LimitVal(logScale(2 * maxconns))
|
||||
}
|
||||
|
||||
defaultLimitConfig.ServiceDefault.StreamsInbound = logScale(8 * maxconns)
|
||||
defaultLimitConfig.ServiceDefault.StreamsOutbound = logScale(32 * maxconns)
|
||||
defaultLimitConfig.ServiceDefault.Streams = logScale(32 * maxconns)
|
||||
changes.ServiceDefault.StreamsInbound = rcmgr.LimitVal(logScale(8 * maxconns))
|
||||
changes.ServiceDefault.StreamsOutbound = rcmgr.LimitVal(logScale(32 * maxconns))
|
||||
changes.ServiceDefault.Streams = rcmgr.LimitVal(logScale(32 * maxconns))
|
||||
|
||||
defaultLimitConfig.ProtocolDefault.StreamsInbound = logScale(8 * maxconns)
|
||||
defaultLimitConfig.ProtocolDefault.StreamsOutbound = logScale(32 * maxconns)
|
||||
defaultLimitConfig.ProtocolDefault.Streams = logScale(32 * maxconns)
|
||||
changes.ProtocolDefault.StreamsInbound = rcmgr.LimitVal(logScale(8 * maxconns))
|
||||
changes.ProtocolDefault.StreamsOutbound = rcmgr.LimitVal(logScale(32 * maxconns))
|
||||
changes.ProtocolDefault.Streams = rcmgr.LimitVal(logScale(32 * maxconns))
|
||||
|
||||
log.Info("adjusted default resource manager limits")
|
||||
}
|
||||
|
||||
changedLimitConfig := changes.Build(defaultLimitConfig)
|
||||
// initialize
|
||||
var limiter rcmgr.Limiter
|
||||
var opts []rcmgr.Option
|
||||
@@ -95,13 +101,13 @@ func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo)
|
||||
switch {
|
||||
case err == nil:
|
||||
defer limitsIn.Close() //nolint:errcheck
|
||||
limiter, err = rcmgr.NewLimiterFromJSON(limitsIn, defaultLimitConfig)
|
||||
limiter, err = rcmgr.NewLimiterFromJSON(limitsIn, changedLimitConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing limit file: %w", err)
|
||||
}
|
||||
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
limiter = rcmgr.NewFixedLimiter(defaultLimitConfig)
|
||||
limiter = rcmgr.NewFixedLimiter(changedLimitConfig)
|
||||
|
||||
default:
|
||||
return nil, err
|
||||
@@ -111,10 +117,10 @@ func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating resource manager stats reporter: %w", err)
|
||||
}
|
||||
err = view.Register(obs.DefaultViews...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error registering rcmgr metrics: %w", err)
|
||||
}
|
||||
|
||||
rcmgrMetricsOnce.Do(func() {
|
||||
rcmgrObs.MustRegisterWith(prometheus.DefaultRegisterer)
|
||||
})
|
||||
|
||||
// Metrics
|
||||
opts = append(opts, rcmgr.WithMetrics(rcmgrMetrics{}), rcmgr.WithTraceReporter(str))
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/index"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
func MsgIndex(lc fx.Lifecycle, mctx helpers.MetricsCtx, cs *store.ChainStore, r repo.LockedRepo) (index.MsgIndex, error) {
|
||||
basePath, err := r.SqlitePath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgIndex, err := index.NewMsgIndex(helpers.LifecycleCtx(mctx, lc), basePath, cs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(_ context.Context) error {
|
||||
return msgIndex.Close()
|
||||
},
|
||||
})
|
||||
|
||||
return msgIndex, nil
|
||||
}
|
||||
|
||||
func DummyMsgIndex() index.MsgIndex {
|
||||
return index.DummyMsgIndex
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -84,7 +85,7 @@ func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello.
|
||||
return nil
|
||||
}
|
||||
|
||||
func protosContains(protos []string, search string) bool {
|
||||
func protosContains(protos []protocol.ID, search protocol.ID) bool {
|
||||
for _, p := range protos {
|
||||
if p == search {
|
||||
return true
|
||||
|
||||
@@ -4,13 +4,15 @@ import (
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/index"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule, b beacon.Schedule) (*stmgr.StateManager, error) {
|
||||
sm, err := stmgr.NewStateManager(cs, exec, sys, us, b)
|
||||
func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule, b beacon.Schedule, metadataDs dtypes.MetadataDS, msgIndex index.MsgIndex) (*stmgr.StateManager, error) {
|
||||
sm, err := stmgr.NewStateManager(cs, exec, sys, us, b, metadataDs, msgIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -18,15 +18,16 @@ import (
|
||||
graphsync "github.com/ipfs/go-graphsync/impl"
|
||||
gsnet "github.com/ipfs/go-graphsync/network"
|
||||
"github.com/ipfs/go-graphsync/storeutil"
|
||||
provider "github.com/ipni/index-provider"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/multierr"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
dtimpl "github.com/filecoin-project/go-data-transfer/impl"
|
||||
dtnet "github.com/filecoin-project/go-data-transfer/network"
|
||||
dtgstransport "github.com/filecoin-project/go-data-transfer/transport/graphsync"
|
||||
dtimpl "github.com/filecoin-project/go-data-transfer/v2/impl"
|
||||
dtnet "github.com/filecoin-project/go-data-transfer/v2/network"
|
||||
dtgstransport "github.com/filecoin-project/go-data-transfer/v2/transport/graphsync"
|
||||
piecefilestore "github.com/filecoin-project/go-fil-markets/filestore"
|
||||
piecestoreimpl "github.com/filecoin-project/go-fil-markets/piecestore/impl"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
@@ -42,7 +43,6 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-statestore"
|
||||
provider "github.com/filecoin-project/index-provider"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
provider "github.com/ipni/index-provider"
|
||||
"github.com/ipni/index-provider/engine"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
provider "github.com/filecoin-project/index-provider"
|
||||
"github.com/filecoin-project/index-provider/engine"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
@@ -41,10 +41,15 @@ func IndexProvider(cfg config.IndexProviderConfig) func(params IdxProv, marketHo
|
||||
}
|
||||
|
||||
ipds := namespace.Wrap(args.Datastore, datastore.NewKey("/index-provider"))
|
||||
addrs := marketHost.Addrs()
|
||||
addrsString := make([]string, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
addrsString = append(addrsString, addr.String())
|
||||
}
|
||||
var opts = []engine.Option{
|
||||
engine.WithDatastore(ipds),
|
||||
engine.WithHost(marketHost),
|
||||
engine.WithRetrievalAddrs(marketHost.Addrs()...),
|
||||
engine.WithRetrievalAddrs(addrsString...),
|
||||
engine.WithEntriesCacheCapacity(cfg.EntriesCacheCapacity),
|
||||
engine.WithChainedEntries(cfg.EntriesChunkSize),
|
||||
engine.WithTopicName(topicName),
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
provider "github.com/ipni/index-provider"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
@@ -14,7 +15,6 @@ import (
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
provider "github.com/filecoin-project/index-provider"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
|
||||
type LotusTraceEvent struct {
|
||||
Type pubsub_pb.TraceEvent_Type `json:"type,omitempty"`
|
||||
PeerID string `json:"peerID,omitempty"`
|
||||
PeerID []byte `json:"peerID,omitempty"`
|
||||
Timestamp *int64 `json:"timestamp,omitempty"`
|
||||
PeerScore TraceEventPeerScore `json:"peerScore,omitempty"`
|
||||
SourceAuth string `json:"sourceAuth,omitempty"`
|
||||
@@ -46,7 +46,7 @@ type TopicScore struct {
|
||||
}
|
||||
|
||||
type TraceEventPeerScore struct {
|
||||
PeerID string `json:"peerID"`
|
||||
PeerID []byte `json:"peerID"`
|
||||
Score float64 `json:"score"`
|
||||
AppSpecificScore float64 `json:"appSpecificScore"`
|
||||
IPColocationFactor float64 `json:"ipColocationFactor"`
|
||||
@@ -77,11 +77,11 @@ func (lt *lotusTracer) PeerScores(scores map[peer.ID]*pubsub.PeerScoreSnapshot)
|
||||
|
||||
evt := &LotusTraceEvent{
|
||||
Type: *TraceEventPeerScores.Enum(),
|
||||
PeerID: lt.pid.Pretty(),
|
||||
Timestamp: &now,
|
||||
PeerID: []byte(lt.pid),
|
||||
SourceAuth: lt.sa,
|
||||
PeerScore: TraceEventPeerScore{
|
||||
PeerID: pid.Pretty(),
|
||||
PeerID: []byte(pid),
|
||||
Score: score.Score,
|
||||
AppSpecificScore: score.AppSpecificScore,
|
||||
IPColocationFactor: score.IPColocationFactor,
|
||||
@@ -104,7 +104,6 @@ func (lt *lotusTracer) TraceLotusEvent(evt *LotusTraceEvent) {
|
||||
log.Errorf("error while transporting peer scores: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (lt *lotusTracer) Trace(evt *pubsub_pb.TraceEvent) {
|
||||
|
||||
@@ -30,16 +30,15 @@ func (ttt *testTracerTransport) Transport(evt TracerTransportEvent) error {
|
||||
}
|
||||
|
||||
func TestTracer_PeerScores(t *testing.T) {
|
||||
|
||||
testTransport := NewTestTraceTransport(t, func(t *testing.T, evt TracerTransportEvent) {
|
||||
require.Equal(t, peerIDA.Pretty(), evt.lotusTraceEvent.PeerID)
|
||||
require.Equal(t, []byte(peerIDA), evt.lotusTraceEvent.PeerID)
|
||||
require.Equal(t, "source-auth-token-test", evt.lotusTraceEvent.SourceAuth)
|
||||
require.Equal(t, float64(32), evt.lotusTraceEvent.PeerScore.Score)
|
||||
|
||||
n := time.Now().UnixNano()
|
||||
require.LessOrEqual(t, *evt.lotusTraceEvent.Timestamp, n)
|
||||
|
||||
require.Equal(t, peerIDA.Pretty(), evt.lotusTraceEvent.PeerScore.PeerID)
|
||||
require.Equal(t, []byte(peerIDA), evt.lotusTraceEvent.PeerScore.PeerID)
|
||||
require.Equal(t, 1, len(evt.lotusTraceEvent.PeerScore.Topics))
|
||||
|
||||
topic := evt.lotusTraceEvent.PeerScore.Topics[0]
|
||||
@@ -85,7 +84,6 @@ func TestTracer_PubSubTrace(t *testing.T) {
|
||||
PeerID: []byte(peerIDA),
|
||||
Timestamp: &n,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestTracer_MultipleTransports(t *testing.T) {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package repo
|
||||
|
||||
import badgerbs "github.com/filecoin-project/lotus/blockstore/badger"
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
badgerbs "github.com/filecoin-project/lotus/blockstore/badger"
|
||||
)
|
||||
|
||||
// BadgerBlockstoreOptions returns the badger options to apply for the provided
|
||||
// domain.
|
||||
@@ -42,5 +47,17 @@ func BadgerBlockstoreOptions(domain BlockstoreDomain, path string, readonly bool
|
||||
|
||||
opts.ReadOnly = readonly
|
||||
|
||||
// Envvar LOTUS_CHAIN_BADGERSTORE_COMPACTIONWORKERNUM
|
||||
// Allows the number of compaction workers used by BadgerDB to be adjusted
|
||||
// Unset - leaves the default number of compaction workers (4)
|
||||
// "0" - disables compaction
|
||||
// Positive integer - enables that number of compaction workers
|
||||
if badgerNumCompactors, badgerNumCompactorsSet := os.LookupEnv("LOTUS_CHAIN_BADGERSTORE_COMPACTIONWORKERNUM"); badgerNumCompactorsSet {
|
||||
if numWorkers, err := strconv.Atoi(badgerNumCompactors); err == nil && numWorkers >= 0 {
|
||||
opts.NumCompactors = numWorkers
|
||||
}
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
|
||||
}
|
||||
|
||||
+32
-14
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/storiface"
|
||||
"github.com/filecoin-project/lotus/system"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -37,6 +38,7 @@ const (
|
||||
fsDatastore = "datastore"
|
||||
fsLock = "repo.lock"
|
||||
fsKeystore = "keystore"
|
||||
fsSqlite = "sqlite"
|
||||
)
|
||||
|
||||
func NewRepoTypeFromString(t string) RepoType {
|
||||
@@ -411,6 +413,10 @@ type fsLockedRepo struct {
|
||||
ssErr error
|
||||
ssOnce sync.Once
|
||||
|
||||
sqlPath string
|
||||
sqlErr error
|
||||
sqlOnce sync.Once
|
||||
|
||||
storageLk sync.Mutex
|
||||
configLk sync.Mutex
|
||||
}
|
||||
@@ -474,19 +480,8 @@ func (fsr *fsLockedRepo) Blockstore(ctx context.Context, domain BlockstoreDomain
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// Tri-state environment variable LOTUS_CHAIN_BADGERSTORE_DISABLE_FSYNC
|
||||
// - unset == the default (currently fsync enabled)
|
||||
// - set with a false-y value == fsync enabled no matter what a future default is
|
||||
// - set with any other value == fsync is disabled ignored defaults (recommended for day-to-day use)
|
||||
//
|
||||
if nosyncBs, nosyncBsSet := os.LookupEnv("LOTUS_CHAIN_BADGERSTORE_DISABLE_FSYNC"); nosyncBsSet {
|
||||
nosyncBs = strings.ToLower(nosyncBs)
|
||||
if nosyncBs == "" || nosyncBs == "0" || nosyncBs == "false" || nosyncBs == "no" {
|
||||
opts.SyncWrites = true
|
||||
} else {
|
||||
opts.SyncWrites = false
|
||||
}
|
||||
if system.BadgerFsyncDisable {
|
||||
opts.SyncWrites = false
|
||||
}
|
||||
|
||||
bs, err := badgerbs.Open(opts)
|
||||
@@ -515,6 +510,21 @@ func (fsr *fsLockedRepo) SplitstorePath() (string, error) {
|
||||
return fsr.ssPath, fsr.ssErr
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) SqlitePath() (string, error) {
|
||||
fsr.sqlOnce.Do(func() {
|
||||
path := fsr.join(fsSqlite)
|
||||
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
fsr.sqlErr = err
|
||||
return
|
||||
}
|
||||
|
||||
fsr.sqlPath = path
|
||||
})
|
||||
|
||||
return fsr.sqlPath, fsr.sqlErr
|
||||
}
|
||||
|
||||
// join joins path elements with fsr.path
|
||||
func (fsr *fsLockedRepo) join(paths ...string) string {
|
||||
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
||||
@@ -535,7 +545,15 @@ func (fsr *fsLockedRepo) Config() (interface{}, error) {
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) loadConfigFromDisk() (interface{}, error) {
|
||||
return config.FromFile(fsr.configPath, fsr.repoType.Config())
|
||||
var opts []config.LoadCfgOpt
|
||||
if fsr.repoType == FullNode {
|
||||
opts = append(opts, config.SetCanFallbackOnDefault(config.NoDefaultForSplitstoreTransition))
|
||||
opts = append(opts, config.SetValidate(config.ValidateSplitstoreSet))
|
||||
}
|
||||
opts = append(opts, config.SetDefault(func() (interface{}, error) {
|
||||
return fsr.repoType.Config(), nil
|
||||
}))
|
||||
return config.FromFile(fsr.configPath, opts...)
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) SetConfig(c func(interface{})) error {
|
||||
|
||||
@@ -69,6 +69,9 @@ type LockedRepo interface {
|
||||
// SplitstorePath returns the path for the SplitStore
|
||||
SplitstorePath() (string, error)
|
||||
|
||||
// SqlitePath returns the path for the Sqlite database
|
||||
SqlitePath() (string, error)
|
||||
|
||||
// Returns config in this repo
|
||||
Config() (interface{}, error)
|
||||
SetConfig(func(interface{})) error
|
||||
|
||||
@@ -277,6 +277,14 @@ func (lmem *lockedMemRepo) SplitstorePath() (string, error) {
|
||||
return splitstorePath, nil
|
||||
}
|
||||
|
||||
func (lmem *lockedMemRepo) SqlitePath() (string, error) {
|
||||
sqlitePath := filepath.Join(lmem.Path(), "sqlite")
|
||||
if err := os.MkdirAll(sqlitePath, 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return sqlitePath, nil
|
||||
}
|
||||
|
||||
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
+5
-3
@@ -75,10 +75,12 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
||||
m := mux.NewRouter()
|
||||
|
||||
serveRpc := func(path string, hnd interface{}) {
|
||||
rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithServerErrors(api.RPCErrors))...)
|
||||
rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithReverseClient[api.EthSubscriberMethods]("Filecoin"), jsonrpc.WithServerErrors(api.RPCErrors))...)
|
||||
rpcServer.Register("Filecoin", hnd)
|
||||
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
|
||||
|
||||
api.CreateEthRPCAliases(rpcServer)
|
||||
|
||||
var handler http.Handler = rpcServer
|
||||
if permissioned {
|
||||
handler = &auth.Handler{Verify: a.AuthVerify, Next: rpcServer.ServeHTTP}
|
||||
@@ -92,8 +94,9 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
||||
fnapi = api.PermissionedFullAPI(fnapi)
|
||||
}
|
||||
|
||||
var v0 v0api.FullNode = &(struct{ v0api.FullNode }{&v0api.WrapperV1Full{FullNode: fnapi}})
|
||||
serveRpc("/rpc/v1", fnapi)
|
||||
serveRpc("/rpc/v0", &v0api.WrapperV1Full{FullNode: fnapi})
|
||||
serveRpc("/rpc/v0", v0)
|
||||
|
||||
// Import handler
|
||||
handleImportFunc := handleImport(a.(*impl.FullNodeAPI))
|
||||
@@ -105,7 +108,6 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
||||
Next: handleImportFunc,
|
||||
}
|
||||
m.Handle("/rest/v0/import", importAH)
|
||||
|
||||
exportAH := &auth.Handler{
|
||||
Verify: a.AuthVerify,
|
||||
Next: handleExportFunc,
|
||||
|
||||
@@ -51,6 +51,7 @@ func MonitorShutdown(triggerCh <-chan struct{}, handlers ...ShutdownHandler) <-c
|
||||
close(out)
|
||||
}()
|
||||
|
||||
signal.Reset(syscall.SIGTERM, syscall.SIGINT)
|
||||
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user