Merge remote-tracking branch 'origin/master' into feat/window-post-faulty-sectors
This commit is contained in:
commit
e996a5246b
@ -231,11 +231,11 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: install statediff globally
|
name: install statediff globally
|
||||||
command: |
|
command: |
|
||||||
|
## statediff is optional; we succeed even if compilation fails.
|
||||||
mkdir -p /tmp/statediff
|
mkdir -p /tmp/statediff
|
||||||
git clone https://github.com/filecoin-project/statediff.git /tmp/statediff
|
git clone https://github.com/filecoin-project/statediff.git /tmp/statediff
|
||||||
cd /tmp/statediff
|
cd /tmp/statediff
|
||||||
go generate ./...
|
go install ./cmd/statediff || exit 0
|
||||||
go install ./cmd/statediff
|
|
||||||
- run:
|
- run:
|
||||||
name: go test
|
name: go test
|
||||||
environment:
|
environment:
|
||||||
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -8,7 +8,7 @@
|
|||||||
## the PR before merging.
|
## the PR before merging.
|
||||||
|
|
||||||
### Global owners.
|
### Global owners.
|
||||||
* @magik6k @whyrusleeping
|
* @magik6k @whyrusleeping @Kubuxu
|
||||||
|
|
||||||
### Conformance testing.
|
### Conformance testing.
|
||||||
conformance/ @raulk
|
conformance/ @raulk
|
||||||
|
39
CHANGELOG.md
39
CHANGELOG.md
@ -1,5 +1,44 @@
|
|||||||
# Lotus changelog
|
# Lotus changelog
|
||||||
|
|
||||||
|
# 0.6.2 / 2020-09-09
|
||||||
|
|
||||||
|
This release introduces some critical fixes to message selection and gas estimation logic. It also adds the ability for nodes to mark a certain tipset as checkpointed, as well as various minor improvements and bugfixes.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
#### Messagepool
|
||||||
|
|
||||||
|
- Warn when optimal selection fails to pack a block and we fall back to random selection (https://github.com/filecoin-project/lotus/pull/3708)
|
||||||
|
- Add basic command for printing gas performance of messages in the mpool (https://github.com/filecoin-project/lotus/pull/3701)
|
||||||
|
- Adjust optimal selection to always try to fill blocks (https://github.com/filecoin-project/lotus/pull/3685)
|
||||||
|
- Fix very minor bug in repub baseFeeLowerBound (https://github.com/filecoin-project/lotus/pull/3663)
|
||||||
|
- Add an auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3676)
|
||||||
|
- Fix mpool optimal selection packing failure (https://github.com/filecoin-project/lotus/pull/3698)
|
||||||
|
|
||||||
|
#### Core Lotus
|
||||||
|
|
||||||
|
- Don't use latency as initital estimate for blocksync (https://github.com/filecoin-project/lotus/pull/3648)
|
||||||
|
- Add niceSleep 1 second when drand errors (https://github.com/filecoin-project/lotus/pull/3664)
|
||||||
|
- Fix isChainNearSync check in block validator (https://github.com/filecoin-project/lotus/pull/3650)
|
||||||
|
- Add peer to peer manager before fetching the tipset (https://github.com/filecoin-project/lotus/pull/3667)
|
||||||
|
- Add StageFetchingMessages to sync status (https://github.com/filecoin-project/lotus/pull/3668)
|
||||||
|
- Pass tipset through upgrade logic (https://github.com/filecoin-project/lotus/pull/3673)
|
||||||
|
- Allow nodes to mark tipsets as checkpointed (https://github.com/filecoin-project/lotus/pull/3680)
|
||||||
|
- Remove hard-coded late-fee in window PoSt (https://github.com/filecoin-project/lotus/pull/3702)
|
||||||
|
- Gas: Fix median calc (https://github.com/filecoin-project/lotus/pull/3686)
|
||||||
|
|
||||||
|
#### Storage
|
||||||
|
|
||||||
|
- Storage manager: bail out with an error if unsealed cid is undefined (https://github.com/filecoin-project/lotus/pull/3655)
|
||||||
|
- Storage: return true from Sealer.ReadPiece() on success (https://github.com/filecoin-project/lotus/pull/3657)
|
||||||
|
|
||||||
|
#### Maintenance
|
||||||
|
|
||||||
|
- Resolve lotus, test-vectors, statediff dependency cycle (https://github.com/filecoin-project/lotus/pull/3688)
|
||||||
|
- Paych: add docs on how to use paych status (https://github.com/filecoin-project/lotus/pull/3690)
|
||||||
|
- Initial CODEOWNERS (https://github.com/filecoin-project/lotus/pull/3691)
|
||||||
|
|
||||||
|
|
||||||
# 0.6.1 / 2020-09-08
|
# 0.6.1 / 2020-09-08
|
||||||
|
|
||||||
This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync.
|
This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync.
|
||||||
|
@ -157,10 +157,16 @@ type FullNode interface {
|
|||||||
// yet synced block headers.
|
// yet synced block headers.
|
||||||
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
||||||
|
|
||||||
|
// SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it.
|
||||||
|
SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error
|
||||||
|
|
||||||
// SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.
|
// SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.
|
||||||
// Use with extreme caution.
|
// Use with extreme caution.
|
||||||
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
||||||
|
|
||||||
|
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
||||||
|
SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
||||||
|
|
||||||
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
||||||
// the reason.
|
// the reason.
|
||||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||||
@ -391,6 +397,9 @@ type FullNode interface {
|
|||||||
|
|
||||||
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
||||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||||
|
// MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
|
||||||
|
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||||
|
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
|
||||||
// MsigCreate creates a multisig wallet
|
// MsigCreate creates a multisig wallet
|
||||||
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
||||||
//<initial balance>, <sender address of the create msg>, <gas price>
|
//<initial balance>, <sender address of the create msg>, <gas price>
|
||||||
@ -407,17 +416,29 @@ type FullNode interface {
|
|||||||
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
|
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
|
||||||
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||||
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||||
|
// MsigAddPropose proposes adding a signer in the multisig
|
||||||
|
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||||
|
// <new signer>, <whether the number of required signers should be increased>
|
||||||
|
MsigAddPropose(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error)
|
||||||
|
// MsigAddApprove approves a previously proposed AddSigner message
|
||||||
|
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||||
|
// <proposer address>, <new signer>, <whether the number of required signers should be increased>
|
||||||
|
MsigAddApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error)
|
||||||
|
// MsigAddCancel cancels a previously proposed AddSigner message
|
||||||
|
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||||
|
// <new signer>, <whether the number of required signers should be increased>
|
||||||
|
MsigAddCancel(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error)
|
||||||
// MsigSwapPropose proposes swapping 2 signers in the multisig
|
// MsigSwapPropose proposes swapping 2 signers in the multisig
|
||||||
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||||
// <old signer> <new signer>
|
// <old signer>, <new signer>
|
||||||
MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error)
|
MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||||
// MsigSwapApprove approves a previously proposed SwapSigner
|
// MsigSwapApprove approves a previously proposed SwapSigner
|
||||||
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||||
// <proposer address>, <old signer> <new signer>
|
// <proposer address>, <old signer>, <new signer>
|
||||||
MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error)
|
MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||||
// MsigSwapCancel cancels a previously proposed SwapSigner message
|
// MsigSwapCancel cancels a previously proposed SwapSigner message
|
||||||
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||||
// <old signer> <new signer>
|
// <old signer>, <new signer>
|
||||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
||||||
|
|
||||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||||
|
@ -105,7 +105,9 @@ type FullNodeStruct struct {
|
|||||||
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
|
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
|
||||||
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
|
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
|
||||||
SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"`
|
SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"`
|
||||||
|
SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"`
|
||||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||||
|
SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||||
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||||
|
|
||||||
MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"`
|
MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"`
|
||||||
@ -199,10 +201,14 @@ type FullNodeStruct struct {
|
|||||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
||||||
|
|
||||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||||
|
MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||||
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||||
|
MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||||
|
MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||||
|
MsigAddCancel func(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||||
@ -704,10 +710,18 @@ func (c *FullNodeStruct) SyncIncomingBlocks(ctx context.Context) (<-chan *types.
|
|||||||
return c.Internal.SyncIncomingBlocks(ctx)
|
return c.Internal.SyncIncomingBlocks(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error {
|
||||||
|
return c.Internal.SyncCheckpoint(ctx, tsk)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
|
func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||||
return c.Internal.SyncMarkBad(ctx, bcid)
|
return c.Internal.SyncMarkBad(ctx, bcid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||||
|
return c.Internal.SyncUnmarkBad(ctx, bcid)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||||
return c.Internal.SyncCheckBad(ctx, bcid)
|
return c.Internal.SyncCheckBad(ctx, bcid)
|
||||||
}
|
}
|
||||||
@ -872,6 +886,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
|
|||||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) {
|
||||||
|
return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||||
return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp)
|
return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp)
|
||||||
}
|
}
|
||||||
@ -888,6 +906,18 @@ func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, t
|
|||||||
return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params)
|
return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||||
|
return c.Internal.MsigAddPropose(ctx, msig, src, newAdd, inc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||||
|
return c.Internal.MsigAddApprove(ctx, msig, src, txID, proposer, newAdd, inc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||||
|
return c.Internal.MsigAddCancel(ctx, msig, src, txID, newAdd, inc)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||||
return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd)
|
return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd)
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func init() {
|
|||||||
addExample(network.Connected)
|
addExample(network.Connected)
|
||||||
addExample(dtypes.NetworkName("lotus"))
|
addExample(dtypes.NetworkName("lotus"))
|
||||||
addExample(api.SyncStateStage(1))
|
addExample(api.SyncStateStage(1))
|
||||||
addExample(build.APIVersion)
|
addExample(build.FullAPIVersion)
|
||||||
addExample(api.PCHInbound)
|
addExample(api.PCHInbound)
|
||||||
addExample(time.Minute)
|
addExample(time.Minute)
|
||||||
addExample(datatransfer.TransferID(3))
|
addExample(datatransfer.TransferID(3))
|
||||||
|
@ -65,6 +65,8 @@ func TestApis(t *testing.T, b APIBuilder) {
|
|||||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||||
|
|
||||||
func (ts *testSuite) testVersion(t *testing.T) {
|
func (ts *testSuite) testVersion(t *testing.T) {
|
||||||
|
build.RunningNodeType = build.NodeFull
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||||
api := apis[0]
|
api := apis[0]
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const UpgradeBreezeHeight = 0
|
const UpgradeBreezeHeight = -1
|
||||||
const BreezeGasTampingDuration = 0
|
const BreezeGasTampingDuration = 0
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
var CurrentCommit string
|
var CurrentCommit string
|
||||||
var BuildType int
|
var BuildType int
|
||||||
@ -25,7 +29,7 @@ func buildType() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildVersion is the local build version, set by build system
|
// BuildVersion is the local build version, set by build system
|
||||||
const BuildVersion = "0.6.2-rc1"
|
const BuildVersion = "0.6.2"
|
||||||
|
|
||||||
func UserVersion() string {
|
func UserVersion() string {
|
||||||
return BuildVersion + buildType() + CurrentCommit
|
return BuildVersion + buildType() + CurrentCommit
|
||||||
@ -52,8 +56,37 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
|||||||
return ve&minorMask == v2&minorMask
|
return ve&minorMask == v2&minorMask
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIVersion is a semver version of the rpc api exposed
|
type NodeType int
|
||||||
var APIVersion Version = newVer(0, 14, 0)
|
|
||||||
|
const (
|
||||||
|
NodeUnknown NodeType = iota
|
||||||
|
|
||||||
|
NodeFull
|
||||||
|
NodeMiner
|
||||||
|
NodeWorker
|
||||||
|
)
|
||||||
|
|
||||||
|
var RunningNodeType NodeType
|
||||||
|
|
||||||
|
func VersionForType(nodeType NodeType) (Version, error) {
|
||||||
|
switch nodeType {
|
||||||
|
case NodeFull:
|
||||||
|
return FullAPIVersion, nil
|
||||||
|
case NodeMiner:
|
||||||
|
return MinerAPIVersion, nil
|
||||||
|
case NodeWorker:
|
||||||
|
return WorkerAPIVersion, nil
|
||||||
|
default:
|
||||||
|
return Version(0), xerrors.Errorf("unknown node type %d", nodeType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// semver versions of the rpc api exposed
|
||||||
|
var (
|
||||||
|
FullAPIVersion = newVer(0, 14, 0)
|
||||||
|
MinerAPIVersion = newVer(0, 14, 0)
|
||||||
|
WorkerAPIVersion = newVer(0, 14, 0)
|
||||||
|
)
|
||||||
|
|
||||||
//nolint:varcheck,deadcode
|
//nolint:varcheck,deadcode
|
||||||
const (
|
const (
|
||||||
|
@ -56,6 +56,10 @@ func (bts *BadBlockCache) Add(c cid.Cid, bbr BadBlockReason) {
|
|||||||
bts.badBlocks.Add(c, bbr)
|
bts.badBlocks.Add(c, bbr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bts *BadBlockCache) Remove(c cid.Cid) {
|
||||||
|
bts.badBlocks.Remove(c)
|
||||||
|
}
|
||||||
|
|
||||||
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
||||||
rval, ok := bts.badBlocks.Get(c)
|
rval, ok := bts.badBlocks.Get(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
81
chain/checkpoint.go
Normal file
81
chain/checkpoint.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var CheckpointKey = datastore.NewKey("/chain/checks")
|
||||||
|
|
||||||
|
func loadCheckpoint(ds dtypes.MetadataDS) (types.TipSetKey, error) {
|
||||||
|
haveChks, err := ds.Has(CheckpointKey)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyTSK, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !haveChks {
|
||||||
|
return types.EmptyTSK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tskBytes, err := ds.Get(CheckpointKey)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyTSK, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tsk types.TipSetKey
|
||||||
|
err = json.Unmarshal(tskBytes, &tsk)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyTSK, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tsk, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) SetCheckpoint(tsk types.TipSetKey) error {
|
||||||
|
if tsk == types.EmptyTSK {
|
||||||
|
return xerrors.Errorf("called with empty tsk")
|
||||||
|
}
|
||||||
|
|
||||||
|
syncer.checkptLk.Lock()
|
||||||
|
defer syncer.checkptLk.Unlock()
|
||||||
|
|
||||||
|
ts, err := syncer.ChainStore().LoadTipSet(tsk)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("cannot find tipset: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hts := syncer.ChainStore().GetHeaviestTipSet()
|
||||||
|
anc, err := syncer.ChainStore().IsAncestorOf(ts, hts)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("cannot determine whether checkpoint tipset is in main-chain: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hts.Equals(ts) && !anc {
|
||||||
|
return xerrors.Errorf("cannot mark tipset as checkpoint, since it isn't in the main-chain: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tskBytes, err := json.Marshal(tsk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = syncer.ds.Put(CheckpointKey, tskBytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
syncer.checkpt = tsk
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) GetCheckpoint() types.TipSetKey {
|
||||||
|
syncer.checkptLk.Lock()
|
||||||
|
defer syncer.checkptLk.Unlock()
|
||||||
|
return syncer.checkpt
|
||||||
|
}
|
@ -590,7 +590,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return publish, mp.addLocked(m, true)
|
return publish, mp.addLocked(m, !local)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||||
@ -812,7 +812,7 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mp.addLocked(msg, true); err != nil {
|
if err := mp.addLocked(msg, false); err != nil {
|
||||||
return nil, xerrors.Errorf("add locked failed: %w", err)
|
return nil, xerrors.Errorf("add locked failed: %w", err)
|
||||||
}
|
}
|
||||||
if err := mp.addLocal(msg, msgb); err != nil {
|
if err := mp.addLocal(msg, msgb); err != nil {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -56,6 +57,13 @@ func (tma *testMpoolAPI) nextBlock() *types.BlockHeader {
|
|||||||
return newBlk
|
return newBlk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tma *testMpoolAPI) nextBlockWithHeight(height uint64) *types.BlockHeader {
|
||||||
|
newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
|
||||||
|
newBlk.Height = abi.ChainEpoch(height)
|
||||||
|
tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
|
||||||
|
return newBlk
|
||||||
|
}
|
||||||
|
|
||||||
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
|
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
|
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
|
||||||
|
@ -199,9 +199,11 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
|
|||||||
gasLimit -= chainGasLimit
|
gasLimit -= chainGasLimit
|
||||||
|
|
||||||
// resort to account for already merged chains and effective performance adjustments
|
// resort to account for already merged chains and effective performance adjustments
|
||||||
sort.Slice(chains[i+1:], func(i, j int) bool {
|
// the sort *must* be stable or we end up getting negative gasPerfs pushed up.
|
||||||
|
sort.SliceStable(chains[i+1:], func(i, j int) bool {
|
||||||
return chains[i].BeforeEffective(chains[j])
|
return chains[i].BeforeEffective(chains[j])
|
||||||
})
|
})
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,8 +309,10 @@ tailLoop:
|
|||||||
|
|
||||||
// if we have gasLimit to spare, pick some random (non-negative) chains to fill the block
|
// if we have gasLimit to spare, pick some random (non-negative) chains to fill the block
|
||||||
// we pick randomly so that we minimize the probability of duplication among all miners
|
// we pick randomly so that we minimize the probability of duplication among all miners
|
||||||
startRandom := time.Now()
|
|
||||||
if gasLimit >= minGas {
|
if gasLimit >= minGas {
|
||||||
|
randomCount := 0
|
||||||
|
|
||||||
|
startRandom := time.Now()
|
||||||
shuffleChains(chains)
|
shuffleChains(chains)
|
||||||
|
|
||||||
for _, chain := range chains {
|
for _, chain := range chains {
|
||||||
@ -357,17 +361,25 @@ tailLoop:
|
|||||||
curChain := chainDeps[i]
|
curChain := chainDeps[i]
|
||||||
curChain.merged = true
|
curChain.merged = true
|
||||||
result = append(result, curChain.msgs...)
|
result = append(result, curChain.msgs...)
|
||||||
|
randomCount += len(curChain.msgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.merged = true
|
chain.merged = true
|
||||||
result = append(result, chain.msgs...)
|
result = append(result, chain.msgs...)
|
||||||
|
randomCount += len(chain.msgs)
|
||||||
gasLimit -= chainGasLimit
|
gasLimit -= chainGasLimit
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if dt := time.Since(startRandom); dt > time.Millisecond {
|
if dt := time.Since(startRandom); dt > time.Millisecond {
|
||||||
log.Infow("pack random tail chains done", "took", dt)
|
log.Infow("pack random tail chains done", "took", dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if randomCount > 0 {
|
||||||
|
log.Warnf("optimal selection failed to pack a block; picked %d messages with random selection",
|
||||||
|
randomCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -912,7 +924,9 @@ func (mc *msgChain) SetNullEffectivePerf() {
|
|||||||
|
|
||||||
func (mc *msgChain) BeforeEffective(other *msgChain) bool {
|
func (mc *msgChain) BeforeEffective(other *msgChain) bool {
|
||||||
// move merged chains to the front so we can discard them earlier
|
// move merged chains to the front so we can discard them earlier
|
||||||
return (mc.merged && !other.merged) || mc.effPerf > other.effPerf ||
|
return (mc.merged && !other.merged) ||
|
||||||
|
(mc.gasPerf >= 0 && other.gasPerf < 0) ||
|
||||||
|
mc.effPerf > other.effPerf ||
|
||||||
(mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) ||
|
(mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) ||
|
||||||
(mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
|
(mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package messagepool
|
package messagepool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
@ -1281,3 +1286,177 @@ func TestGasReward(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRealWorldSelection(t *testing.T) {
|
||||||
|
// load test-messages.json.gz and rewrite the messages so that
|
||||||
|
// 1) we map each real actor to a test actor so that we can sign the messages
|
||||||
|
// 2) adjust the nonces so that they start from 0
|
||||||
|
file, err := os.Open("test-messages.json.gz")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gzr, err := gzip.NewReader(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dec := json.NewDecoder(gzr)
|
||||||
|
|
||||||
|
var msgs []*types.SignedMessage
|
||||||
|
baseNonces := make(map[address.Address]uint64)
|
||||||
|
|
||||||
|
readLoop:
|
||||||
|
for {
|
||||||
|
m := new(types.SignedMessage)
|
||||||
|
err := dec.Decode(m)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
msgs = append(msgs, m)
|
||||||
|
nonce, ok := baseNonces[m.Message.From]
|
||||||
|
if !ok || m.Message.Nonce < nonce {
|
||||||
|
baseNonces[m.Message.From] = m.Message.Nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
case io.EOF:
|
||||||
|
break readLoop
|
||||||
|
|
||||||
|
default:
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actorMap := make(map[address.Address]address.Address)
|
||||||
|
actorWallets := make(map[address.Address]*wallet.Wallet)
|
||||||
|
|
||||||
|
for _, m := range msgs {
|
||||||
|
baseNonce := baseNonces[m.Message.From]
|
||||||
|
|
||||||
|
localActor, ok := actorMap[m.Message.From]
|
||||||
|
if !ok {
|
||||||
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actorMap[m.Message.From] = a
|
||||||
|
actorWallets[a] = w
|
||||||
|
localActor = a
|
||||||
|
}
|
||||||
|
|
||||||
|
w, ok := actorWallets[localActor]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("failed to lookup wallet for actor %s", localActor)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Message.From = localActor
|
||||||
|
m.Message.Nonce -= baseNonce
|
||||||
|
|
||||||
|
sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Signature = *sig
|
||||||
|
}
|
||||||
|
|
||||||
|
mp, tma := makeTestMpool()
|
||||||
|
|
||||||
|
block := tma.nextBlockWithHeight(build.UpgradeBreezeHeight + 10)
|
||||||
|
ts := mock.TipSet(block)
|
||||||
|
tma.applyBlock(t, block)
|
||||||
|
|
||||||
|
for _, a := range actorMap {
|
||||||
|
tma.setBalance(a, 1000000)
|
||||||
|
}
|
||||||
|
|
||||||
|
tma.baseFee = types.NewInt(800_000_000)
|
||||||
|
|
||||||
|
sort.Slice(msgs, func(i, j int) bool {
|
||||||
|
return msgs[i].Message.Nonce < msgs[j].Message.Nonce
|
||||||
|
})
|
||||||
|
|
||||||
|
// add the messages
|
||||||
|
for _, m := range msgs {
|
||||||
|
mustAdd(t, mp, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// do message selection and check block packing
|
||||||
|
minGasLimit := int64(0.9 * float64(build.BlockGasLimit))
|
||||||
|
|
||||||
|
// greedy first
|
||||||
|
selected, err := mp.SelectMessages(ts, 1.0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit := int64(0)
|
||||||
|
for _, m := range selected {
|
||||||
|
gasLimit += m.Message.GasLimit
|
||||||
|
}
|
||||||
|
if gasLimit < minGasLimit {
|
||||||
|
t.Fatalf("failed to pack with tq=1.0; packed %d, minimum packing: %d", gasLimit, minGasLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// high quality ticket
|
||||||
|
selected, err = mp.SelectMessages(ts, .8)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit = int64(0)
|
||||||
|
for _, m := range selected {
|
||||||
|
gasLimit += m.Message.GasLimit
|
||||||
|
}
|
||||||
|
if gasLimit < minGasLimit {
|
||||||
|
t.Fatalf("failed to pack with tq=0.8; packed %d, minimum packing: %d", gasLimit, minGasLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mid quality ticket
|
||||||
|
selected, err = mp.SelectMessages(ts, .4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit = int64(0)
|
||||||
|
for _, m := range selected {
|
||||||
|
gasLimit += m.Message.GasLimit
|
||||||
|
}
|
||||||
|
if gasLimit < minGasLimit {
|
||||||
|
t.Fatalf("failed to pack with tq=0.4; packed %d, minimum packing: %d", gasLimit, minGasLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// low quality ticket
|
||||||
|
selected, err = mp.SelectMessages(ts, .1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit = int64(0)
|
||||||
|
for _, m := range selected {
|
||||||
|
gasLimit += m.Message.GasLimit
|
||||||
|
}
|
||||||
|
if gasLimit < minGasLimit {
|
||||||
|
t.Fatalf("failed to pack with tq=0.1; packed %d, minimum packing: %d", gasLimit, minGasLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// very low quality ticket
|
||||||
|
selected, err = mp.SelectMessages(ts, .01)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit = int64(0)
|
||||||
|
for _, m := range selected {
|
||||||
|
gasLimit += m.Message.GasLimit
|
||||||
|
}
|
||||||
|
if gasLimit < minGasLimit {
|
||||||
|
t.Fatalf("failed to pack with tq=0.01; packed %d, minimum packing: %d", gasLimit, minGasLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
BIN
chain/messagepool/test-messages.json.gz
Normal file
BIN
chain/messagepool/test-messages.json.gz
Normal file
Binary file not shown.
@ -471,7 +471,7 @@ func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) {
|
|||||||
|
|
||||||
cur := b
|
cur := b
|
||||||
for !a.Equals(cur) && cur.Height() > a.Height() {
|
for !a.Equals(cur) && cur.Height() > a.Height() {
|
||||||
next, err := cs.LoadTipSet(b.Parents())
|
next, err := cs.LoadTipSet(cur.Parents())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,11 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||||
|
|
||||||
"github.com/Gurpartap/async"
|
"github.com/Gurpartap/async"
|
||||||
@ -129,10 +132,16 @@ type Syncer struct {
|
|||||||
windowSize int
|
windowSize int
|
||||||
|
|
||||||
tickerCtxCancel context.CancelFunc
|
tickerCtxCancel context.CancelFunc
|
||||||
|
|
||||||
|
checkptLk sync.Mutex
|
||||||
|
|
||||||
|
checkpt types.TipSetKey
|
||||||
|
|
||||||
|
ds dtypes.MetadataDS
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSyncer creates a new Syncer object.
|
// NewSyncer creates a new Syncer object.
|
||||||
func NewSyncer(sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||||
gen, err := sm.ChainStore().GetGenesis()
|
gen, err := sm.ChainStore().GetGenesis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("getting genesis block: %w", err)
|
return nil, xerrors.Errorf("getting genesis block: %w", err)
|
||||||
@ -143,7 +152,14 @@ func NewSyncer(sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cp, err := loadCheckpoint(ds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
s := &Syncer{
|
s := &Syncer{
|
||||||
|
ds: ds,
|
||||||
|
checkpt: cp,
|
||||||
beacon: beacon,
|
beacon: beacon,
|
||||||
bad: NewBadBlockCache(),
|
bad: NewBadBlockCache(),
|
||||||
Genesis: gent,
|
Genesis: gent,
|
||||||
@ -1361,7 +1377,7 @@ loop:
|
|||||||
log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", incoming.Cids(), incoming.Height(), known.Cids(), known.Height())
|
log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", incoming.Cids(), incoming.Height(), known.Cids(), known.Height())
|
||||||
fork, err := syncer.syncFork(ctx, base, known)
|
fork, err := syncer.syncFork(ctx, base, known)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, ErrForkTooLong) {
|
if xerrors.Is(err, ErrForkTooLong) || xerrors.Is(err, ErrForkCheckpoint) {
|
||||||
// TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish?
|
// TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish?
|
||||||
log.Warn("adding forked chain to our bad tipset cache")
|
log.Warn("adding forked chain to our bad tipset cache")
|
||||||
for _, b := range incoming.Blocks() {
|
for _, b := range incoming.Blocks() {
|
||||||
@ -1377,14 +1393,23 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
|
var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
|
||||||
|
var ErrForkCheckpoint = fmt.Errorf("fork would require us to diverge from checkpointed block")
|
||||||
|
|
||||||
// syncFork tries to obtain the chain fragment that links a fork into a common
|
// syncFork tries to obtain the chain fragment that links a fork into a common
|
||||||
// ancestor in our view of the chain.
|
// ancestor in our view of the chain.
|
||||||
//
|
//
|
||||||
// If the fork is too long (build.ForkLengthThreshold), we add the entire subchain to the
|
// If the fork is too long (build.ForkLengthThreshold), or would cause us to diverge from the checkpoint (ErrForkCheckpoint),
|
||||||
// denylist. Else, we find the common ancestor, and add the missing chain
|
// we add the entire subchain to the denylist. Else, we find the common ancestor, and add the missing chain
|
||||||
// fragment until the fork point to the returned []TipSet.
|
// fragment until the fork point to the returned []TipSet.
|
||||||
func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) {
|
func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) {
|
||||||
|
|
||||||
|
chkpt := syncer.GetCheckpoint()
|
||||||
|
if known.Key() == chkpt {
|
||||||
|
return nil, ErrForkCheckpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Does this mean we always ask for ForkLengthThreshold blocks from the network, even if we just need, like, 2?
|
||||||
|
// Would it not be better to ask in smaller chunks, given that an ~ForkLengthThreshold is very rare?
|
||||||
tips, err := syncer.Exchange.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold))
|
tips, err := syncer.Exchange.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1410,12 +1435,18 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know
|
|||||||
if nts.Height() < tips[cur].Height() {
|
if nts.Height() < tips[cur].Height() {
|
||||||
cur++
|
cur++
|
||||||
} else {
|
} else {
|
||||||
|
// We will be forking away from nts, check that it isn't checkpointed
|
||||||
|
if nts.Key() == chkpt {
|
||||||
|
return nil, ErrForkCheckpoint
|
||||||
|
}
|
||||||
|
|
||||||
nts, err = syncer.store.LoadTipSet(nts.Parents())
|
nts, err = syncer.store.LoadTipSet(nts.Parents())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("loading next local tipset: %w", err)
|
return nil, xerrors.Errorf("loading next local tipset: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrForkTooLong
|
return nil, ErrForkTooLong
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1644,6 +1675,11 @@ func (syncer *Syncer) MarkBad(blk cid.Cid) {
|
|||||||
syncer.bad.Add(blk, NewBadBlockReason([]cid.Cid{blk}, "manually marked bad"))
|
syncer.bad.Add(blk, NewBadBlockReason([]cid.Cid{blk}, "manually marked bad"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarkBad manually adds a block to the "bad blocks" cache.
|
||||||
|
func (syncer *Syncer) UnmarkBad(blk cid.Cid) {
|
||||||
|
syncer.bad.Remove(blk)
|
||||||
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||||
bbr, ok := syncer.bad.Has(blk)
|
bbr, ok := syncer.bad.Has(blk)
|
||||||
return bbr.String(), ok
|
return bbr.String(), ok
|
||||||
|
@ -333,6 +333,36 @@ func (tu *syncTestUtil) compareSourceState(with int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tu *syncTestUtil) assertBad(node int, ts *types.TipSet) {
|
||||||
|
for _, blk := range ts.Cids() {
|
||||||
|
rsn, err := tu.nds[node].SyncCheckBad(context.TODO(), blk)
|
||||||
|
require.NoError(tu.t, err)
|
||||||
|
require.True(tu.t, len(rsn) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tu *syncTestUtil) getHead(node int) *types.TipSet {
|
||||||
|
ts, err := tu.nds[node].ChainHead(context.TODO())
|
||||||
|
require.NoError(tu.t, err)
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tu *syncTestUtil) checkpointTs(node int, tsk types.TipSetKey) {
|
||||||
|
require.NoError(tu.t, tu.nds[node].SyncCheckpoint(context.TODO(), tsk))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tu *syncTestUtil) waitUntilNodeHasTs(node int, tsk types.TipSetKey) {
|
||||||
|
for {
|
||||||
|
_, err := tu.nds[node].ChainGetTipSet(context.TODO(), tsk)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time to allow for syncing and validation
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
func (tu *syncTestUtil) waitUntilSync(from, to int) {
|
func (tu *syncTestUtil) waitUntilSync(from, to int) {
|
||||||
target, err := tu.nds[from].ChainHead(tu.ctx)
|
target, err := tu.nds[from].ChainHead(tu.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -678,3 +708,87 @@ func TestSyncInputs(t *testing.T) {
|
|||||||
t.Fatal("should error on block with nil election proof")
|
t.Fatal("should error on block with nil election proof")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSyncCheckpointHead(t *testing.T) {
|
||||||
|
H := 10
|
||||||
|
tu := prepSyncTest(t, H)
|
||||||
|
|
||||||
|
p1 := tu.addClientNode()
|
||||||
|
p2 := tu.addClientNode()
|
||||||
|
|
||||||
|
fmt.Println("GENESIS: ", tu.g.Genesis().Cid())
|
||||||
|
tu.loadChainToNode(p1)
|
||||||
|
tu.loadChainToNode(p2)
|
||||||
|
|
||||||
|
base := tu.g.CurTipset
|
||||||
|
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
||||||
|
|
||||||
|
// The two nodes fork at this point into 'a' and 'b'
|
||||||
|
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil)
|
||||||
|
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil)
|
||||||
|
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil)
|
||||||
|
|
||||||
|
tu.waitUntilSyncTarget(p1, a.TipSet())
|
||||||
|
tu.checkpointTs(p1, a.TipSet().Key())
|
||||||
|
|
||||||
|
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||||
|
// chain B will now be heaviest
|
||||||
|
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil)
|
||||||
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||||
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||||
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||||
|
|
||||||
|
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
||||||
|
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
||||||
|
|
||||||
|
// Now for the fun part!! p1 should mark p2's head as BAD.
|
||||||
|
|
||||||
|
require.NoError(t, tu.mn.LinkAll())
|
||||||
|
tu.connect(p1, p2)
|
||||||
|
tu.waitUntilNodeHasTs(p1, b.TipSet().Key())
|
||||||
|
p1Head := tu.getHead(p1)
|
||||||
|
require.Equal(tu.t, p1Head, a.TipSet())
|
||||||
|
tu.assertBad(p1, b.TipSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSyncCheckpointEarlierThanHead(t *testing.T) {
|
||||||
|
H := 10
|
||||||
|
tu := prepSyncTest(t, H)
|
||||||
|
|
||||||
|
p1 := tu.addClientNode()
|
||||||
|
p2 := tu.addClientNode()
|
||||||
|
|
||||||
|
fmt.Println("GENESIS: ", tu.g.Genesis().Cid())
|
||||||
|
tu.loadChainToNode(p1)
|
||||||
|
tu.loadChainToNode(p2)
|
||||||
|
|
||||||
|
base := tu.g.CurTipset
|
||||||
|
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
||||||
|
|
||||||
|
// The two nodes fork at this point into 'a' and 'b'
|
||||||
|
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil)
|
||||||
|
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil)
|
||||||
|
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil)
|
||||||
|
|
||||||
|
tu.waitUntilSyncTarget(p1, a.TipSet())
|
||||||
|
tu.checkpointTs(p1, a1.TipSet().Key())
|
||||||
|
|
||||||
|
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||||
|
// chain B will now be heaviest
|
||||||
|
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil)
|
||||||
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||||
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||||
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||||
|
|
||||||
|
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
||||||
|
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
||||||
|
|
||||||
|
// Now for the fun part!! p1 should mark p2's head as BAD.
|
||||||
|
|
||||||
|
require.NoError(t, tu.mn.LinkAll())
|
||||||
|
tu.connect(p1, p2)
|
||||||
|
tu.waitUntilNodeHasTs(p1, b.TipSet().Key())
|
||||||
|
p1Head := tu.getHead(p1)
|
||||||
|
require.Equal(tu.t, p1Head, a.TipSet())
|
||||||
|
tu.assertBad(p1, b.TipSet())
|
||||||
|
}
|
||||||
|
19
cli/chain.go
19
cli/chain.go
@ -337,25 +337,6 @@ var chainSetHeadCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) {
|
|
||||||
var headers []*types.BlockHeader
|
|
||||||
for _, c := range vals {
|
|
||||||
blkc, err := cid.Decode(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bh, err := api.ChainGetBlock(ctx, blkc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
headers = append(headers, bh)
|
|
||||||
}
|
|
||||||
|
|
||||||
return types.NewTipSet(headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
var chainListCmd = &cli.Command{
|
var chainListCmd = &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "View a segment of the chain",
|
Usage: "View a segment of the chain",
|
||||||
|
86
cli/mpool.go
86
cli/mpool.go
@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
stdbig "math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
lapi "github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
@ -29,6 +31,7 @@ var mpoolCmd = &cli.Command{
|
|||||||
mpoolReplaceCmd,
|
mpoolReplaceCmd,
|
||||||
mpoolFindCmd,
|
mpoolFindCmd,
|
||||||
mpoolConfig,
|
mpoolConfig,
|
||||||
|
mpoolGasPerfCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,3 +519,86 @@ var mpoolConfig = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mpoolGasPerfCmd = &cli.Command{
|
||||||
|
Name: "gas-perf",
|
||||||
|
Usage: "Check gas performance of messages in mempool",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "all",
|
||||||
|
Usage: "print gas performance for all mempool messages (default only prints for local)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msgs, err := api.MpoolPending(ctx, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var filter map[address.Address]struct{}
|
||||||
|
if !cctx.Bool("all") {
|
||||||
|
filter = map[address.Address]struct{}{}
|
||||||
|
|
||||||
|
addrss, err := api.WalletList(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting local addresses: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range addrss {
|
||||||
|
filter[a] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var filtered []*types.SignedMessage
|
||||||
|
for _, msg := range msgs {
|
||||||
|
if _, has := filter[msg.Message.From]; !has {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filtered = append(filtered, msg)
|
||||||
|
}
|
||||||
|
msgs = filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err := api.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get chain head: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseFee := ts.Blocks()[0].ParentBaseFee
|
||||||
|
|
||||||
|
bigBlockGasLimit := big.NewInt(build.BlockGasLimit)
|
||||||
|
|
||||||
|
getGasReward := func(msg *types.SignedMessage) big.Int {
|
||||||
|
maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee)
|
||||||
|
if types.BigCmp(maxPremium, msg.Message.GasPremium) < 0 {
|
||||||
|
maxPremium = msg.Message.GasPremium
|
||||||
|
}
|
||||||
|
return types.BigMul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit)))
|
||||||
|
}
|
||||||
|
|
||||||
|
getGasPerf := func(gasReward big.Int, gasLimit int64) float64 {
|
||||||
|
// gasPerf = gasReward * build.BlockGasLimit / gasLimit
|
||||||
|
a := new(stdbig.Rat).SetInt(new(stdbig.Int).Mul(gasReward.Int, bigBlockGasLimit.Int))
|
||||||
|
b := stdbig.NewRat(1, gasLimit)
|
||||||
|
c := new(stdbig.Rat).Mul(a, b)
|
||||||
|
r, _ := c.Float64()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range msgs {
|
||||||
|
gasReward := getGasReward(m)
|
||||||
|
gasPerf := getGasPerf(gasReward, m.Message.GasLimit)
|
||||||
|
|
||||||
|
fmt.Printf("%s\t%d\t%s\t%f\n", m.Message.From, m.Message.Nonce, gasReward, gasPerf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
300
cli/multisig.go
300
cli/multisig.go
@ -37,9 +37,13 @@ var multisigCmd = &cli.Command{
|
|||||||
msigInspectCmd,
|
msigInspectCmd,
|
||||||
msigProposeCmd,
|
msigProposeCmd,
|
||||||
msigApproveCmd,
|
msigApproveCmd,
|
||||||
|
msigAddProposeCmd,
|
||||||
|
msigAddApproveCmd,
|
||||||
|
msigAddCancelCmd,
|
||||||
msigSwapProposeCmd,
|
msigSwapProposeCmd,
|
||||||
msigSwapApproveCmd,
|
msigSwapApproveCmd,
|
||||||
msigSwapCancelCmd,
|
msigSwapCancelCmd,
|
||||||
|
msigVestedCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,6 +510,236 @@ var msigApproveCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msigAddProposeCmd = &cli.Command{
|
||||||
|
Name: "add-propose",
|
||||||
|
Usage: "Propose to add a signer",
|
||||||
|
ArgsUsage: "[multisigAddress signer]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "increase-threshold",
|
||||||
|
Usage: "whether the number of required signers should be increased",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "from",
|
||||||
|
Usage: "account to send the propose message from",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 2 {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("must pass multisig address and signer address"))
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := address.NewFromString(cctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var from address.Address
|
||||||
|
if cctx.IsSet("from") {
|
||||||
|
f, err := address.NewFromString(cctx.String("from"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
from = f
|
||||||
|
} else {
|
||||||
|
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
from = defaddr
|
||||||
|
}
|
||||||
|
|
||||||
|
msgCid, err := api.MsigAddPropose(ctx, msig, from, addr, cctx.Bool("increase-threshold"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("sent add proposal in message: ", msgCid)
|
||||||
|
|
||||||
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if wait.Receipt.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("add proposal returned exit %d", wait.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var msigAddApproveCmd = &cli.Command{
|
||||||
|
Name: "add-approve",
|
||||||
|
Usage: "Approve a message to add a signer",
|
||||||
|
ArgsUsage: "[multisigAddress proposerAddress txId newAddress increaseThreshold]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "from",
|
||||||
|
Usage: "account to send the approve message from",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 5 {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("must pass multisig address, proposer address, transaction id, new signer address, whether to increase threshold"))
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
prop, err := address.NewFromString(cctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
txid, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newAdd, err := address.NewFromString(cctx.Args().Get(3))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inc, err := strconv.ParseBool(cctx.Args().Get(4))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var from address.Address
|
||||||
|
if cctx.IsSet("from") {
|
||||||
|
f, err := address.NewFromString(cctx.String("from"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
from = f
|
||||||
|
} else {
|
||||||
|
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
from = defaddr
|
||||||
|
}
|
||||||
|
|
||||||
|
msgCid, err := api.MsigAddApprove(ctx, msig, from, txid, prop, newAdd, inc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("sent add approval in message: ", msgCid)
|
||||||
|
|
||||||
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if wait.Receipt.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("add approval returned exit %d", wait.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var msigAddCancelCmd = &cli.Command{
|
||||||
|
Name: "add-cancel",
|
||||||
|
Usage: "Cancel a message to add a signer",
|
||||||
|
ArgsUsage: "[multisigAddress txId newAddress increaseThreshold]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "from",
|
||||||
|
Usage: "account to send the approve message from",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 4 {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("must pass multisig address, transaction id, new signer address, whether to increase threshold"))
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newAdd, err := address.NewFromString(cctx.Args().Get(2))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inc, err := strconv.ParseBool(cctx.Args().Get(3))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var from address.Address
|
||||||
|
if cctx.IsSet("from") {
|
||||||
|
f, err := address.NewFromString(cctx.String("from"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
from = f
|
||||||
|
} else {
|
||||||
|
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
from = defaddr
|
||||||
|
}
|
||||||
|
|
||||||
|
msgCid, err := api.MsigAddCancel(ctx, msig, from, txid, newAdd, inc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("sent add cancellation in message: ", msgCid)
|
||||||
|
|
||||||
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if wait.Receipt.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("add cancellation returned exit %d", wait.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var msigSwapProposeCmd = &cli.Command{
|
var msigSwapProposeCmd = &cli.Command{
|
||||||
Name: "swap-propose",
|
Name: "swap-propose",
|
||||||
Usage: "Propose to swap signers",
|
Usage: "Propose to swap signers",
|
||||||
@ -722,7 +956,7 @@ var msigSwapCancelCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("sent swap approval in message: ", msgCid)
|
fmt.Println("sent swap cancellation in message: ", msgCid)
|
||||||
|
|
||||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -730,9 +964,71 @@ var msigSwapCancelCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if wait.Receipt.ExitCode != 0 {
|
if wait.Receipt.ExitCode != 0 {
|
||||||
return fmt.Errorf("swap approval returned exit %d", wait.Receipt.ExitCode)
|
return fmt.Errorf("swap cancellation returned exit %d", wait.Receipt.ExitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msigVestedCmd = &cli.Command{
|
||||||
|
Name: "vested",
|
||||||
|
Usage: "Gets the amount vested in an msig between two epochs",
|
||||||
|
ArgsUsage: "[multisigAddress]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.Int64Flag{
|
||||||
|
Name: "start-epoch",
|
||||||
|
Usage: "start epoch to measure vesting from",
|
||||||
|
Value: 0,
|
||||||
|
},
|
||||||
|
&cli.Int64Flag{
|
||||||
|
Name: "end-epoch",
|
||||||
|
Usage: "end epoch to stop measure vesting at",
|
||||||
|
Value: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 1 {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("must pass multisig address"))
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
start, err := api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("start-epoch")), types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var end *types.TipSet
|
||||||
|
if cctx.Int64("end-epoch") < 0 {
|
||||||
|
end, err = LoadTipSet(ctx, cctx, api)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
end, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("end-epoch")), types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := api.MsigGetVested(ctx, msig, start.Key(), end.Key())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Vested: %s between %d and %d\n", types.FIL(ret), start.Height(), end.Height())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
71
cli/sync.go
71
cli/sync.go
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@ -20,7 +22,9 @@ var syncCmd = &cli.Command{
|
|||||||
syncStatusCmd,
|
syncStatusCmd,
|
||||||
syncWaitCmd,
|
syncWaitCmd,
|
||||||
syncMarkBadCmd,
|
syncMarkBadCmd,
|
||||||
|
syncUnmarkBadCmd,
|
||||||
syncCheckBadCmd,
|
syncCheckBadCmd,
|
||||||
|
syncCheckpointCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +121,31 @@ var syncMarkBadCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var syncUnmarkBadCmd = &cli.Command{
|
||||||
|
Name: "unmark-bad",
|
||||||
|
Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it",
|
||||||
|
ArgsUsage: "[blockCid]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
napi, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
if !cctx.Args().Present() {
|
||||||
|
return fmt.Errorf("must specify block cid to unmark")
|
||||||
|
}
|
||||||
|
|
||||||
|
bcid, err := cid.Decode(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode input as a cid: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return napi.SyncUnmarkBad(ctx, bcid)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var syncCheckBadCmd = &cli.Command{
|
var syncCheckBadCmd = &cli.Command{
|
||||||
Name: "check-bad",
|
Name: "check-bad",
|
||||||
Usage: "check if the given block was marked bad, and for what reason",
|
Usage: "check if the given block was marked bad, and for what reason",
|
||||||
@ -153,6 +182,48 @@ var syncCheckBadCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var syncCheckpointCmd = &cli.Command{
|
||||||
|
Name: "checkpoint",
|
||||||
|
Usage: "mark a certain tipset as checkpointed; the node will never fork away from this tipset",
|
||||||
|
ArgsUsage: "[tipsetKey]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.Uint64Flag{
|
||||||
|
Name: "epoch",
|
||||||
|
Usage: "checkpoint the tipset at the given epoch",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
napi, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
var ts *types.TipSet
|
||||||
|
|
||||||
|
if cctx.IsSet("epoch") {
|
||||||
|
ts, err = napi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), types.EmptyTSK)
|
||||||
|
}
|
||||||
|
if ts == nil {
|
||||||
|
ts, err = parseTipSet(ctx, napi, cctx.Args().Slice())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ts == nil {
|
||||||
|
return fmt.Errorf("must pass cids for tipset to set as head, or specify epoch flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := napi.SyncCheckpoint(ctx, ts.Key()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func SyncWait(ctx context.Context, napi api.FullNode) error {
|
func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||||
for {
|
for {
|
||||||
state, err := napi.SyncState(ctx)
|
state, err := napi.SyncState(ctx)
|
||||||
|
28
cli/util.go
Normal file
28
cli/util.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) {
|
||||||
|
var headers []*types.BlockHeader
|
||||||
|
for _, c := range vals {
|
||||||
|
blkc, err := cid.Decode(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bh, err := api.ChainGetBlock(ctx, blkc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = append(headers, bh)
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewTipSet(headers)
|
||||||
|
}
|
@ -694,7 +694,7 @@ func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, events chan<- *MinerSectorsEvent) error {
|
func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, events chan<- *MinerSectorsEvent) error {
|
||||||
prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.tsKey)
|
prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.parentTsKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ const FlagWorkerRepo = "worker-repo"
|
|||||||
const FlagWorkerRepoDeprecation = "workerrepo"
|
const FlagWorkerRepoDeprecation = "workerrepo"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
build.RunningNodeType = build.NodeWorker
|
||||||
|
|
||||||
lotuslog.SetupLogLevels()
|
lotuslog.SetupLogLevels()
|
||||||
|
|
||||||
local := []*cli.Command{
|
local := []*cli.Command{
|
||||||
@ -187,8 +189,8 @@ var runCmd = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if v.APIVersion != build.APIVersion {
|
if v.APIVersion != build.MinerAPIVersion {
|
||||||
return xerrors.Errorf("lotus-miner API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion})
|
return xerrors.Errorf("lotus-miner API version doesn't match: expected: %s", api.Version{APIVersion: build.MinerAPIVersion})
|
||||||
}
|
}
|
||||||
log.Infof("Remote version %s", v)
|
log.Infof("Remote version %s", v)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ type worker struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) Version(context.Context) (build.Version, error) {
|
func (w *worker) Version(context.Context) (build.Version, error) {
|
||||||
return build.APIVersion, nil
|
return build.WorkerAPIVersion, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) StorageAddLocal(ctx context.Context, path string) error {
|
func (w *worker) StorageAddLocal(ctx context.Context, path string) error {
|
||||||
|
@ -33,6 +33,7 @@ func main() {
|
|||||||
mpoolCmd,
|
mpoolCmd,
|
||||||
genesisVerifyCmd,
|
genesisVerifyCmd,
|
||||||
mathCmd,
|
mathCmd,
|
||||||
|
mpoolStatsCmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
|
273
cmd/lotus-shed/mempool-stats.go
Normal file
273
cmd/lotus-shed/mempool-stats.go
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"contrib.go.opencensus.io/exporter/prometheus"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
logging "github.com/ipfs/go-log"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"go.opencensus.io/stats"
|
||||||
|
"go.opencensus.io/stats/view"
|
||||||
|
"go.opencensus.io/tag"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MpoolAge = stats.Float64("mpoolage", "Age of messages in the mempool", stats.UnitSeconds)
|
||||||
|
MpoolSize = stats.Int64("mpoolsize", "Number of messages in mempool", stats.UnitDimensionless)
|
||||||
|
MpoolInboundRate = stats.Int64("inbound", "Counter for inbound messages", stats.UnitDimensionless)
|
||||||
|
BlockInclusionRate = stats.Int64("inclusion", "Counter for message included in blocks", stats.UnitDimensionless)
|
||||||
|
MsgWaitTime = stats.Float64("msg-wait-time", "Wait time of messages to make it into a block", stats.UnitSeconds)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
LeTag, _ = tag.NewKey("quantile")
|
||||||
|
MTTag, _ = tag.NewKey("msg_type")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
AgeView = &view.View{
|
||||||
|
Name: "mpool-age",
|
||||||
|
Measure: MpoolAge,
|
||||||
|
TagKeys: []tag.Key{LeTag, MTTag},
|
||||||
|
Aggregation: view.LastValue(),
|
||||||
|
}
|
||||||
|
SizeView = &view.View{
|
||||||
|
Name: "mpool-size",
|
||||||
|
Measure: MpoolSize,
|
||||||
|
TagKeys: []tag.Key{MTTag},
|
||||||
|
Aggregation: view.LastValue(),
|
||||||
|
}
|
||||||
|
InboundRate = &view.View{
|
||||||
|
Name: "msg-inbound",
|
||||||
|
Measure: MpoolInboundRate,
|
||||||
|
TagKeys: []tag.Key{MTTag},
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
InclusionRate = &view.View{
|
||||||
|
Name: "msg-inclusion",
|
||||||
|
Measure: BlockInclusionRate,
|
||||||
|
TagKeys: []tag.Key{MTTag},
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
MsgWait = &view.View{
|
||||||
|
Name: "msg-wait",
|
||||||
|
Measure: MsgWaitTime,
|
||||||
|
TagKeys: []tag.Key{MTTag},
|
||||||
|
Aggregation: view.Distribution(10, 30, 60, 120, 240, 600, 1800, 3600),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type msgInfo struct {
|
||||||
|
msg *types.SignedMessage
|
||||||
|
seen time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
var mpoolStatsCmd = &cli.Command{
|
||||||
|
Name: "mpool-stats",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
logging.SetLogLevel("rpc", "ERROR")
|
||||||
|
|
||||||
|
if err := view.Register(AgeView, SizeView, InboundRate, InclusionRate, MsgWait); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
expo, err := prometheus.NewExporter(prometheus.Options{
|
||||||
|
Namespace: "lotusmpool",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Handle("/debug/metrics", expo)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := http.ListenAndServe(":10555", nil); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer closer()
|
||||||
|
ctx := lcli.ReqContext(cctx)
|
||||||
|
|
||||||
|
updates, err := api.MpoolSub(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mcache := make(map[address.Address]bool)
|
||||||
|
isMiner := func(addr address.Address) (bool, error) {
|
||||||
|
cache, ok := mcache[addr]
|
||||||
|
if ok {
|
||||||
|
return cache, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
act, err := api.StateGetActor(ctx, addr, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ism := act.Code == builtin.StorageMinerActorCodeID
|
||||||
|
mcache[addr] = ism
|
||||||
|
return ism, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wpostTracker := make(map[cid.Cid]*msgInfo)
|
||||||
|
tracker := make(map[cid.Cid]*msgInfo)
|
||||||
|
tick := time.Tick(time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case u, ok := <-updates:
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("connection with lotus node broke")
|
||||||
|
}
|
||||||
|
switch u.Type {
|
||||||
|
case lapi.MpoolAdd:
|
||||||
|
stats.Record(ctx, MpoolInboundRate.M(1))
|
||||||
|
tracker[u.Message.Cid()] = &msgInfo{
|
||||||
|
msg: u.Message,
|
||||||
|
seen: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Message.Message.Method == builtin.MethodsMiner.SubmitWindowedPoSt {
|
||||||
|
|
||||||
|
miner, err := isMiner(u.Message.Message.To)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to determine if message target was to a miner: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if miner {
|
||||||
|
wpostTracker[u.Message.Cid()] = &msgInfo{
|
||||||
|
msg: u.Message,
|
||||||
|
seen: time.Now(),
|
||||||
|
}
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolInboundRate.M(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case lapi.MpoolRemove:
|
||||||
|
mi, ok := tracker[u.Message.Cid()]
|
||||||
|
if ok {
|
||||||
|
fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium)
|
||||||
|
stats.Record(ctx, BlockInclusionRate.M(1))
|
||||||
|
stats.Record(ctx, MsgWaitTime.M(time.Since(mi.seen).Seconds()))
|
||||||
|
delete(tracker, u.Message.Cid())
|
||||||
|
}
|
||||||
|
|
||||||
|
wm, ok := wpostTracker[u.Message.Cid()]
|
||||||
|
if ok {
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, BlockInclusionRate.M(1))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MsgWaitTime.M(time.Since(wm.seen).Seconds()))
|
||||||
|
delete(wpostTracker, u.Message.Cid())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unrecognized mpool update state: %d", u.Type)
|
||||||
|
}
|
||||||
|
case <-tick:
|
||||||
|
var ages []time.Duration
|
||||||
|
if len(tracker) > 0 {
|
||||||
|
for _, v := range tracker {
|
||||||
|
age := time.Since(v.seen)
|
||||||
|
ages = append(ages, age)
|
||||||
|
}
|
||||||
|
|
||||||
|
st := ageStats(ages)
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds()))
|
||||||
|
|
||||||
|
stats.Record(ctx, MpoolSize.M(int64(len(tracker))))
|
||||||
|
fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95)
|
||||||
|
}
|
||||||
|
|
||||||
|
var wpages []time.Duration
|
||||||
|
if len(wpostTracker) > 0 {
|
||||||
|
for _, v := range wpostTracker {
|
||||||
|
age := time.Since(v.seen)
|
||||||
|
wpages = append(wpages, age)
|
||||||
|
}
|
||||||
|
|
||||||
|
st := ageStats(wpages)
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc40.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc50.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc60.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc70.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc80.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc90.Seconds()))
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc95.Seconds()))
|
||||||
|
|
||||||
|
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolSize.M(int64(len(wpostTracker))))
|
||||||
|
fmt.Printf("%d wpost messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type ageStat struct {
|
||||||
|
Average time.Duration
|
||||||
|
Max time.Duration
|
||||||
|
Perc40 time.Duration
|
||||||
|
Perc50 time.Duration
|
||||||
|
Perc60 time.Duration
|
||||||
|
Perc70 time.Duration
|
||||||
|
Perc80 time.Duration
|
||||||
|
Perc90 time.Duration
|
||||||
|
Perc95 time.Duration
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ageStats(ages []time.Duration) *ageStat {
|
||||||
|
sort.Slice(ages, func(i, j int) bool {
|
||||||
|
return ages[i] < ages[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
st := ageStat{
|
||||||
|
Count: len(ages),
|
||||||
|
}
|
||||||
|
var sum time.Duration
|
||||||
|
for _, a := range ages {
|
||||||
|
sum += a
|
||||||
|
if a > st.Max {
|
||||||
|
st.Max = a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st.Average = sum / time.Duration(len(ages))
|
||||||
|
|
||||||
|
p40 := (4 * len(ages)) / 10
|
||||||
|
p50 := len(ages) / 2
|
||||||
|
p60 := (6 * len(ages)) / 10
|
||||||
|
p70 := (7 * len(ages)) / 10
|
||||||
|
p80 := (4 * len(ages)) / 5
|
||||||
|
p90 := (9 * len(ages)) / 10
|
||||||
|
p95 := (19 * len(ages)) / 20
|
||||||
|
|
||||||
|
st.Perc40 = ages[p40]
|
||||||
|
st.Perc50 = ages[p50]
|
||||||
|
st.Perc60 = ages[p60]
|
||||||
|
st.Perc70 = ages[p70]
|
||||||
|
st.Perc80 = ages[p80]
|
||||||
|
st.Perc90 = ages[p90]
|
||||||
|
st.Perc95 = ages[p95]
|
||||||
|
|
||||||
|
return &st
|
||||||
|
}
|
@ -179,8 +179,8 @@ var initCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v.APIVersion.EqMajorMinor(build.APIVersion) {
|
if !v.APIVersion.EqMajorMinor(build.FullAPIVersion) {
|
||||||
return xerrors.Errorf("Remote API version didn't match (local %s, remote %s)", build.APIVersion, v.APIVersion)
|
return xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", build.FullAPIVersion, v.APIVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Initializing repo")
|
log.Info("Initializing repo")
|
||||||
|
@ -26,6 +26,8 @@ const FlagMinerRepo = "miner-repo"
|
|||||||
const FlagMinerRepoDeprecation = "storagerepo"
|
const FlagMinerRepoDeprecation = "storagerepo"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
build.RunningNodeType = build.NodeMiner
|
||||||
|
|
||||||
lotuslog.SetupLogLevels()
|
lotuslog.SetupLogLevels()
|
||||||
|
|
||||||
local := []*cli.Command{
|
local := []*cli.Command{
|
||||||
|
@ -77,8 +77,8 @@ var runCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.APIVersion != build.APIVersion {
|
if v.APIVersion != build.FullAPIVersion {
|
||||||
return xerrors.Errorf("lotus-daemon API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion})
|
return xerrors.Errorf("lotus-daemon API version doesn't match: expected: %s", api.Version{APIVersion: build.FullAPIVersion})
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Checking full node sync status")
|
log.Info("Checking full node sync status")
|
||||||
|
@ -16,6 +16,8 @@ import (
|
|||||||
var AdvanceBlockCmd *cli.Command
|
var AdvanceBlockCmd *cli.Command
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
build.RunningNodeType = build.NodeFull
|
||||||
|
|
||||||
lotuslog.SetupLogLevels()
|
lotuslog.SetupLogLevels()
|
||||||
|
|
||||||
local := []*cli.Command{
|
local := []*cli.Command{
|
||||||
|
@ -62,6 +62,9 @@ const (
|
|||||||
// MethodMutateState is the identifier for the method that attempts to mutate
|
// MethodMutateState is the identifier for the method that attempts to mutate
|
||||||
// a state value in the actor.
|
// a state value in the actor.
|
||||||
MethodMutateState
|
MethodMutateState
|
||||||
|
// MethodAbortWith is the identifier for the method that panics optionally with
|
||||||
|
// a passed exit code.
|
||||||
|
MethodAbortWith
|
||||||
)
|
)
|
||||||
|
|
||||||
// Exports defines the methods this actor exposes publicly.
|
// Exports defines the methods this actor exposes publicly.
|
||||||
@ -74,6 +77,7 @@ func (a Actor) Exports() []interface{} {
|
|||||||
MethodDeleteActor: a.DeleteActor,
|
MethodDeleteActor: a.DeleteActor,
|
||||||
MethodSend: a.Send,
|
MethodSend: a.Send,
|
||||||
MethodMutateState: a.MutateState,
|
MethodMutateState: a.MutateState,
|
||||||
|
MethodAbortWith: a.AbortWith,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,3 +234,21 @@ func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.Empty
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AbortWithArgs are the arguments to the Actor.AbortWith method, specifying the
|
||||||
|
// exit code to (optionally) abort with and the message.
|
||||||
|
type AbortWithArgs struct {
|
||||||
|
Code exitcode.ExitCode
|
||||||
|
Message string
|
||||||
|
Uncontrolled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbortWith simply causes a panic with the passed exit code.
|
||||||
|
func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *adt.EmptyValue {
|
||||||
|
if args.Uncontrolled { // uncontrolled abort: directly panic
|
||||||
|
panic(args.Message)
|
||||||
|
} else {
|
||||||
|
rt.Abortf(args.Code, args.Message)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -614,3 +614,119 @@ func (t *MutateStateArgs) UnmarshalCBOR(r io.Reader) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lengthBufAbortWithArgs = []byte{131}
|
||||||
|
|
||||||
|
func (t *AbortWithArgs) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write(lengthBufAbortWithArgs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch := make([]byte, 9)
|
||||||
|
|
||||||
|
// t.Code (exitcode.ExitCode) (int64)
|
||||||
|
if t.Code >= 0 {
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Code)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Code-1)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Message (string) (string)
|
||||||
|
if len(t.Message) > cbg.MaxLength {
|
||||||
|
return xerrors.Errorf("Value in field t.Message was too long")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Message))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.WriteString(w, string(t.Message)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Uncontrolled (bool) (bool)
|
||||||
|
if err := cbg.WriteBool(w, t.Uncontrolled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
*t = AbortWithArgs{}
|
||||||
|
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
scratch := make([]byte, 8)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 3 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Code (exitcode.ExitCode) (int64)
|
||||||
|
{
|
||||||
|
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
var extraI int64
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch maj {
|
||||||
|
case cbg.MajUnsignedInt:
|
||||||
|
extraI = int64(extra)
|
||||||
|
if extraI < 0 {
|
||||||
|
return fmt.Errorf("int64 positive overflow")
|
||||||
|
}
|
||||||
|
case cbg.MajNegativeInt:
|
||||||
|
extraI = int64(extra)
|
||||||
|
if extraI < 0 {
|
||||||
|
return fmt.Errorf("int64 negative oveflow")
|
||||||
|
}
|
||||||
|
extraI = -1 - extraI
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Code = exitcode.ExitCode(extraI)
|
||||||
|
}
|
||||||
|
// t.Message (string) (string)
|
||||||
|
|
||||||
|
{
|
||||||
|
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Message = string(sval)
|
||||||
|
}
|
||||||
|
// t.Uncontrolled (bool) (bool)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajOther {
|
||||||
|
return fmt.Errorf("booleans must be major type 7")
|
||||||
|
}
|
||||||
|
switch extra {
|
||||||
|
case 20:
|
||||||
|
t.Uncontrolled = false
|
||||||
|
case 21:
|
||||||
|
t.Uncontrolled = true
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ func main() {
|
|||||||
chaos.SendArgs{},
|
chaos.SendArgs{},
|
||||||
chaos.SendReturn{},
|
chaos.SendReturn{},
|
||||||
chaos.MutateStateArgs{},
|
chaos.MutateStateArgs{},
|
||||||
|
chaos.AbortWithArgs{},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -75,10 +75,14 @@
|
|||||||
* [MpoolSetConfig](#MpoolSetConfig)
|
* [MpoolSetConfig](#MpoolSetConfig)
|
||||||
* [MpoolSub](#MpoolSub)
|
* [MpoolSub](#MpoolSub)
|
||||||
* [Msig](#Msig)
|
* [Msig](#Msig)
|
||||||
|
* [MsigAddApprove](#MsigAddApprove)
|
||||||
|
* [MsigAddCancel](#MsigAddCancel)
|
||||||
|
* [MsigAddPropose](#MsigAddPropose)
|
||||||
* [MsigApprove](#MsigApprove)
|
* [MsigApprove](#MsigApprove)
|
||||||
* [MsigCancel](#MsigCancel)
|
* [MsigCancel](#MsigCancel)
|
||||||
* [MsigCreate](#MsigCreate)
|
* [MsigCreate](#MsigCreate)
|
||||||
* [MsigGetAvailableBalance](#MsigGetAvailableBalance)
|
* [MsigGetAvailableBalance](#MsigGetAvailableBalance)
|
||||||
|
* [MsigGetVested](#MsigGetVested)
|
||||||
* [MsigPropose](#MsigPropose)
|
* [MsigPropose](#MsigPropose)
|
||||||
* [MsigSwapApprove](#MsigSwapApprove)
|
* [MsigSwapApprove](#MsigSwapApprove)
|
||||||
* [MsigSwapCancel](#MsigSwapCancel)
|
* [MsigSwapCancel](#MsigSwapCancel)
|
||||||
@ -156,10 +160,12 @@
|
|||||||
* [StateWaitMsg](#StateWaitMsg)
|
* [StateWaitMsg](#StateWaitMsg)
|
||||||
* [Sync](#Sync)
|
* [Sync](#Sync)
|
||||||
* [SyncCheckBad](#SyncCheckBad)
|
* [SyncCheckBad](#SyncCheckBad)
|
||||||
|
* [SyncCheckpoint](#SyncCheckpoint)
|
||||||
* [SyncIncomingBlocks](#SyncIncomingBlocks)
|
* [SyncIncomingBlocks](#SyncIncomingBlocks)
|
||||||
* [SyncMarkBad](#SyncMarkBad)
|
* [SyncMarkBad](#SyncMarkBad)
|
||||||
* [SyncState](#SyncState)
|
* [SyncState](#SyncState)
|
||||||
* [SyncSubmitBlock](#SyncSubmitBlock)
|
* [SyncSubmitBlock](#SyncSubmitBlock)
|
||||||
|
* [SyncUnmarkBad](#SyncUnmarkBad)
|
||||||
* [Wallet](#Wallet)
|
* [Wallet](#Wallet)
|
||||||
* [WalletBalance](#WalletBalance)
|
* [WalletBalance](#WalletBalance)
|
||||||
* [WalletDefaultAddress](#WalletDefaultAddress)
|
* [WalletDefaultAddress](#WalletDefaultAddress)
|
||||||
@ -1837,6 +1843,84 @@ The Msig methods are used to interact with multisig wallets on the
|
|||||||
filecoin network
|
filecoin network
|
||||||
|
|
||||||
|
|
||||||
|
### MsigAddApprove
|
||||||
|
MsigAddApprove approves a previously proposed AddSigner message
|
||||||
|
It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||||
|
<proposer address>, <new signer>, <whether the number of required signers should be increased>
|
||||||
|
|
||||||
|
|
||||||
|
Perms: sign
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"t01234",
|
||||||
|
"t01234",
|
||||||
|
42,
|
||||||
|
"t01234",
|
||||||
|
"t01234",
|
||||||
|
true
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### MsigAddCancel
|
||||||
|
MsigAddCancel cancels a previously proposed AddSigner message
|
||||||
|
It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||||
|
<new signer>, <whether the number of required signers should be increased>
|
||||||
|
|
||||||
|
|
||||||
|
Perms: sign
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"t01234",
|
||||||
|
"t01234",
|
||||||
|
42,
|
||||||
|
"t01234",
|
||||||
|
true
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### MsigAddPropose
|
||||||
|
MsigAddPropose proposes adding a signer in the multisig
|
||||||
|
It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||||
|
<new signer>, <whether the number of required signers should be increased>
|
||||||
|
|
||||||
|
|
||||||
|
Perms: sign
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"t01234",
|
||||||
|
"t01234",
|
||||||
|
"t01234",
|
||||||
|
true
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### MsigApprove
|
### MsigApprove
|
||||||
MsigApprove approves a previously-proposed multisig message
|
MsigApprove approves a previously-proposed multisig message
|
||||||
It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
|
It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
|
||||||
@ -1944,6 +2028,38 @@ Inputs:
|
|||||||
|
|
||||||
Response: `"0"`
|
Response: `"0"`
|
||||||
|
|
||||||
|
### MsigGetVested
|
||||||
|
MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
|
||||||
|
It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"t01234",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `"0"`
|
||||||
|
|
||||||
### MsigPropose
|
### MsigPropose
|
||||||
MsigPropose proposes a multisig message
|
MsigPropose proposes a multisig message
|
||||||
It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||||
@ -1974,7 +2090,7 @@ Response:
|
|||||||
### MsigSwapApprove
|
### MsigSwapApprove
|
||||||
MsigSwapApprove approves a previously proposed SwapSigner
|
MsigSwapApprove approves a previously proposed SwapSigner
|
||||||
It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||||
<proposer address>, <old signer> <new signer>
|
<proposer address>, <old signer>, <new signer>
|
||||||
|
|
||||||
|
|
||||||
Perms: sign
|
Perms: sign
|
||||||
@ -2001,7 +2117,7 @@ Response:
|
|||||||
### MsigSwapCancel
|
### MsigSwapCancel
|
||||||
MsigSwapCancel cancels a previously proposed SwapSigner message
|
MsigSwapCancel cancels a previously proposed SwapSigner message
|
||||||
It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||||
<old signer> <new signer>
|
<old signer>, <new signer>
|
||||||
|
|
||||||
|
|
||||||
Perms: sign
|
Perms: sign
|
||||||
@ -2027,7 +2143,7 @@ Response:
|
|||||||
### MsigSwapPropose
|
### MsigSwapPropose
|
||||||
MsigSwapPropose proposes swapping 2 signers in the multisig
|
MsigSwapPropose proposes swapping 2 signers in the multisig
|
||||||
It takes the following params: <multisig address>, <sender address of the propose msg>,
|
It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||||
<old signer> <new signer>
|
<old signer>, <new signer>
|
||||||
|
|
||||||
|
|
||||||
Perms: sign
|
Perms: sign
|
||||||
@ -3995,6 +4111,28 @@ Inputs:
|
|||||||
|
|
||||||
Response: `"string value"`
|
Response: `"string value"`
|
||||||
|
|
||||||
|
### SyncCheckpoint
|
||||||
|
SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it.
|
||||||
|
|
||||||
|
|
||||||
|
Perms: admin
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `{}`
|
||||||
|
|
||||||
### SyncIncomingBlocks
|
### SyncIncomingBlocks
|
||||||
SyncIncomingBlocks returns a channel streaming incoming, potentially not
|
SyncIncomingBlocks returns a channel streaming incoming, potentially not
|
||||||
yet synced block headers.
|
yet synced block headers.
|
||||||
@ -4130,6 +4268,23 @@ Inputs:
|
|||||||
|
|
||||||
Response: `{}`
|
Response: `{}`
|
||||||
|
|
||||||
|
### SyncUnmarkBad
|
||||||
|
SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
||||||
|
|
||||||
|
|
||||||
|
Perms: admin
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `{}`
|
||||||
|
|
||||||
## Wallet
|
## Wallet
|
||||||
|
|
||||||
|
|
||||||
|
2
extern/storage-sealing/states_failed.go
vendored
2
extern/storage-sealing/states_failed.go
vendored
@ -62,7 +62,7 @@ func (m *Sealing) handleSealPrecommit2Failed(ctx statemachine.Context, sector Se
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sector.PreCommit2Fails > 1 {
|
if sector.PreCommit2Fails > 3 {
|
||||||
return ctx.Send(SectorRetrySealPreCommit1{})
|
return ctx.Send(SectorRetrySealPreCommit1{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
go.mod
2
go.mod
@ -90,7 +90,7 @@ require (
|
|||||||
github.com/libp2p/go-libp2p-mplex v0.2.4
|
github.com/libp2p/go-libp2p-mplex v0.2.4
|
||||||
github.com/libp2p/go-libp2p-noise v0.1.1
|
github.com/libp2p/go-libp2p-noise v0.1.1
|
||||||
github.com/libp2p/go-libp2p-peerstore v0.2.6
|
github.com/libp2p/go-libp2p-peerstore v0.2.6
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb
|
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18
|
||||||
github.com/libp2p/go-libp2p-quic-transport v0.8.0
|
github.com/libp2p/go-libp2p-quic-transport v0.8.0
|
||||||
github.com/libp2p/go-libp2p-record v0.1.3
|
github.com/libp2p/go-libp2p-record v0.1.3
|
||||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3
|
github.com/libp2p/go-libp2p-routing-helpers v0.2.3
|
||||||
|
4
go.sum
4
go.sum
@ -843,8 +843,8 @@ github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1
|
|||||||
github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=
|
github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q=
|
github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q=
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato=
|
github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato=
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb h1:0jm9ZSDkteX9XRjZqZwG5X0wuR+e0zAJ6ZEnqo2vcb0=
|
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18 h1:+ae7vHSv/PJ4xGXwLV6LKGj32zjyB8ttJHtyV4TXal0=
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
|
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
|
||||||
github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU=
|
github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU=
|
||||||
github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M=
|
github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M=
|
||||||
github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E=
|
github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E=
|
||||||
|
@ -170,9 +170,14 @@ func (a *CommonAPI) ID(context.Context) (peer.ID, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *CommonAPI) Version(context.Context) (api.Version, error) {
|
func (a *CommonAPI) Version(context.Context) (api.Version, error) {
|
||||||
|
v, err := build.VersionForType(build.RunningNodeType)
|
||||||
|
if err != nil {
|
||||||
|
return api.Version{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return api.Version{
|
return api.Version{
|
||||||
Version: build.UserVersion(),
|
Version: build.UserVersion(),
|
||||||
APIVersion: build.APIVersion,
|
APIVersion: v,
|
||||||
|
|
||||||
BlockDelay: build.BlockDelaySecs,
|
BlockDelay: build.BlockDelaySecs,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -130,6 +130,33 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr
|
|||||||
return smsg.Cid(), nil
|
return smsg.Cid(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *MsigAPI) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||||
|
enc, actErr := serializeAddParams(newAdd, inc)
|
||||||
|
if actErr != nil {
|
||||||
|
return cid.Undef, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MsigAPI) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||||
|
enc, actErr := serializeAddParams(newAdd, inc)
|
||||||
|
if actErr != nil {
|
||||||
|
return cid.Undef, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MsigAPI) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||||
|
enc, actErr := serializeAddParams(newAdd, inc)
|
||||||
|
if actErr != nil {
|
||||||
|
return cid.Undef, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *MsigAPI) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
func (a *MsigAPI) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||||
enc, actErr := serializeSwapParams(oldAdd, newAdd)
|
enc, actErr := serializeSwapParams(oldAdd, newAdd)
|
||||||
if actErr != nil {
|
if actErr != nil {
|
||||||
@ -244,6 +271,18 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro
|
|||||||
return smsg.Cid(), nil
|
return smsg.Cid(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func serializeAddParams(new address.Address, inc bool) ([]byte, error) {
|
||||||
|
enc, actErr := actors.SerializeParams(&samsig.AddSignerParams{
|
||||||
|
Signer: new,
|
||||||
|
Increase: inc,
|
||||||
|
})
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return enc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func serializeSwapParams(old address.Address, new address.Address) ([]byte, error) {
|
func serializeSwapParams(old address.Address, new address.Address) ([]byte, error) {
|
||||||
enc, actErr := actors.SerializeParams(&samsig.SwapSignerParams{
|
enc, actErr := actors.SerializeParams(&samsig.SwapSignerParams{
|
||||||
From: old,
|
From: old,
|
||||||
|
@ -886,6 +886,48 @@ func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Add
|
|||||||
return types.BigSub(act.Balance, minBalance), nil
|
return types.BigSub(act.Balance, minBalance), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
|
||||||
|
startTs, err := a.Chain.GetTipSetFromKey(start)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyInt, xerrors.Errorf("loading start tipset %s: %w", start, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
endTs, err := a.Chain.GetTipSetFromKey(end)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyInt, xerrors.Errorf("loading end tipset %s: %w", end, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if startTs.Height() > endTs.Height() {
|
||||||
|
return types.EmptyInt, xerrors.Errorf("start tipset %d is after end tipset %d", startTs.Height(), endTs.Height())
|
||||||
|
} else if startTs.Height() == endTs.Height() {
|
||||||
|
return big.Zero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var mst samsig.State
|
||||||
|
act, err := a.StateManager.LoadActorState(ctx, addr, &mst, endTs)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state at end epoch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if act.Code != builtin.MultisigActorCodeID {
|
||||||
|
return types.EmptyInt, fmt.Errorf("given actor was not a multisig")
|
||||||
|
}
|
||||||
|
|
||||||
|
if mst.UnlockDuration == 0 ||
|
||||||
|
mst.InitialBalance.IsZero() ||
|
||||||
|
mst.StartEpoch+mst.UnlockDuration <= startTs.Height() ||
|
||||||
|
mst.StartEpoch >= endTs.Height() {
|
||||||
|
return big.Zero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
startLk := mst.InitialBalance
|
||||||
|
if startTs.Height() > mst.StartEpoch {
|
||||||
|
startLk = mst.AmountLocked(startTs.Height() - mst.StartEpoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
return big.Sub(startLk, mst.AmountLocked(endTs.Height()-mst.StartEpoch)), nil
|
||||||
|
}
|
||||||
|
|
||||||
var initialPledgeNum = types.NewInt(110)
|
var initialPledgeNum = types.NewInt(110)
|
||||||
var initialPledgeDen = types.NewInt(100)
|
var initialPledgeDen = types.NewInt(100)
|
||||||
|
|
||||||
|
@ -97,12 +97,23 @@ func (a *SyncAPI) SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHe
|
|||||||
return a.Syncer.IncomingBlocks(ctx)
|
return a.Syncer.IncomingBlocks(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *SyncAPI) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error {
|
||||||
|
log.Warnf("Marking tipset %s as checkpoint", tsk)
|
||||||
|
return a.Syncer.SetCheckpoint(tsk)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *SyncAPI) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
|
func (a *SyncAPI) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||||
log.Warnf("Marking block %s as bad", bcid)
|
log.Warnf("Marking block %s as bad", bcid)
|
||||||
a.Syncer.MarkBad(bcid)
|
a.Syncer.MarkBad(bcid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *SyncAPI) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||||
|
log.Warnf("Unmarking block %s as bad", bcid)
|
||||||
|
a.Syncer.UnmarkBad(bcid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *SyncAPI) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
func (a *SyncAPI) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||||
reason, ok := a.Syncer.CheckBadBlockCache(bcid)
|
reason, ok := a.Syncer.CheckBadBlockCache(bcid)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -163,8 +163,8 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore,
|
|||||||
return netName, err
|
return netName, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) {
|
func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) {
|
||||||
syncer, err := chain.NewSyncer(sm, exchange, h.ConnManager(), h.ID(), beacon, verifier)
|
syncer, err := chain.NewSyncer(ds, sm, exchange, h.ConnManager(), h.ID(), beacon, verifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user