Compare commits
100
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26ed6af040 | ||
|
|
82bd7bd2ec | ||
|
|
cd0a43b7f4 | ||
|
|
b14632b750 | ||
|
|
ebcf77e830 | ||
|
|
344d30e960 | ||
|
|
efb13a0d9b | ||
|
|
0223582d41 | ||
|
|
973f61bc10 | ||
|
|
60768f4863 | ||
|
|
c60d13ee56 | ||
|
|
0f8fc119f3 | ||
|
|
e4d2e6e01d | ||
|
|
d55f10bed6 | ||
|
|
21de538d09 | ||
|
|
fe5b32026a | ||
|
|
91c10c2df5 | ||
|
|
c3420c0ceb | ||
|
|
7933cf094f | ||
|
|
4cd73f1560 | ||
|
|
8a175a7465 | ||
|
|
f7f229ae54 | ||
|
|
1323e07a2c | ||
|
|
2ad671649c | ||
|
|
d26ece10b8 | ||
|
|
4c8084dcb0 | ||
|
|
98d702fb5a | ||
|
|
17f61ac212 | ||
|
|
df67576b89 | ||
|
|
cdc2f86f5a | ||
|
|
67b3a55e30 | ||
|
|
3201e0eb8f | ||
|
|
8d2d74438b | ||
|
|
1f9446f91f | ||
|
|
4937ca1a96 | ||
|
|
264fe4edb9 | ||
|
|
cb7d99fcc7 | ||
|
|
7332a39f00 | ||
|
|
8f35a5c036 | ||
|
|
dea7042668 | ||
|
|
bd8f3f05be | ||
|
|
304d835739 | ||
|
|
cb8678e4c2 | ||
|
|
da34548a05 | ||
|
|
cd9af278b4 | ||
|
|
b1fe92f8ff | ||
|
|
8dd8892b81 | ||
|
|
79dba816c7 | ||
|
|
14bb4c9a0b | ||
|
|
f9f54819d4 | ||
|
|
d1555106a4 | ||
|
|
413c357361 | ||
|
|
d97eb10349 | ||
|
|
e8253d22c6 | ||
|
|
a4e954197c | ||
|
|
8f4911ac0d | ||
|
|
b0bea5f145 | ||
|
|
7c7e0d73d5 | ||
|
|
1fea550ce5 | ||
|
|
9b7b6146eb | ||
|
|
dab1107f5b | ||
|
|
fe912223bd | ||
|
|
12cd478e11 | ||
|
|
ae3691e0a2 | ||
|
|
e55b00f358 | ||
|
|
de3f4111f4 | ||
|
|
767c346cf8 | ||
|
|
6f4a762664 | ||
|
|
c02daca9e9 | ||
|
|
cca17f6078 | ||
|
|
c17fa4bc35 | ||
|
|
e803cf151f | ||
|
|
1268cfbfcd | ||
|
|
5ef929f130 | ||
|
|
5bd6a3cdad | ||
|
|
df4b068d0e | ||
|
|
0d34881a0c | ||
|
|
6eb49b717f | ||
|
|
099b982ea8 | ||
|
|
10c120bd3c | ||
|
|
7cd1330acd | ||
|
|
39bc816a79 | ||
|
|
81fb552e1d | ||
|
|
cfd126ee9f | ||
|
|
d6fa644974 | ||
|
|
d3dc560f53 | ||
|
|
25bc00eec8 | ||
|
|
3b12a9f425 | ||
|
|
b7c8f65af5 | ||
|
|
c6e0cb4ff2 | ||
|
|
f6eb530cba | ||
|
|
f4991e868e | ||
|
|
be92dd9e63 | ||
|
|
15670942c3 | ||
|
|
bd474617ed | ||
|
|
087030fe37 | ||
|
|
4a3081c77a | ||
|
|
d4cbd4fb55 | ||
|
|
1fc23fb466 | ||
|
|
c66f087f4c |
+94
-1
@@ -1,5 +1,98 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 0.9.0 / 2020-10-07
|
||||
|
||||
This consensus-breaking release of Lotus upgrades the actors version to v2.0.0. This requires migrating actor state from v0 to v2. The changes that break consensus are:
|
||||
|
||||
- Introducing v2 actors and its migration (https://github.com/filecoin-project/lotus/pull/3936)
|
||||
- Runtime's Receiver() should only return ID addresses (https://github.com/filecoin-project/lotus/pull/3589)
|
||||
- Update miner eligibility checks for v2 actors (https://github.com/filecoin-project/lotus/pull/4188)
|
||||
- Add funds that have left FilReserve to circ supply (https://github.com/filecoin-project/lotus/pull/4160)
|
||||
- Set WinningPoStSectorSetLookback to finality post-v2 actors (https://github.com/filecoin-project/lotus/pull/4190)
|
||||
- fix: error when actor panics directly (https://github.com/filecoin-project/lotus/pull/3697)
|
||||
|
||||
## Changes
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- Update go-bitfield (https://github.com/filecoin-project/lotus/pull/4171)
|
||||
- update the AMT implementation (https://github.com/filecoin-project/lotus/pull/4194)
|
||||
- Update to actors v0.2.1 (https://github.com/filecoin-project/lotus/pull/4199)
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Paych: fix voucher amount verification (https://github.com/filecoin-project/lotus/pull/3821)
|
||||
- Cap market provider messages (https://github.com/filecoin-project/lotus/pull/4141)
|
||||
- Run fork function after cron for null block safety (https://github.com/filecoin-project/lotus/pull/4114)
|
||||
- use bitswap sessions when fetching messages, and cancel them (https://github.com/filecoin-project/lotus/pull/4142)
|
||||
- relax pubsub IPColocationFactorThreshold to 5 (https://github.com/filecoin-project/lotus/pull/4183)
|
||||
- Support addresses with mainnet prefixes (https://github.com/filecoin-project/lotus/pull/4186)
|
||||
- fix: make message signer nonce generation transactional (https://github.com/filecoin-project/lotus/pull/4165)
|
||||
- build: Env var to keep test address output (https://github.com/filecoin-project/lotus/pull/4213)
|
||||
- make vm.EnableGasTracing public (https://github.com/filecoin-project/lotus/pull/4214)
|
||||
- introduce separate state-tree versions (https://github.com/filecoin-project/lotus/pull/4197)
|
||||
- reject explicit "calls" at the upgrade height (https://github.com/filecoin-project/lotus/pull/4231)
|
||||
- return an illegal actor error when we see an unsupported actor version (https://github.com/filecoin-project/lotus/pull/4232)
|
||||
- Set head should unmark blocks as valid (https://gist.github.com/travisperson/3c7cddd77a33979a519ccef4e6515f20)
|
||||
|
||||
#### Mining
|
||||
|
||||
- Increased ExpectedSealDuration and and WaitDealsDelay (https://github.com/filecoin-project/lotus/pull/3743)
|
||||
- Miner backup/restore commands (https://github.com/filecoin-project/lotus/pull/4133)
|
||||
- lotus-miner: add more help text to storage / attach (https://github.com/filecoin-project/lotus/pull/3961)
|
||||
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
|
||||
- feat(miner): add miner deadline diffing logic (https://github.com/filecoin-project/lotus/pull/4178)
|
||||
|
||||
#### UX
|
||||
|
||||
- Improve the UX for replacing messages (https://github.com/filecoin-project/lotus/pull/4134)
|
||||
- Add verified flag to interactive deal creation (https://github.com/filecoin-project/lotus/pull/4145)
|
||||
- Add command to (slowly) prune lotus chain datastore (https://github.com/filecoin-project/lotus/pull/3876)
|
||||
- Some helpers for verifreg work (https://github.com/filecoin-project/lotus/pull/4124)
|
||||
- Always use default 720h for setask duration and hide the duration param option (https://github.com/filecoin-project/lotus/pull/4077)
|
||||
- Convert ID addresses to key addresses before checking wallet (https://github.com/filecoin-project/lotus/pull/4122)
|
||||
- add a command to view block space utilization (https://github.com/filecoin-project/lotus/pull/4176)
|
||||
- allow usage inspection on a chain segment (https://github.com/filecoin-project/lotus/pull/4177)
|
||||
- Add mpool stats for base fee (https://github.com/filecoin-project/lotus/pull/4170)
|
||||
- Add verified status to api.DealInfo (https://github.com/filecoin-project/lotus/pull/4153)
|
||||
- Add a CLI command to set a miner's owner address (https://github.com/filecoin-project/lotus/pull/4189)
|
||||
|
||||
#### Tooling and validation
|
||||
|
||||
- Lotus-pcr: add recover-miners command (https://github.com/filecoin-project/lotus/pull/3714)
|
||||
- MpoolPushUntrusted API for gateway (https://github.com/filecoin-project/lotus/pull/3915)
|
||||
- Test lotus-miner info all (https://github.com/filecoin-project/lotus/pull/4166)
|
||||
- chain export: Error with unfinished exports (https://github.com/filecoin-project/lotus/pull/4179)
|
||||
- add printf in TestWindowPost (https://github.com/filecoin-project/lotus/pull/4043)
|
||||
- add trace wdpost (https://github.com/filecoin-project/lotus/pull/4020)
|
||||
- Fix noncefix (https://github.com/filecoin-project/lotus/pull/4202)
|
||||
- Lotus-pcr: Limit the fee cap of messages we will process, refund gas fees for windowed post and storage deals (https://github.com/filecoin-project/lotus/pull/4198)
|
||||
- Fix pond (https://github.com/filecoin-project/lotus/pull/4203)
|
||||
- allow manual setting of noncefix fee cap (https://github.com/filecoin-project/lotus/pull/4205)
|
||||
- implement command to get execution traces of any message (https://github.com/filecoin-project/lotus/pull/4200)
|
||||
- conformance: minor driver refactors (https://github.com/filecoin-project/lotus/pull/4211)
|
||||
- lotus-pcr: ignore all other messages (https://github.com/filecoin-project/lotus/pull/4218)
|
||||
- lotus-pcr: zero refund (https://github.com/filecoin-project/lotus/pull/4229)
|
||||
|
||||
## Contributors
|
||||
|
||||
The following contributors had 5 or more commits go into this release.
|
||||
We are grateful for every contribution!
|
||||
|
||||
| Contributor | Commits | Lines ± |
|
||||
|--------------------|---------|---------------|
|
||||
| Stebalien | 84 | +3425/-2287 |
|
||||
| magik6k | 41 | +2121/-506 |
|
||||
| arajasek | 39 | +2467/-424 |
|
||||
| Kubuxu | 25 | +2344/-775 |
|
||||
| raulk | 21 | +287/-196 |
|
||||
| whyrusleeping | 13 | +727/-71 |
|
||||
| hsanjuan | 13 | +5886/-7956 |
|
||||
| dirkmc | 11 | +2634/-576 |
|
||||
| travisperson | 8 | +923/-202 |
|
||||
| ribasushi | 6 | +188/-128 |
|
||||
| zgfzgf | 5 | +21/-17 |
|
||||
|
||||
# 0.8.1 / 2020-09-30
|
||||
|
||||
This optional release of Lotus introduces a new version of markets which switches to CBOR-map encodings, and allows datastore migrations. The release also introduces several improvements to the mining process, a few performance optimizations, and a battery of UX additions and enhancements.
|
||||
@@ -117,7 +210,7 @@ We are grateful for every contribution!
|
||||
| vyzo | 22 | +287/-196 |
|
||||
| alanshaw | 15 | +761/-146 |
|
||||
| whyrusleeping | 15 | +736/-52 |
|
||||
| hannahhoward | 14 | +1237/837- |
|
||||
| hannahhoward | 14 | +1237/-837 |
|
||||
| anton | 6 | +32/-8 |
|
||||
| travisperson | 5 | +502/-6 |
|
||||
| Frank | 5 | +78/-39 |
|
||||
|
||||
@@ -418,6 +418,9 @@ type FullNode interface {
|
||||
|
||||
// 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)
|
||||
// MsigGetLockedBalance returns the locked balance of an msig at a vien epoch.
|
||||
// The return may be greater than the multisig actor's actual balance.
|
||||
MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, 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)
|
||||
@@ -871,3 +874,15 @@ type Fault struct {
|
||||
Miner address.Address
|
||||
Epoch abi.ChainEpoch
|
||||
}
|
||||
|
||||
var EmptyVesting = MsigVesting{
|
||||
InitialBalance: types.EmptyInt,
|
||||
StartEpoch: -1,
|
||||
UnlockDuration: -1,
|
||||
}
|
||||
|
||||
type MsigVesting struct {
|
||||
InitialBalance abi.TokenAmount
|
||||
StartEpoch abi.ChainEpoch
|
||||
UnlockDuration abi.ChainEpoch
|
||||
}
|
||||
|
||||
@@ -212,6 +212,7 @@ type FullNodeStruct struct {
|
||||
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigGetVestingSchedule func(context.Context, address.Address, types.TipSetKey) (api.MsigVesting, 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"`
|
||||
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -933,6 +934,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetVestingSchedule(ctx context.Context, a address.Address, tsk types.TipSetKey) (api.MsigVesting, error) {
|
||||
return c.Internal.MsigGetVestingSchedule(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)
|
||||
}
|
||||
|
||||
+12
-2
@@ -3,6 +3,9 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
@@ -13,8 +16,10 @@ const BreezeGasTampingDuration = 0
|
||||
|
||||
const UpgradeSmokeHeight = -1
|
||||
const UpgradeIgnitionHeight = -2
|
||||
const UpgradeLiftoffHeight = -3
|
||||
const UpgradeActorsV2Height = 10
|
||||
const UpgradeRefuelHeight = -3
|
||||
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
@@ -25,6 +30,11 @@ func init() {
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
|
||||
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||
UpgradeActorsV2Height = math.MaxInt64
|
||||
UpgradeLiftoffHeight = 11
|
||||
}
|
||||
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +82,9 @@ var (
|
||||
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -3
|
||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||
UpgradeActorsV2Height abi.ChainEpoch = 10
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -4
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
|
||||
+12
-3
@@ -5,6 +5,9 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
@@ -23,9 +26,9 @@ const BreezeGasTampingDuration = 120
|
||||
const UpgradeSmokeHeight = 51000
|
||||
|
||||
const UpgradeIgnitionHeight = 94000
|
||||
const UpgradeRefuelHeight = 130800
|
||||
|
||||
// TODO: Actual epoch needs to be filled in
|
||||
const UpgradeActorsV2Height = 128888
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
||||
|
||||
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
||||
// Miners, clients, developers, custodians all need time to prepare.
|
||||
@@ -39,7 +42,13 @@ func init() {
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
||||
)
|
||||
|
||||
SetAddressNetwork(address.Mainnet)
|
||||
if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" {
|
||||
SetAddressNetwork(address.Mainnet)
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||
UpgradeActorsV2Height = math.MaxInt64
|
||||
}
|
||||
|
||||
Devnet = false
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.8.1"
|
||||
const BuildVersion = "0.9.0"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
var SystemActorAddr = builtin0.SystemActorAddr
|
||||
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||
var ReserveAddress = makeAddress("t090")
|
||||
var RootVerifierAddress = makeAddress("t080")
|
||||
|
||||
// TODO: Why does actors have 2 different versions of this?
|
||||
type SectorInfo = proof0.SectorInfo
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
)
|
||||
|
||||
type DeadlinesDiff map[uint64]*DeadlineDiff
|
||||
|
||||
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
|
||||
changed, err := pre.DeadlinesChanged(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
numDl, err := pre.NumDeadlines()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dlDiff := make(DeadlinesDiff, numDl)
|
||||
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
|
||||
curDl, err := cur.LoadDeadline(idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
diff, err := DiffDeadline(preDl, curDl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dlDiff[idx] = diff
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dlDiff, nil
|
||||
}
|
||||
|
||||
type DeadlineDiff map[uint64]*PartitionDiff
|
||||
|
||||
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
|
||||
changed, err := pre.PartitionsChanged(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
partDiff := make(DeadlineDiff)
|
||||
if err := pre.ForEachPartition(func(idx uint64, prePart Partition) error {
|
||||
// try loading current partition at this index
|
||||
curPart, err := cur.LoadPartition(idx)
|
||||
if err != nil {
|
||||
if errors.Is(err, exitcode.ErrNotFound) {
|
||||
// TODO correctness?
|
||||
return nil // the partition was removed.
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// compare it with the previous partition
|
||||
diff, err := DiffPartition(prePart, curPart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
partDiff[idx] = diff
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// all previous partitions have been walked.
|
||||
// all partitions in cur and not in prev are new... can they be faulty already?
|
||||
// TODO is this correct?
|
||||
if err := cur.ForEachPartition(func(idx uint64, curPart Partition) error {
|
||||
if _, found := partDiff[idx]; found {
|
||||
return nil
|
||||
}
|
||||
faults, err := curPart.FaultySectors()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
recovering, err := curPart.RecoveringSectors()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
partDiff[idx] = &PartitionDiff{
|
||||
Removed: bitfield.New(),
|
||||
Recovered: bitfield.New(),
|
||||
Faulted: faults,
|
||||
Recovering: recovering,
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &partDiff, nil
|
||||
}
|
||||
|
||||
type PartitionDiff struct {
|
||||
Removed bitfield.BitField
|
||||
Recovered bitfield.BitField
|
||||
Faulted bitfield.BitField
|
||||
Recovering bitfield.BitField
|
||||
}
|
||||
|
||||
func DiffPartition(pre, cur Partition) (*PartitionDiff, error) {
|
||||
prevLiveSectors, err := pre.LiveSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curLiveSectors, err := cur.LiveSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
removed, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prevRecoveries, err := pre.RecoveringSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
curRecoveries, err := cur.RecoveringSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recovering, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prevFaults, err := pre.FaultySectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
curFaults, err := cur.FaultySectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
faulted, err := bitfield.SubtractBitField(curFaults, prevFaults)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// all current good sectors
|
||||
curActiveSectors, err := cur.ActiveSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// sectors that were previously fault and are now currently active are considered recovered.
|
||||
recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PartitionDiff{
|
||||
Removed: removed,
|
||||
Recovered: recovered,
|
||||
Faulted: faulted,
|
||||
Recovering: recovering,
|
||||
}, nil
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
type Version int
|
||||
|
||||
const (
|
||||
Version0 = 0
|
||||
Version2 = 2
|
||||
Version0 Version = 0
|
||||
Version2 Version = 2
|
||||
)
|
||||
|
||||
// Converts a network version into an actors adt version.
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -117,7 +116,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
||||
}
|
||||
|
||||
state, err := state.NewStateTree(cst, actors.Version0)
|
||||
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
|
||||
@@ -149,13 +149,13 @@ loop:
|
||||
|
||||
if len(msgs) > 0 {
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
msgsEv := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
msgs = append(msgs, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
msgsEv = append(msgsEv, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
}
|
||||
return MessagePoolEvt{
|
||||
Action: "repub",
|
||||
Messages: msgs,
|
||||
Messages: msgsEv,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+40
-16
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
|
||||
// StateTree stores actors state by their ID.
|
||||
type StateTree struct {
|
||||
root adt.Map
|
||||
version actors.Version // TODO
|
||||
version types.StateTreeVersion
|
||||
info cid.Cid
|
||||
Store cbor.IpldStore
|
||||
|
||||
@@ -120,21 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
|
||||
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
||||
}
|
||||
|
||||
func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error) {
|
||||
// VersionForNetwork returns the state tree version for the given network
|
||||
// version.
|
||||
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
|
||||
if actors.VersionForNetwork(ver) == actors.Version0 {
|
||||
return types.StateTreeVersion0
|
||||
}
|
||||
return types.StateTreeVersion1
|
||||
}
|
||||
|
||||
func adtForSTVersion(ver types.StateTreeVersion) actors.Version {
|
||||
switch ver {
|
||||
case types.StateTreeVersion0:
|
||||
return actors.Version0
|
||||
case types.StateTreeVersion1:
|
||||
return actors.Version2
|
||||
default:
|
||||
panic("unhandled state tree version")
|
||||
}
|
||||
}
|
||||
|
||||
func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, error) {
|
||||
var info cid.Cid
|
||||
switch version {
|
||||
case actors.Version0:
|
||||
switch ver {
|
||||
case types.StateTreeVersion0:
|
||||
// info is undefined
|
||||
case actors.Version2:
|
||||
case types.StateTreeVersion1:
|
||||
var err error
|
||||
info, err = cst.Put(context.TODO(), new(types.StateInfo))
|
||||
info, err = cst.Put(context.TODO(), new(types.StateInfo0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
|
||||
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
|
||||
}
|
||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
|
||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -142,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error
|
||||
return &StateTree{
|
||||
root: root,
|
||||
info: info,
|
||||
version: version,
|
||||
version: ver,
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
@@ -154,13 +175,16 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
||||
if err := cst.Get(context.TODO(), c, &root); err != nil {
|
||||
// We failed to decode as the new version, must be an old version.
|
||||
root.Actors = c
|
||||
root.Version = actors.Version0
|
||||
root.Version = types.StateTreeVersion0
|
||||
}
|
||||
|
||||
switch root.Version {
|
||||
case actors.Version0, actors.Version2:
|
||||
case types.StateTreeVersion0, types.StateTreeVersion1:
|
||||
// Load the actual state-tree HAMT.
|
||||
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version))
|
||||
nd, err := adt.AsMap(
|
||||
adt.WrapStore(context.TODO(), cst), root.Actors,
|
||||
adtForSTVersion(root.Version),
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("loading hamt node %s failed: %s", c, err)
|
||||
return nil, err
|
||||
@@ -169,7 +193,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
||||
return &StateTree{
|
||||
root: nd,
|
||||
info: root.Info,
|
||||
version: actors.Version(root.Version),
|
||||
version: root.Version,
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
@@ -309,11 +333,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
|
||||
}
|
||||
// If we're version 0, return a raw tree.
|
||||
if st.version == actors.Version0 {
|
||||
if st.version == types.StateTreeVersion0 {
|
||||
return root, nil
|
||||
}
|
||||
// Otherwise, return a versioned tree.
|
||||
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
|
||||
return st.Store.Put(ctx, &types.StateRoot{Version: st.version, Actors: root, Info: st.info})
|
||||
}
|
||||
|
||||
func (st *StateTree) Snapshot(ctx context.Context) error {
|
||||
@@ -400,7 +424,7 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error
|
||||
}
|
||||
|
||||
// Version returns the version of the StateTree data structure in use.
|
||||
func (st *StateTree) Version() actors.Version {
|
||||
func (st *StateTree) Version() types.StateTreeVersion {
|
||||
return st.version
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,12 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func BenchmarkStateTreeSet(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -46,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
||||
|
||||
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -76,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
|
||||
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -118,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
|
||||
func TestSetCache(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -155,7 +154,7 @@ func TestSetCache(t *testing.T) {
|
||||
func TestSnapshots(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -239,7 +238,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
|
||||
func TestStateTreeConsistency(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
// TODO: ActorUpgrade: this test tests pre actors v2
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+42
-2
@@ -2,6 +2,7 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -17,17 +18,38 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at epoch")
|
||||
|
||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.Call")
|
||||
defer span.End()
|
||||
|
||||
// If no tipset is provided, try to find one without a fork.
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
|
||||
// Search back till we find a height with no fork, or we reach the beginning.
|
||||
for ts.Height() > 0 && sm.hasExpensiveFork(ctx, ts.Height()-1) {
|
||||
var err error
|
||||
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bstate := ts.ParentState()
|
||||
bheight := ts.Height()
|
||||
|
||||
// If we have to run an expensive migration, and we're not at genesis,
|
||||
// return an error because the migration will take too long.
|
||||
//
|
||||
// We allow this at height 0 for at-genesis migrations (for testing).
|
||||
if bheight-1 > 0 && sm.hasExpensiveFork(ctx, bheight-1) {
|
||||
return nil, ErrExpensiveFork
|
||||
}
|
||||
|
||||
// Run the (not expensive) migration.
|
||||
bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||
@@ -44,7 +66,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
|
||||
vmi, err := vm.NewVM(ctx, vmopt)
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
@@ -106,6 +128,24 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
|
||||
// Search back till we find a height with no fork, or we reach the beginning.
|
||||
// We need the _previous_ height to have no fork, because we'll
|
||||
// run the fork logic in `sm.TipSetState`. We need the _current_
|
||||
// height to have no fork, because we'll run it inside this
|
||||
// function before executing the given message.
|
||||
for ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
|
||||
var err error
|
||||
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When we're not at the genesis block, make sure we don't have an expensive migration.
|
||||
if ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
|
||||
return nil, ErrExpensiveFork
|
||||
}
|
||||
|
||||
state, _, err := sm.TipSetState(ctx, ts)
|
||||
@@ -138,7 +178,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
vmi, err := vm.NewVM(ctx, vmopt)
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
|
||||
+131
-15
@@ -6,6 +6,8 @@ import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
@@ -25,20 +27,30 @@ import (
|
||||
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/bufbstore"
|
||||
)
|
||||
|
||||
type UpgradeFunc func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error)
|
||||
// UpgradeFunc is a migration function run at every upgrade.
|
||||
//
|
||||
// - The oldState is the state produced by the upgrade epoch.
|
||||
// - The returned newState is the new state that will be used by the next epoch.
|
||||
// - The height is the upgrade epoch height (already executed).
|
||||
// - The tipset is the tipset for the last non-null block before the upgrade. Do
|
||||
// not assume that ts.Height() is the upgrade height.
|
||||
type UpgradeFunc func(ctx context.Context, sm *StateManager, cb ExecCallback, oldState cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (newState cid.Cid, err error)
|
||||
|
||||
type Upgrade struct {
|
||||
Height abi.ChainEpoch
|
||||
Network network.Version
|
||||
Expensive bool
|
||||
Migration UpgradeFunc
|
||||
}
|
||||
|
||||
@@ -47,7 +59,7 @@ type UpgradeSchedule []Upgrade
|
||||
func DefaultUpgradeSchedule() UpgradeSchedule {
|
||||
var us UpgradeSchedule
|
||||
|
||||
for _, u := range []Upgrade{{
|
||||
updates := []Upgrade{{
|
||||
Height: build.UpgradeBreezeHeight,
|
||||
Network: network.Version1,
|
||||
Migration: UpgradeFaucetBurnRecovery,
|
||||
@@ -59,15 +71,46 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
||||
Height: build.UpgradeIgnitionHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeIgnition,
|
||||
}, {
|
||||
Height: build.UpgradeRefuelHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeRefuel,
|
||||
}, {
|
||||
Height: build.UpgradeActorsV2Height,
|
||||
Network: network.Version4,
|
||||
Expensive: true,
|
||||
Migration: UpgradeActorsV2,
|
||||
}, {
|
||||
Height: build.UpgradeLiftoffHeight,
|
||||
Network: network.Version4,
|
||||
Migration: UpgradeLiftoff,
|
||||
}} {
|
||||
}}
|
||||
|
||||
if build.UpgradeActorsV2Height == math.MaxInt64 { // disable actors upgrade
|
||||
updates = []Upgrade{{
|
||||
Height: build.UpgradeBreezeHeight,
|
||||
Network: network.Version1,
|
||||
Migration: UpgradeFaucetBurnRecovery,
|
||||
}, {
|
||||
Height: build.UpgradeSmokeHeight,
|
||||
Network: network.Version2,
|
||||
Migration: nil,
|
||||
}, {
|
||||
Height: build.UpgradeIgnitionHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeIgnition,
|
||||
}, {
|
||||
Height: build.UpgradeRefuelHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeRefuel,
|
||||
}, {
|
||||
Height: build.UpgradeLiftoffHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeLiftoff,
|
||||
}}
|
||||
}
|
||||
|
||||
for _, u := range updates {
|
||||
if u.Height < 0 {
|
||||
// upgrade disabled
|
||||
continue
|
||||
@@ -109,7 +152,7 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
|
||||
var err error
|
||||
f, ok := sm.stateMigrations[height]
|
||||
if ok {
|
||||
retCid, err = f(ctx, sm, cb, root, ts)
|
||||
retCid, err = f(ctx, sm, cb, root, height, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
@@ -118,6 +161,11 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
|
||||
return retCid, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEpoch) bool {
|
||||
_, ok := sm.expensiveUpgrades[height]
|
||||
return ok
|
||||
}
|
||||
|
||||
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||
fromAct, err := tree.GetActor(from)
|
||||
if err != nil {
|
||||
@@ -180,7 +228,7 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
// Some initial parameters
|
||||
FundsForMiners := types.FromFil(1_000_000)
|
||||
LookbackEpoch := abi.ChainEpoch(32000)
|
||||
@@ -432,11 +480,9 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
store := sm.cs.Store(ctx)
|
||||
|
||||
epoch := ts.Height() - 1
|
||||
|
||||
if build.UpgradeLiftoffHeight <= epoch {
|
||||
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
||||
}
|
||||
@@ -489,12 +535,42 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
|
||||
store := sm.cs.Store(ctx)
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
epoch := ts.Height() - 1
|
||||
addr, err := address.NewFromString("t0122")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting address: %w", err)
|
||||
}
|
||||
|
||||
info, err := store.Put(ctx, new(types.StateInfo))
|
||||
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, builtin.ReserveAddress, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, builtin.RootVerifierAddress, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
buf := bufbstore.NewTieredBstore(sm.cs.Blockstore(), bstore.NewTemporarySync())
|
||||
store := store.ActorStore(ctx, buf)
|
||||
|
||||
info, err := store.Put(ctx, new(types.StateInfo0))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
|
||||
}
|
||||
@@ -518,8 +594,7 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
}
|
||||
|
||||
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||
// TODO: ActorUpgrade: should be state-tree specific, not just the actors version.
|
||||
Version: actors.Version2,
|
||||
Version: types.StateTreeVersion1,
|
||||
Actors: newHamtRoot,
|
||||
Info: info,
|
||||
})
|
||||
@@ -538,10 +613,19 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err)
|
||||
}
|
||||
|
||||
{
|
||||
from := buf
|
||||
to := buf.Read()
|
||||
|
||||
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return newRoot, nil
|
||||
}
|
||||
|
||||
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
@@ -699,6 +783,7 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
|
||||
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
|
||||
gb, err := sm.cs.GetGenesis()
|
||||
if err != nil {
|
||||
@@ -748,3 +833,34 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resetMultisigVesting(ctx context.Context, store adt0.Store, tree *state.StateTree, addr address.Address, startEpoch abi.ChainEpoch, duration abi.ChainEpoch, balance abi.TokenAmount) error {
|
||||
act, err := tree.GetActor(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting actor: %w", err)
|
||||
}
|
||||
|
||||
if !builtin.IsMultisigActor(act.Code) {
|
||||
return xerrors.Errorf("actor wasn't msig: %w", err)
|
||||
}
|
||||
|
||||
var msigState multisig0.State
|
||||
if err := store.Get(ctx, act.Head, &msigState); err != nil {
|
||||
return xerrors.Errorf("reading multisig state: %w", err)
|
||||
}
|
||||
|
||||
msigState.StartEpoch = startEpoch
|
||||
msigState.UnlockDuration = duration
|
||||
msigState.InitialBalance = balance
|
||||
|
||||
act.Head, err = store.Put(ctx, &msigState)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing new multisig state: %w", err)
|
||||
}
|
||||
|
||||
if err := tree.SetActor(addr, act); err != nil {
|
||||
return xerrors.Errorf("setting multisig actor: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,8 +10,9 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
@@ -76,7 +77,7 @@ func (ta testActor) Exports() []interface{} {
|
||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
rt.StateCreate(&testActorState{11})
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||
//fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||
|
||||
return abi.Empty
|
||||
}
|
||||
@@ -120,7 +121,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
Network: 1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||
root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
|
||||
st, err := sm.StateTree(root)
|
||||
@@ -173,7 +174,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
|
||||
var msgs []*types.SignedMessage
|
||||
|
||||
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -233,3 +234,84 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestForkRefuseCall(t *testing.T) {
|
||||
logging.SetAllLoggers(logging.LevelInfo)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cg, err := gen.NewGenerator()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||
cg.ChainStore(), UpgradeSchedule{{
|
||||
Network: 1,
|
||||
Expensive: true,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
return root, nil
|
||||
}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inv := vm.NewActorRegistry()
|
||||
inv.Register(nil, testActor{})
|
||||
|
||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||
nvm, err := vm.NewVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nvm.SetInvoker(inv)
|
||||
return nvm, nil
|
||||
})
|
||||
|
||||
cg.SetStateManager(sm)
|
||||
|
||||
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m := &types.Message{
|
||||
From: cg.Banker(),
|
||||
To: lotusinit.Address,
|
||||
Method: builtin.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
GasLimit: types.TestGasLimit,
|
||||
Value: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
ts, err := cg.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet())
|
||||
switch ts.TipSet.TipSet().Height() {
|
||||
case testForkHeight, testForkHeight + 1:
|
||||
// If I had a fork, or I _will_ have a fork, it should fail.
|
||||
require.Equal(t, ErrExpensiveFork, err)
|
||||
default:
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||
}
|
||||
// Call just runs on the parent state for a tipset, so we only
|
||||
// expect an error at the fork height.
|
||||
ret, err = sm.Call(ctx, m, ts.TipSet.TipSet())
|
||||
switch ts.TipSet.TipSet().Height() {
|
||||
case testForkHeight + 1:
|
||||
require.Equal(t, ErrExpensiveFork, err)
|
||||
default:
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+49
-31
@@ -2,6 +2,7 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
@@ -53,6 +54,10 @@ type StateManager struct {
|
||||
|
||||
// Maps chain epochs to upgrade functions.
|
||||
stateMigrations map[abi.ChainEpoch]UpgradeFunc
|
||||
// A set of potentially expensive/time consuming upgrades. Explicit
|
||||
// calls for, e.g., gas estimation fail against this epoch with
|
||||
// ErrExpensiveFork.
|
||||
expensiveUpgrades map[abi.ChainEpoch]struct{}
|
||||
|
||||
stCache map[string][]cid.Cid
|
||||
compWait map[string]chan struct{}
|
||||
@@ -78,6 +83,7 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
|
||||
}
|
||||
|
||||
stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us))
|
||||
expensiveUpgrades := make(map[abi.ChainEpoch]struct{}, len(us))
|
||||
var networkVersions []versionSpec
|
||||
lastVersion := network.Version0
|
||||
if len(us) > 0 {
|
||||
@@ -87,6 +93,9 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
|
||||
if upgrade.Migration != nil {
|
||||
stateMigrations[upgrade.Height] = upgrade.Migration
|
||||
}
|
||||
if upgrade.Expensive {
|
||||
expensiveUpgrades[upgrade.Height] = struct{}{}
|
||||
}
|
||||
networkVersions = append(networkVersions, versionSpec{
|
||||
networkVersion: lastVersion,
|
||||
atOrBelow: upgrade.Height,
|
||||
@@ -99,13 +108,14 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
|
||||
}
|
||||
|
||||
return &StateManager{
|
||||
networkVersions: networkVersions,
|
||||
latestVersion: lastVersion,
|
||||
stateMigrations: stateMigrations,
|
||||
newVM: vm.NewVM,
|
||||
cs: cs,
|
||||
stCache: make(map[string][]cid.Cid),
|
||||
compWait: make(map[string]chan struct{}),
|
||||
networkVersions: networkVersions,
|
||||
latestVersion: lastVersion,
|
||||
stateMigrations: stateMigrations,
|
||||
expensiveUpgrades: expensiveUpgrades,
|
||||
newVM: vm.NewVM,
|
||||
cs: cs,
|
||||
stCache: make(map[string][]cid.Cid),
|
||||
compWait: make(map[string]chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -498,16 +508,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
||||
return nil, fmt.Errorf("failed to load message: %w", err)
|
||||
}
|
||||
|
||||
r, _, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
_, r, _, err = sm.searchBackForMsg(ctx, ts, m)
|
||||
_, r, _, err := sm.searchBackForMsg(ctx, ts, m)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
|
||||
}
|
||||
@@ -665,6 +666,18 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
|
||||
cur := from
|
||||
curActor, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load initital tipset")
|
||||
}
|
||||
|
||||
mFromId, err := sm.LookupID(ctx, m.VMMessage().From, from)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("looking up From id address: %w", err)
|
||||
}
|
||||
|
||||
mNonce := m.VMMessage().Nonce
|
||||
|
||||
for {
|
||||
if cur.Height() == 0 {
|
||||
// it ain't here!
|
||||
@@ -677,32 +690,37 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
||||
default:
|
||||
}
|
||||
|
||||
act, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Cid{}, err
|
||||
}
|
||||
|
||||
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
|
||||
// either way, no reason to lookback, it ain't there
|
||||
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
|
||||
if curActor == nil || curActor.Nonce == 0 || curActor.Nonce < mNonce {
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
ts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
pts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
}
|
||||
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(ts, m.Cid(), m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("checking for message execution during lookback: %w", err)
|
||||
act, err := sm.LoadActor(ctx, mFromId, pts)
|
||||
actorNoExist := errors.Is(err, types.ErrActorNotFound)
|
||||
if err != nil && !actorNoExist {
|
||||
return nil, nil, cid.Cid{}, xerrors.Errorf("failed to load the actor: %w", err)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return ts, r, foundMsg, nil
|
||||
// check that between cur and parent tipset the nonce fell into range of our message
|
||||
if actorNoExist || (curActor.Nonce > mNonce && act.Nonce <= mNonce) {
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(cur, m.Cid(), m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return pts, r, foundMsg, nil
|
||||
}
|
||||
}
|
||||
|
||||
cur = ts
|
||||
cur = pts
|
||||
curActor = act
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -387,7 +387,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
vmi, err := vm.NewVM(ctx, vmopt)
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
@@ -172,25 +172,24 @@ func fetchCids(
|
||||
cids []cid.Cid,
|
||||
cb func(int, blocks.Block) error,
|
||||
) error {
|
||||
fetchedBlocks := bserv.GetBlocks(ctx, cids)
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
cidIndex := make(map[cid.Cid]int)
|
||||
for i, c := range cids {
|
||||
cidIndex[c] = i
|
||||
}
|
||||
if len(cids) != len(cidIndex) {
|
||||
return fmt.Errorf("duplicate CIDs in fetchCids input")
|
||||
}
|
||||
|
||||
fetchedBlocks := bserv.GetBlocks(ctx, cids)
|
||||
|
||||
for i := 0; i < len(cids); i++ {
|
||||
select {
|
||||
case block, ok := <-fetchedBlocks:
|
||||
if !ok {
|
||||
// Closed channel, no more blocks fetched, check if we have all
|
||||
// of the CIDs requested.
|
||||
// FIXME: Review this check. We don't call the callback on the
|
||||
// last index?
|
||||
if i == len(cids)-1 {
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to fetch all messages")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type getter struct {
|
||||
msgs []*types.Message
|
||||
}
|
||||
|
||||
func (g *getter) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { panic("NYI") }
|
||||
|
||||
func (g *getter) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block {
|
||||
ch := make(chan blocks.Block, len(g.msgs))
|
||||
for _, m := range g.msgs {
|
||||
by, err := m.Serialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := blocks.NewBlockWithCid(by, m.Cid())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ch <- b
|
||||
}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func TestFetchCidsWithDedup(t *testing.T) {
|
||||
msgs := []*types.Message{}
|
||||
for i := 0; i < 10; i++ {
|
||||
msgs = append(msgs, &types.Message{
|
||||
From: address.TestAddress,
|
||||
To: address.TestAddress,
|
||||
|
||||
Nonce: uint64(i),
|
||||
})
|
||||
}
|
||||
cids := []cid.Cid{}
|
||||
for _, m := range msgs {
|
||||
cids = append(cids, m.Cid())
|
||||
}
|
||||
g := &getter{msgs}
|
||||
|
||||
// the cids have a duplicate
|
||||
res, err := FetchMessagesByCids(context.TODO(), g, append(cids, cids[0]))
|
||||
|
||||
t.Logf("err: %+v", err)
|
||||
t.Logf("res: %+v", res)
|
||||
if err == nil {
|
||||
t.Errorf("there should be an error")
|
||||
}
|
||||
if err == nil && (res[0] == nil || res[len(res)-1] == nil) {
|
||||
t.Fatalf("there is a nil message: first %p, last %p", res[0], res[len(res)-1])
|
||||
}
|
||||
}
|
||||
+18
-6
@@ -217,6 +217,12 @@ func (syncer *Syncer) Stop() {
|
||||
// This should be called when connecting to new peers, and additionally
|
||||
// when receiving new blocks from the network
|
||||
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Errorf("panic in InformNewHead: ", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
if fts == nil {
|
||||
log.Errorf("got nil tipset in InformNewHead")
|
||||
@@ -731,7 +737,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
||||
|
||||
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute lookback tipset state: %w", err)
|
||||
return xerrors.Errorf("failed to compute lookback tipset state (epoch %d): %w", lbts.Height(), err)
|
||||
}
|
||||
|
||||
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
|
||||
@@ -1281,9 +1287,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet
|
||||
|
||||
blockSet := []*types.TipSet{incoming}
|
||||
|
||||
// Parent of the new (possibly better) tipset that we need to fetch next.
|
||||
at := incoming.Parents()
|
||||
|
||||
// we want to sync all the blocks until the height above the block we have
|
||||
// we want to sync all the blocks until the height above our
|
||||
// best tipset so far
|
||||
untilHeight := known.Height() + 1
|
||||
|
||||
ss.SetHeight(blockSet[len(blockSet)-1].Height())
|
||||
@@ -1377,13 +1385,17 @@ loop:
|
||||
}
|
||||
|
||||
base := blockSet[len(blockSet)-1]
|
||||
if base.Parents() == known.Parents() {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
if base.IsChildOf(known) {
|
||||
// common case: receiving blocks that are building on top of our best tipset
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
if types.CidArrsEqual(base.Parents().Cids(), known.Cids()) {
|
||||
// common case: receiving blocks that are building on top of our best tipset
|
||||
knownParent, err := syncer.store.LoadTipSet(known.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load next local tipset: %w", err)
|
||||
}
|
||||
if base.IsChildOf(knownParent) {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Version (uint64) (uint64)
|
||||
// t.Version (types.StateTreeVersion) (uint64)
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
|
||||
return err
|
||||
@@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Version (uint64) (uint64)
|
||||
// t.Version (types.StateTreeVersion) (uint64)
|
||||
|
||||
{
|
||||
|
||||
@@ -1698,7 +1698,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Version = uint64(extra)
|
||||
t.Version = StateTreeVersion(extra)
|
||||
|
||||
}
|
||||
// t.Actors (cid.Cid) (struct)
|
||||
@@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufStateInfo = []byte{128}
|
||||
var lengthBufStateInfo0 = []byte{128}
|
||||
|
||||
func (t *StateInfo) MarshalCBOR(w io.Writer) error {
|
||||
func (t *StateInfo0) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufStateInfo); err != nil {
|
||||
if _, err := w.Write(lengthBufStateInfo0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = StateInfo{}
|
||||
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = StateInfo0{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
+6
-2
@@ -12,11 +12,15 @@ import (
|
||||
type FIL BigInt
|
||||
|
||||
func (f FIL) String() string {
|
||||
return f.Unitless() + " FIL"
|
||||
}
|
||||
|
||||
func (f FIL) Unitless() string {
|
||||
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
|
||||
if r.Sign() == 0 {
|
||||
return "0 FIL"
|
||||
return "0"
|
||||
}
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL"
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
|
||||
}
|
||||
|
||||
func (f FIL) Format(s fmt.State, ch rune) {
|
||||
|
||||
+14
-3
@@ -2,9 +2,20 @@ package types
|
||||
|
||||
import "github.com/ipfs/go-cid"
|
||||
|
||||
// StateTreeVersion is the version of the state tree itself, independent of the
|
||||
// network version or the actors version.
|
||||
type StateTreeVersion uint64
|
||||
|
||||
const (
|
||||
// StateTreeVersion0 corresponds to actors < v2.
|
||||
StateTreeVersion0 StateTreeVersion = iota
|
||||
// StateTreeVersion1 corresponds to actors >= v2.
|
||||
StateTreeVersion1
|
||||
)
|
||||
|
||||
type StateRoot struct {
|
||||
// State root version. Versioned along with actors (for now).
|
||||
Version uint64
|
||||
// State tree version.
|
||||
Version StateTreeVersion
|
||||
// Actors tree. The structure depends on the state root version.
|
||||
Actors cid.Cid
|
||||
// Info. The structure depends on the state root version.
|
||||
@@ -12,4 +23,4 @@ type StateRoot struct {
|
||||
}
|
||||
|
||||
// TODO: version this.
|
||||
type StateInfo struct{}
|
||||
type StateInfo0 struct{}
|
||||
|
||||
+3
-3
@@ -70,12 +70,12 @@ func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.Meth
|
||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
|
||||
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
|
||||
}
|
||||
if err := act.predicate(rt, act.vmActor); err != nil {
|
||||
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "unsupported actor: %s", err)
|
||||
}
|
||||
if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil {
|
||||
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method)
|
||||
}
|
||||
if err := act.predicate(rt, act.vmActor); err != nil {
|
||||
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "unsupported actor: %s", err)
|
||||
}
|
||||
return act.methods[method](rt, params)
|
||||
|
||||
}
|
||||
|
||||
+5
-4
@@ -49,6 +49,9 @@ func (m *Message) ValueReceived() abi.TokenAmount {
|
||||
return m.msg.Value
|
||||
}
|
||||
|
||||
// EnableGasTracing, if true, outputs gas tracing in execution traces.
|
||||
var EnableGasTracing = false
|
||||
|
||||
type Runtime struct {
|
||||
rt0.Message
|
||||
rt0.Syscalls
|
||||
@@ -477,7 +480,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
}
|
||||
|
||||
func (rt *Runtime) finilizeGasTracing() {
|
||||
if enableTracing {
|
||||
if EnableGasTracing {
|
||||
if rt.lastGasCharge != nil {
|
||||
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
|
||||
}
|
||||
@@ -509,11 +512,9 @@ func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
|
||||
|
||||
}
|
||||
|
||||
var enableTracing = false
|
||||
|
||||
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
|
||||
toUse := gas.Total()
|
||||
if enableTracing {
|
||||
if EnableGasTracing {
|
||||
var callers [10]uintptr
|
||||
|
||||
cout := 0 //gruntime.Callers(2+skip, callers[:])
|
||||
|
||||
@@ -45,3 +45,23 @@ func TestRuntimePutErrors(t *testing.T) {
|
||||
rt.StorePut(&NotAVeryGoodMarshaler{})
|
||||
t.Error("expected panic")
|
||||
}
|
||||
|
||||
func BenchmarkRuntime_CreateRuntimeChargeGas_TracingDisabled(b *testing.B) {
|
||||
var (
|
||||
cst = cbor.NewCborStore(nil)
|
||||
gch = newGasCharge("foo", 1000, 1000)
|
||||
)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
EnableGasTracing = false
|
||||
noop := func() bool { return EnableGasTracing }
|
||||
for n := 0; n < b.N; n++ {
|
||||
// flip the value and access it to make sure
|
||||
// the compiler doesn't optimize away
|
||||
EnableGasTracing = true
|
||||
_ = noop()
|
||||
EnableGasTracing = false
|
||||
_ = (&Runtime{cst: cst}).chargeGasInternal(gch, 0)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
}
|
||||
|
||||
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
||||
if enableTracing {
|
||||
if EnableGasTracing {
|
||||
rt.lastGasChargeTime = start
|
||||
if parent != nil {
|
||||
rt.lastGasChargeTime = parent.lastGasChargeTime
|
||||
|
||||
+9
-4
@@ -449,11 +449,16 @@ var chainInspectUsage = &cli.Command{
|
||||
bySender := make(map[string]int64)
|
||||
byDest := make(map[string]int64)
|
||||
byMethod := make(map[string]int64)
|
||||
bySenderC := make(map[string]int64)
|
||||
byDestC := make(map[string]int64)
|
||||
byMethodC := make(map[string]int64)
|
||||
|
||||
var sum int64
|
||||
for _, m := range msgs {
|
||||
bySender[m.Message.From.String()] += m.Message.GasLimit
|
||||
bySenderC[m.Message.From.String()]++
|
||||
byDest[m.Message.To.String()] += m.Message.GasLimit
|
||||
byDestC[m.Message.To.String()]++
|
||||
sum += m.Message.GasLimit
|
||||
|
||||
code, err := lookupActorCode(m.Message.To)
|
||||
@@ -464,7 +469,7 @@ var chainInspectUsage = &cli.Command{
|
||||
mm := stmgr.MethodsMap[code][m.Message.Method]
|
||||
|
||||
byMethod[mm.Name] += m.Message.GasLimit
|
||||
|
||||
byMethodC[mm.Name]++
|
||||
}
|
||||
|
||||
type keyGasPair struct {
|
||||
@@ -496,19 +501,19 @@ var chainInspectUsage = &cli.Command{
|
||||
fmt.Printf("By Sender:\n")
|
||||
for i := 0; i < numRes && i < len(senderVals); i++ {
|
||||
sv := senderVals[i]
|
||||
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
|
||||
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, bySenderC[sv.Key])
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf("By Receiver:\n")
|
||||
for i := 0; i < numRes && i < len(destVals); i++ {
|
||||
sv := destVals[i]
|
||||
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
|
||||
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byDestC[sv.Key])
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf("By Method:\n")
|
||||
for i := 0; i < numRes && i < len(methodVals); i++ {
|
||||
sv := methodVals[i]
|
||||
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
|
||||
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byMethodC[sv.Key])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+16
-7
@@ -536,7 +536,7 @@ func interactiveDeal(cctx *cli.Context) error {
|
||||
|
||||
state = "miner"
|
||||
case "miner":
|
||||
fmt.Print("Miner Address (t0..): ")
|
||||
fmt.Print("Miner Address (f0..): ")
|
||||
var maddrStr string
|
||||
|
||||
_, err := fmt.Scan(&maddrStr)
|
||||
@@ -1039,6 +1039,10 @@ var clientListDeals = &cli.Command{
|
||||
Usage: "use color in display output",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-failed",
|
||||
Usage: "show failed/failing deals",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "watch",
|
||||
Usage: "watch deal updates in real-time, rather than a one time list",
|
||||
@@ -1055,6 +1059,7 @@ var clientListDeals = &cli.Command{
|
||||
verbose := cctx.Bool("verbose")
|
||||
color := cctx.Bool("color")
|
||||
watch := cctx.Bool("watch")
|
||||
showFailed := cctx.Bool("show-failed")
|
||||
|
||||
localDeals, err := api.ClientListDeals(ctx)
|
||||
if err != nil {
|
||||
@@ -1071,7 +1076,7 @@ var clientListDeals = &cli.Command{
|
||||
tm.Clear()
|
||||
tm.MoveCursor(1, 1)
|
||||
|
||||
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color)
|
||||
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color, showFailed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1097,7 +1102,7 @@ var clientListDeals = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"))
|
||||
return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1120,7 +1125,7 @@ func dealFromDealInfo(ctx context.Context, full api.FullNode, head *types.TipSet
|
||||
}
|
||||
}
|
||||
|
||||
func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, localDeals []api.DealInfo, verbose bool, color bool) error {
|
||||
func outputStorageDeals(ctx context.Context, out io.Writer, full lapi.FullNode, localDeals []lapi.DealInfo, verbose bool, color bool, showFailed bool) error {
|
||||
sort.Slice(localDeals, func(i, j int) bool {
|
||||
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
|
||||
})
|
||||
@@ -1132,12 +1137,14 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
|
||||
var deals []deal
|
||||
for _, localDeal := range localDeals {
|
||||
deals = append(deals, dealFromDealInfo(ctx, full, head, localDeal))
|
||||
if showFailed || localDeal.State != storagemarket.StorageDealError {
|
||||
deals = append(deals, dealFromDealInfo(ctx, full, head, localDeal))
|
||||
}
|
||||
}
|
||||
|
||||
if verbose {
|
||||
w := tabwriter.NewWriter(out, 2, 4, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
|
||||
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tVerified\tMessage\n")
|
||||
for _, d := range deals {
|
||||
onChain := "N"
|
||||
if d.OnChainDealState.SectorStartEpoch != -1 {
|
||||
@@ -1150,7 +1157,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
}
|
||||
|
||||
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
|
||||
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
|
||||
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%v\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Verified, d.LocalDeal.Message)
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
@@ -1165,6 +1172,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
tablewriter.Col("Size"),
|
||||
tablewriter.Col("Price"),
|
||||
tablewriter.Col("Duration"),
|
||||
tablewriter.Col("Verified"),
|
||||
tablewriter.NewLineCol("Message"))
|
||||
|
||||
for _, d := range deals {
|
||||
@@ -1194,6 +1202,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
"PieceCID": piece,
|
||||
"Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)),
|
||||
"Price": price,
|
||||
"Verified": d.LocalDeal.Verified,
|
||||
"Duration": d.LocalDeal.Duration,
|
||||
"Message": d.LocalDeal.Message,
|
||||
})
|
||||
|
||||
+40
-17
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
@@ -47,14 +48,44 @@ func NewCliError(s string) error {
|
||||
type ApiConnector func() api.FullNode
|
||||
|
||||
type APIInfo struct {
|
||||
Addr multiaddr.Multiaddr
|
||||
Addr string
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func (a APIInfo) DialArgs() (string, error) {
|
||||
_, addr, err := manet.DialArgs(a.Addr)
|
||||
ma, err := multiaddr.NewMultiaddr(a.Addr)
|
||||
if err == nil {
|
||||
_, addr, err := manet.DialArgs(ma)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "ws://" + addr + "/rpc/v0", err
|
||||
return "ws://" + addr + "/rpc/v0", nil
|
||||
}
|
||||
|
||||
_, err = url.Parse(a.Addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return a.Addr + "/rpc/v0", nil
|
||||
}
|
||||
|
||||
func (a APIInfo) Host() (string, error) {
|
||||
ma, err := multiaddr.NewMultiaddr(a.Addr)
|
||||
if err == nil {
|
||||
_, addr, err := manet.DialArgs(ma)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
spec, err := url.Parse(a.Addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return spec.Host, nil
|
||||
}
|
||||
|
||||
func (a APIInfo) AuthHeader() http.Header {
|
||||
@@ -72,11 +103,11 @@ func (a APIInfo) AuthHeader() http.Header {
|
||||
func flagForAPI(t repo.RepoType) string {
|
||||
switch t {
|
||||
case repo.FullNode:
|
||||
return "api"
|
||||
return "api-url"
|
||||
case repo.StorageMiner:
|
||||
return "miner-api"
|
||||
return "miner-api-url"
|
||||
case repo.Worker:
|
||||
return "worker-api"
|
||||
return "worker-api-url"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown repo type: %v", t))
|
||||
}
|
||||
@@ -130,11 +161,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
strma := ctx.String(apiFlag)
|
||||
strma = strings.TrimSpace(strma)
|
||||
|
||||
apima, err := multiaddr.NewMultiaddr(strma)
|
||||
if err != nil {
|
||||
return APIInfo{}, err
|
||||
}
|
||||
return APIInfo{Addr: apima}, nil
|
||||
return APIInfo{Addr: strma}, nil
|
||||
}
|
||||
|
||||
envKey := envForRepo(t)
|
||||
@@ -152,12 +179,8 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
if len(sp) != 2 {
|
||||
log.Warnf("invalid env(%s) value, missing token or address", envKey)
|
||||
} else {
|
||||
ma, err := multiaddr.NewMultiaddr(sp[1])
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("could not parse multiaddr from env(%s): %w", envKey, err)
|
||||
}
|
||||
return APIInfo{
|
||||
Addr: ma,
|
||||
Addr: sp[1],
|
||||
Token: []byte(sp[0]),
|
||||
}, nil
|
||||
}
|
||||
@@ -186,7 +209,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
}
|
||||
|
||||
return APIInfo{
|
||||
Addr: ma,
|
||||
Addr: ma.String(),
|
||||
Token: token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+5
-5
@@ -439,12 +439,12 @@ type mockCLI struct {
|
||||
}
|
||||
|
||||
func newMockCLI(t *testing.T) *mockCLI {
|
||||
// Create a CLI App with an --api flag so that we can specify which node
|
||||
// Create a CLI App with an --api-url flag so that we can specify which node
|
||||
// the command should be executed against
|
||||
app := cli.NewApp()
|
||||
app.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "api",
|
||||
Name: "api-url",
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
@@ -476,8 +476,8 @@ func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
||||
}
|
||||
|
||||
func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) {
|
||||
// prepend --api=<node api listener address>
|
||||
apiFlag := "--api=" + c.addr.String()
|
||||
// prepend --api-url=<node api listener address>
|
||||
apiFlag := "--api-url=" + c.addr.String()
|
||||
input = append([]string{apiFlag}, input...)
|
||||
|
||||
fs := c.flagSet(cmd)
|
||||
@@ -493,7 +493,7 @@ func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, err
|
||||
}
|
||||
|
||||
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
|
||||
// Apply app level flags (so we can process --api flag)
|
||||
// Apply app level flags (so we can process --api-url flag)
|
||||
fs := &flag.FlagSet{}
|
||||
for _, f := range c.cctx.App.Flags {
|
||||
err := f.Apply(fs)
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var pprofCmd = &cli.Command{
|
||||
@@ -37,7 +36,7 @@ var PprofGoroutines = &cli.Command{
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get API info: %w", err)
|
||||
}
|
||||
_, addr, err := manet.DialArgs(ainfo.Addr)
|
||||
addr, err := ainfo.Host()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+95
-3
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/apibstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
@@ -70,6 +72,7 @@ var stateCmd = &cli.Command{
|
||||
stateMsgCostCmd,
|
||||
stateMinerInfo,
|
||||
stateMarketCmd,
|
||||
stateExecTraceCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -313,6 +316,74 @@ var stateActiveSectorsCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var stateExecTraceCmd = &cli.Command{
|
||||
Name: "exec-trace",
|
||||
Usage: "Get the execution trace of a given message",
|
||||
ArgsUsage: "<messageCid>",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass message cid"))
|
||||
}
|
||||
|
||||
mcid, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("message cid was invalid: %s", err)
|
||||
}
|
||||
|
||||
capi, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msg, err := capi.ChainGetMessage(ctx, mcid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lookup, err := capi.StateSearchMsg(ctx, mcid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ts, err := capi.ChainGetTipSet(ctx, lookup.TipSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pts, err := capi.ChainGetTipSet(ctx, ts.Parents())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cso, err := capi.StateCompute(ctx, pts.Height(), nil, pts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var trace *api.InvocResult
|
||||
for _, t := range cso.Trace {
|
||||
if t.Msg.From == msg.From && t.Msg.Nonce == msg.Nonce {
|
||||
trace = t
|
||||
break
|
||||
}
|
||||
}
|
||||
if trace == nil {
|
||||
return fmt.Errorf("failed to find message in tipset trace output")
|
||||
}
|
||||
|
||||
out, err := json.MarshalIndent(trace, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateReplaySetCmd = &cli.Command{
|
||||
Name: "replay",
|
||||
Usage: "Replay a particular message within a tipset",
|
||||
@@ -823,6 +894,10 @@ var stateComputeStateCmd = &cli.Command{
|
||||
Name: "json",
|
||||
Usage: "generate json output",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "compute-state-output",
|
||||
Usage: "a json file containing pre-existing compute-state output, to generate html reports without rerunning state changes",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -862,9 +937,26 @@ var stateComputeStateCmd = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
stout, err := api.StateCompute(ctx, h, msgs, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
var stout *lapi.ComputeStateOutput
|
||||
if csofile := cctx.String("compute-state-output"); csofile != "" {
|
||||
data, err := ioutil.ReadFile(csofile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var o lapi.ComputeStateOutput
|
||||
if err := json.Unmarshal(data, &o); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stout = &o
|
||||
} else {
|
||||
o, err := api.StateCompute(ctx, h, msgs, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stout = o
|
||||
}
|
||||
|
||||
if cctx.Bool("json") {
|
||||
|
||||
+9
-3
@@ -233,7 +233,13 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||
|
||||
samples := 8
|
||||
i := 0
|
||||
var app, lastApp uint64
|
||||
var firstApp, app, lastApp uint64
|
||||
|
||||
state, err := napi.SyncState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
firstApp = state.VMApplied
|
||||
|
||||
for {
|
||||
state, err := napi.SyncState(ctx)
|
||||
@@ -286,10 +292,10 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||
|
||||
if i%samples == 0 {
|
||||
lastApp = app
|
||||
app = state.VMApplied
|
||||
app = state.VMApplied - firstApp
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied, (app-lastApp)*uint64(time.Second/tick)/uint64(samples))
|
||||
fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied-firstApp, (app-lastApp)*uint64(time.Second/tick)/uint64(samples))
|
||||
lastLines++
|
||||
}
|
||||
|
||||
|
||||
+202
-82
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
@@ -37,6 +38,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/tools/stats"
|
||||
@@ -342,6 +344,18 @@ var runCmd = &cli.Command{
|
||||
Usage: "process ProveCommitSector messages",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "windowed-post",
|
||||
EnvVars: []string{"LOTUS_PCR_WINDOWED_POST"},
|
||||
Usage: "process SubmitWindowedPoSt messages and refund gas fees",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "storage-deals",
|
||||
EnvVars: []string{"LOTUS_PCR_STORAGE_DEALS"},
|
||||
Usage: "process PublishStorageDeals messages and refund gas fees",
|
||||
Value: false,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "head-delay",
|
||||
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
|
||||
@@ -378,6 +392,18 @@ var runCmd = &cli.Command{
|
||||
Usage: "percent of refund to issue",
|
||||
Value: 110,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pre-fee-cap-max",
|
||||
EnvVars: []string{"LOTUS_PCR_PRE_FEE_CAP_MAX"},
|
||||
Usage: "messages with a fee cap larger than this will be skipped when processing pre commit messages",
|
||||
Value: "0.000000001",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "prove-fee-cap-max",
|
||||
EnvVars: []string{"LOTUS_PCR_PROVE_FEE_CAP_MAX"},
|
||||
Usage: "messages with a prove cap larger than this will be skipped when processing pre commit messages",
|
||||
Value: "0.000000001",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
go func() {
|
||||
@@ -421,6 +447,8 @@ var runCmd = &cli.Command{
|
||||
dryRun := cctx.Bool("dry-run")
|
||||
preCommitEnabled := cctx.Bool("pre-commit")
|
||||
proveCommitEnabled := cctx.Bool("prove-commit")
|
||||
windowedPoStEnabled := cctx.Bool("windowed-post")
|
||||
publishStorageDealsEnabled := cctx.Bool("storage-deals")
|
||||
aggregateTipsets := cctx.Int("aggregate-tipsets")
|
||||
minerRecoveryEnabled := cctx.Bool("miner-recovery")
|
||||
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
|
||||
@@ -428,6 +456,16 @@ var runCmd = &cli.Command{
|
||||
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
|
||||
minerRecoveryBonus := uint64(cctx.Int("miner-recovery-bonus"))
|
||||
|
||||
preFeeCapMax, err := types.ParseFIL(cctx.String("pre-fee-cap-max"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proveFeeCapMax, err := types.ParseFIL(cctx.String("prove-fee-cap-max"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rf := &refunder{
|
||||
api: api,
|
||||
wallet: from,
|
||||
@@ -438,6 +476,10 @@ var runCmd = &cli.Command{
|
||||
dryRun: dryRun,
|
||||
preCommitEnabled: preCommitEnabled,
|
||||
proveCommitEnabled: proveCommitEnabled,
|
||||
windowedPoStEnabled: windowedPoStEnabled,
|
||||
publishStorageDealsEnabled: publishStorageDealsEnabled,
|
||||
preFeeCapMax: types.BigInt(preFeeCapMax),
|
||||
proveFeeCapMax: types.BigInt(proveFeeCapMax),
|
||||
}
|
||||
|
||||
var refunds *MinersRefund = NewMinersRefund()
|
||||
@@ -589,7 +631,12 @@ type refunder struct {
|
||||
dryRun bool
|
||||
preCommitEnabled bool
|
||||
proveCommitEnabled bool
|
||||
windowedPoStEnabled bool
|
||||
publishStorageDealsEnabled bool
|
||||
threshold big.Int
|
||||
|
||||
preFeeCapMax big.Int
|
||||
proveFeeCapMax big.Int
|
||||
}
|
||||
|
||||
func (r *refunder) FindMiners(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, owner, worker, control bool) (*MinersRefund, error) {
|
||||
@@ -817,6 +864,147 @@ func (r *refunder) EnsureMinerMinimums(ctx context.Context, tipset *types.TipSet
|
||||
return refunds, nil
|
||||
}
|
||||
|
||||
func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
|
||||
|
||||
m := msg.Message
|
||||
refundValue := types.NewInt(0)
|
||||
var messageMethod string
|
||||
|
||||
switch m.Method {
|
||||
case builtin0.MethodsMarket.PublishStorageDeals:
|
||||
if !r.publishStorageDealsEnabled {
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
messageMethod = "PublishStorageDeals"
|
||||
|
||||
if recp.ExitCode != exitcode.Ok {
|
||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
||||
}
|
||||
|
||||
return true, messageMethod, refundValue, nil
|
||||
}
|
||||
|
||||
func (r *refunder) processTipsetStorageMinerActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
|
||||
|
||||
m := msg.Message
|
||||
refundValue := types.NewInt(0)
|
||||
var messageMethod string
|
||||
|
||||
switch m.Method {
|
||||
case builtin0.MethodsMiner.SubmitWindowedPoSt:
|
||||
if !r.windowedPoStEnabled {
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
messageMethod = "SubmitWindowedPoSt"
|
||||
|
||||
if recp.ExitCode != exitcode.Ok {
|
||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
||||
case builtin0.MethodsMiner.ProveCommitSector:
|
||||
if !r.proveCommitEnabled {
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
messageMethod = "ProveCommitSector"
|
||||
|
||||
if recp.ExitCode != exitcode.Ok {
|
||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
if m.GasFeeCap.GreaterThan(r.proveFeeCapMax) {
|
||||
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.proveFeeCapMax)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
var sn abi.SectorNumber
|
||||
|
||||
var proveCommitSector miner0.ProveCommitSectorParams
|
||||
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
||||
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
sn = proveCommitSector.SectorNumber
|
||||
|
||||
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
|
||||
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
|
||||
if err != nil {
|
||||
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
|
||||
if err != nil {
|
||||
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
|
||||
if err != nil {
|
||||
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
|
||||
if collateral.LessThan(big.Zero()) {
|
||||
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
refundValue = collateral
|
||||
if r.refundPercent > 0 {
|
||||
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
||||
}
|
||||
case builtin0.MethodsMiner.PreCommitSector:
|
||||
if !r.preCommitEnabled {
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
messageMethod = "PreCommitSector"
|
||||
|
||||
if recp.ExitCode != exitcode.Ok {
|
||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
if m.GasFeeCap.GreaterThan(r.preFeeCapMax) {
|
||||
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.preFeeCapMax)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
var precommitInfo miner.SectorPreCommitInfo
|
||||
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
||||
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
|
||||
if err != nil {
|
||||
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
refundValue = collateral
|
||||
if r.refundPercent > 0 {
|
||||
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
||||
}
|
||||
default:
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
return true, messageMethod, refundValue, nil
|
||||
}
|
||||
|
||||
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) {
|
||||
cids := tipset.Cids()
|
||||
if len(cids) == 0 {
|
||||
@@ -841,9 +1029,9 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
refundValue := types.NewInt(0)
|
||||
tipsetRefunds := NewMinersRefund()
|
||||
for i, msg := range msgs {
|
||||
refundValue := types.NewInt(0)
|
||||
m := msg.Message
|
||||
|
||||
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
|
||||
@@ -852,91 +1040,23 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
|
||||
continue
|
||||
}
|
||||
|
||||
if !builtin.IsStorageMinerActor(a.Code) {
|
||||
continue
|
||||
}
|
||||
|
||||
var messageMethod string
|
||||
var processed bool
|
||||
|
||||
switch m.Method {
|
||||
case builtin0.MethodsMiner.ProveCommitSector:
|
||||
if !r.proveCommitEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
messageMethod = "ProveCommitSector"
|
||||
|
||||
if recps[i].ExitCode != exitcode.Ok {
|
||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
|
||||
continue
|
||||
}
|
||||
|
||||
var sn abi.SectorNumber
|
||||
|
||||
var proveCommitSector miner0.ProveCommitSectorParams
|
||||
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
||||
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
||||
continue
|
||||
}
|
||||
|
||||
sn = proveCommitSector.SectorNumber
|
||||
|
||||
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
|
||||
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
|
||||
if err != nil {
|
||||
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
continue
|
||||
}
|
||||
|
||||
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
|
||||
if err != nil {
|
||||
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
continue
|
||||
}
|
||||
|
||||
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
|
||||
if err != nil {
|
||||
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
}
|
||||
|
||||
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
|
||||
if collateral.LessThan(big.Zero()) {
|
||||
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||
continue
|
||||
}
|
||||
|
||||
refundValue = collateral
|
||||
case builtin0.MethodsMiner.PreCommitSector:
|
||||
if !r.preCommitEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
messageMethod = "PreCommitSector"
|
||||
|
||||
if recps[i].ExitCode != exitcode.Ok {
|
||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
|
||||
continue
|
||||
}
|
||||
|
||||
var precommitInfo miner.SectorPreCommitInfo
|
||||
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
||||
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
||||
continue
|
||||
}
|
||||
|
||||
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
|
||||
if err != nil {
|
||||
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
|
||||
continue
|
||||
}
|
||||
|
||||
refundValue = collateral
|
||||
default:
|
||||
continue
|
||||
if m.To == market.Address {
|
||||
processed, messageMethod, refundValue, err = r.processTipsetStorageMarketActor(ctx, tipset, msg, recps[i])
|
||||
}
|
||||
|
||||
if r.refundPercent > 0 {
|
||||
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
||||
if builtin.IsStorageMinerActor(a.Code) {
|
||||
processed, messageMethod, refundValue, err = r.processTipsetStorageMinerActor(ctx, tipset, msg, recps[i])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorw("error while processing message", "cid", msg.Cid)
|
||||
continue
|
||||
}
|
||||
if !processed {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugw(
|
||||
|
||||
+59
-25
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
|
||||
@@ -33,16 +34,19 @@ import (
|
||||
)
|
||||
|
||||
type accountInfo struct {
|
||||
Address address.Address
|
||||
Balance types.FIL
|
||||
Type string
|
||||
Power abi.StoragePower
|
||||
Worker address.Address
|
||||
Owner address.Address
|
||||
InitialPledge types.FIL
|
||||
PreCommits types.FIL
|
||||
LockedFunds types.FIL
|
||||
Sectors uint64
|
||||
Address address.Address
|
||||
Balance types.FIL
|
||||
Type string
|
||||
Power abi.StoragePower
|
||||
Worker address.Address
|
||||
Owner address.Address
|
||||
InitialPledge types.FIL
|
||||
PreCommits types.FIL
|
||||
LockedFunds types.FIL
|
||||
Sectors uint64
|
||||
VestingStart abi.ChainEpoch
|
||||
VestingDuration abi.ChainEpoch
|
||||
VestingAmount types.FIL
|
||||
}
|
||||
|
||||
var auditsCmd = &cli.Command{
|
||||
@@ -115,10 +119,8 @@ var chainBalanceCmd = &cli.Command{
|
||||
infos = append(infos, ai)
|
||||
}
|
||||
|
||||
fmt.Printf("Address,Balance,Type,Power,Worker,Owner\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Power, acc.Worker, acc.Owner)
|
||||
}
|
||||
printAccountInfos(infos, false)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -196,6 +198,7 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
LockedFunds: types.FIL(big.NewInt(0)),
|
||||
InitialPledge: types.FIL(big.NewInt(0)),
|
||||
PreCommits: types.FIL(big.NewInt(0)),
|
||||
VestingAmount: types.FIL(big.NewInt(0)),
|
||||
}
|
||||
|
||||
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
|
||||
@@ -234,6 +237,32 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
ai.Worker = minfo.Worker
|
||||
ai.Owner = minfo.Owner
|
||||
}
|
||||
|
||||
if builtin.IsMultisigActor(act.Code) {
|
||||
mst, err := multisig.Load(store, act)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ai.VestingStart, err = mst.StartEpoch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ib, err := mst.InitialBalance()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ai.VestingAmount = types.FIL(ib)
|
||||
|
||||
ai.VestingDuration, err = mst.UnlockDuration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
infos = append(infos, ai)
|
||||
return nil
|
||||
})
|
||||
@@ -241,22 +270,27 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
return xerrors.Errorf("failed to loop over actors: %w", err)
|
||||
}
|
||||
|
||||
if minerInfo {
|
||||
fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge, acc.LockedFunds, acc.PreCommits)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Address,Balance,Type\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance, acc.Type)
|
||||
}
|
||||
}
|
||||
printAccountInfos(infos, minerInfo)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func printAccountInfos(infos []accountInfo, minerInfo bool) {
|
||||
if minerInfo {
|
||||
fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits,VestingStart,VestingDuration,VestingAmount\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s,%d,%d,%s\n", acc.Address, acc.Balance.Unitless(), acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge.Unitless(), acc.LockedFunds.Unitless(), acc.PreCommits.Unitless(), acc.VestingStart, acc.VestingDuration, acc.VestingAmount.Unitless())
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Address,Balance,Type\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance.Unitless(), acc.Type)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var chainPledgeCmd = &cli.Command{
|
||||
Name: "stateroot-pledge",
|
||||
Description: "Calculate sector pledge numbers",
|
||||
|
||||
@@ -111,7 +111,7 @@ var consensusCheckCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ainfo := lcli.APIInfo{Addr: apima}
|
||||
ainfo := lcli.APIInfo{Addr: apima.String()}
|
||||
addr, err := ainfo.DialArgs()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"math"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -32,6 +34,10 @@ var noncefix = &cli.Command{
|
||||
&cli.BoolFlag{
|
||||
Name: "auto",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "gas-fee-cap",
|
||||
Usage: "specify gas fee cap for nonce filling messages",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
@@ -84,15 +90,32 @@ var noncefix = &cli.Command{
|
||||
}
|
||||
fmt.Printf("Creating %d filler messages (%d ~ %d)\n", end-start, start, end)
|
||||
|
||||
ts, err := api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
feeCap := big.Mul(ts.Blocks()[0].ParentBaseFee, big.NewInt(2)) // default fee cap to 2 * parent base fee
|
||||
if fcf := cctx.Int64("gas-fee-cap"); fcf != 0 {
|
||||
feeCap = abi.NewTokenAmount(fcf)
|
||||
}
|
||||
|
||||
for i := start; i < end; i++ {
|
||||
msg := &types.Message{
|
||||
From: addr,
|
||||
To: addr,
|
||||
Value: types.NewInt(1),
|
||||
Nonce: i,
|
||||
From: addr,
|
||||
To: addr,
|
||||
Value: types.NewInt(0),
|
||||
Nonce: i,
|
||||
GasLimit: 1000000,
|
||||
GasFeeCap: feeCap,
|
||||
GasPremium: abi.NewTokenAmount(5),
|
||||
}
|
||||
smsg, err := api.WalletSignMessage(ctx, addr, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = api.MpoolPushMessage(ctx, msg, nil)
|
||||
_, err = api.MpoolPush(ctx, smsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -154,14 +154,14 @@ var setAskCmd = &cli.Command{
|
||||
Name: "set-ask",
|
||||
Usage: "Configure the miner's ask",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Uint64Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "price",
|
||||
Usage: "Set the price of the ask for unverified deals (specified as attoFIL / GiB / Epoch) to `PRICE`",
|
||||
Usage: "Set the price of the ask for unverified deals (specified as FIL / GiB / Epoch) to `PRICE`.",
|
||||
Required: true,
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "verified-price",
|
||||
Usage: "Set the price of the ask for verified deals (specified as attoFIL / GiB / Epoch) to `PRICE`",
|
||||
Usage: "Set the price of the ask for verified deals (specified as FIL / GiB / Epoch) to `PRICE`",
|
||||
Required: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@@ -185,8 +185,15 @@ var setAskCmd = &cli.Command{
|
||||
}
|
||||
defer closer()
|
||||
|
||||
pri := types.NewInt(cctx.Uint64("price"))
|
||||
vpri := types.NewInt(cctx.Uint64("verified-price"))
|
||||
pri, err := types.ParseFIL(cctx.String("price"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vpri, err := types.ParseFIL(cctx.String("verified-price"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dur, err := time.ParseDuration("720h0m0s")
|
||||
if err != nil {
|
||||
@@ -229,7 +236,7 @@ var setAskCmd = &cli.Command{
|
||||
return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax))))
|
||||
}
|
||||
|
||||
return api.MarketSetAsk(ctx, pri, vpri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max))
|
||||
return api.MarketSetAsk(ctx, types.BigInt(pri), types.BigInt(vpri), abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -281,7 +288,7 @@ var getAskCmd = &cli.Command{
|
||||
rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String()
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, ask.VerifiedPrice, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo)
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", types.FIL(ask.Price), types.FIL(ask.VerifiedPrice), types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo)
|
||||
|
||||
return w.Flush()
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@ var runCmd = &cli.Command{
|
||||
Usage: "Start a lotus miner process",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "api",
|
||||
Name: "miner-api",
|
||||
Usage: "2345",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
@@ -61,7 +61,7 @@ var runCmd = &cli.Command{
|
||||
|
||||
nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
return xerrors.Errorf("getting full node api: %w", err)
|
||||
}
|
||||
defer ncloser()
|
||||
ctx := lcli.DaemonContext(cctx)
|
||||
@@ -112,29 +112,29 @@ var runCmd = &cli.Command{
|
||||
node.Online(),
|
||||
node.Repo(r),
|
||||
|
||||
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
|
||||
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("miner-api") },
|
||||
node.Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) {
|
||||
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("api"))
|
||||
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("miner-api"))
|
||||
})),
|
||||
node.Override(new(api.FullNode), nodeApi),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return xerrors.Errorf("creating node: %w", err)
|
||||
}
|
||||
|
||||
endpoint, err := r.APIEndpoint()
|
||||
if err != nil {
|
||||
return err
|
||||
return xerrors.Errorf("getting API endpoint: %w", err)
|
||||
}
|
||||
|
||||
// Bootstrap with full node
|
||||
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
return xerrors.Errorf("getting full node libp2p address: %w", err)
|
||||
}
|
||||
|
||||
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
|
||||
return err
|
||||
return xerrors.Errorf("connecting to full node (libp2p): %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Remote version %s", v)
|
||||
|
||||
@@ -31,6 +31,10 @@ const metaFile = "sectorstore.json"
|
||||
var storageCmd = &cli.Command{
|
||||
Name: "storage",
|
||||
Usage: "manage sector storage",
|
||||
Description: `Sectors can be stored across many filesystem paths. These
|
||||
commands provide ways to manage the storage the miner will used to store sectors
|
||||
long term for proving (references as 'store') as well as how sectors will be
|
||||
stored while moving through the sealing pipeline (references as 'seal').`,
|
||||
Subcommands: []*cli.Command{
|
||||
storageAttachCmd,
|
||||
storageListCmd,
|
||||
@@ -41,6 +45,25 @@ var storageCmd = &cli.Command{
|
||||
var storageAttachCmd = &cli.Command{
|
||||
Name: "attach",
|
||||
Usage: "attach local storage path",
|
||||
Description: `Storage can be attached to the miner using this command. The storage volume
|
||||
list is stored local to the miner in $LOTUS_MINER_PATH/storage.json. We do not
|
||||
recommend manually modifying this value without further understanding of the
|
||||
storage system.
|
||||
|
||||
Each storage volume contains a configuration file which describes the
|
||||
capabilities of the volume. When the '--init' flag is provided, this file will
|
||||
be created using the additional flags.
|
||||
|
||||
Weight
|
||||
A high weight value means data will be more likely to be stored in this path
|
||||
|
||||
Seal
|
||||
Data for the sealing process will be stored here
|
||||
|
||||
Store
|
||||
Finalized sectors that will be moved here for long term storage and be proven
|
||||
over time
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "init",
|
||||
|
||||
+15
-7
@@ -198,8 +198,10 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
||||
Preroot: root,
|
||||
Epoch: execTs.Height(),
|
||||
Message: m,
|
||||
CircSupply: &circSupplyDetail.FilCirculating,
|
||||
BaseFee: &basefee,
|
||||
CircSupply: circSupplyDetail.FilCirculating,
|
||||
BaseFee: basefee,
|
||||
// recorded randomness will be discarded.
|
||||
Rand: conformance.NewRecordingRand(new(conformance.LogReporter), fapi),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute precursor message: %w", err)
|
||||
@@ -212,6 +214,9 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
||||
applyret *vm.ApplyRet
|
||||
carWriter func(w io.Writer) error
|
||||
retention = opts.retain
|
||||
|
||||
// recordingRand will record randomness so we can embed it in the test vector.
|
||||
recordingRand = conformance.NewRecordingRand(new(conformance.LogReporter), fapi)
|
||||
)
|
||||
|
||||
log.Printf("using state retention strategy: %s", retention)
|
||||
@@ -229,8 +234,9 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
||||
Preroot: preroot,
|
||||
Epoch: execTs.Height(),
|
||||
Message: msg,
|
||||
CircSupply: &circSupplyDetail.FilCirculating,
|
||||
BaseFee: &basefee,
|
||||
CircSupply: circSupplyDetail.FilCirculating,
|
||||
BaseFee: basefee,
|
||||
Rand: recordingRand,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute message: %w", err)
|
||||
@@ -260,8 +266,9 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
||||
Preroot: preroot,
|
||||
Epoch: execTs.Height(),
|
||||
Message: msg,
|
||||
CircSupply: &circSupplyDetail.FilCirculating,
|
||||
BaseFee: &basefee,
|
||||
CircSupply: circSupplyDetail.FilCirculating,
|
||||
BaseFee: basefee,
|
||||
Rand: recordingRand,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute message: %w", err)
|
||||
@@ -356,7 +363,8 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
||||
{Source: fmt.Sprintf("execution_tipset:%s", execTs.Key().String())},
|
||||
{Source: "github.com/filecoin-project/lotus", Version: version.String()}},
|
||||
},
|
||||
CAR: out.Bytes(),
|
||||
Randomness: recordingRand.Recorded(),
|
||||
CAR: out.Bytes(),
|
||||
Pre: &schema.Preconditions{
|
||||
Epoch: int64(execTs.Height()),
|
||||
CircSupply: circSupply.Int,
|
||||
|
||||
+38
-16
@@ -2,6 +2,7 @@ package conformance
|
||||
|
||||
import (
|
||||
"context"
|
||||
gobig "math/big"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
@@ -13,7 +14,11 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/test-vectors/schema"
|
||||
@@ -79,8 +84,8 @@ type ExecuteTipsetResult struct {
|
||||
// and reward withdrawal per miner.
|
||||
func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot cid.Cid, parentEpoch abi.ChainEpoch, tipset *schema.Tipset) (*ExecuteTipsetResult, error) {
|
||||
var (
|
||||
syscalls = mkFakedSigSyscalls(vm.Syscalls(ffiwrapper.ProofVerifier))
|
||||
vmRand = new(testRand)
|
||||
syscalls = vm.Syscalls(ffiwrapper.ProofVerifier)
|
||||
vmRand = NewFixedRand()
|
||||
|
||||
cs = store.NewChainStore(bs, ds, syscalls)
|
||||
sm = stmgr.NewStateManager(cs)
|
||||
@@ -143,8 +148,12 @@ type ExecuteMessageParams struct {
|
||||
Preroot cid.Cid
|
||||
Epoch abi.ChainEpoch
|
||||
Message *types.Message
|
||||
CircSupply *abi.TokenAmount
|
||||
BaseFee *abi.TokenAmount
|
||||
CircSupply abi.TokenAmount
|
||||
BaseFee abi.TokenAmount
|
||||
|
||||
// Rand is an optional vm.Rand implementation to use. If nil, the driver
|
||||
// will use a vm.Rand that returns a fixed value for all calls.
|
||||
Rand vm.Rand
|
||||
}
|
||||
|
||||
// ExecuteMessage executes a conformance test vector message in a temporary VM.
|
||||
@@ -155,14 +164,8 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
_ = os.Setenv("LOTUS_DISABLE_VM_BUF", "iknowitsabadidea")
|
||||
}
|
||||
|
||||
basefee := DefaultBaseFee
|
||||
if params.BaseFee != nil {
|
||||
basefee = *params.BaseFee
|
||||
}
|
||||
|
||||
circSupply := DefaultCirculatingSupply
|
||||
if params.CircSupply != nil {
|
||||
circSupply = *params.CircSupply
|
||||
if params.Rand == nil {
|
||||
params.Rand = NewFixedRand()
|
||||
}
|
||||
|
||||
// dummy state manager; only to reference the GetNetworkVersion method,
|
||||
@@ -172,13 +175,13 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
vmOpts := &vm.VMOpts{
|
||||
StateBase: params.Preroot,
|
||||
Epoch: params.Epoch,
|
||||
Rand: &testRand{}, // TODO always succeeds; need more flexibility.
|
||||
Bstore: bs,
|
||||
Syscalls: mkFakedSigSyscalls(vm.Syscalls(ffiwrapper.ProofVerifier)), // TODO always succeeds; need more flexibility.
|
||||
Syscalls: vm.Syscalls(ffiwrapper.ProofVerifier),
|
||||
CircSupplyCalc: func(_ context.Context, _ abi.ChainEpoch, _ *state.StateTree) (abi.TokenAmount, error) {
|
||||
return circSupply, nil
|
||||
return params.CircSupply, nil
|
||||
},
|
||||
BaseFee: basefee,
|
||||
Rand: params.Rand,
|
||||
BaseFee: params.BaseFee,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
}
|
||||
|
||||
@@ -231,3 +234,22 @@ func toChainMsg(msg *types.Message) (ret types.ChainMsg) {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// BaseFeeOrDefault converts a basefee as passed in a test vector (go *big.Int
|
||||
// type) to an abi.TokenAmount, or if nil it returns the DefaultBaseFee.
|
||||
func BaseFeeOrDefault(basefee *gobig.Int) abi.TokenAmount {
|
||||
if basefee == nil {
|
||||
return DefaultBaseFee
|
||||
}
|
||||
return big.NewFromGo(basefee)
|
||||
}
|
||||
|
||||
// CircSupplyOrDefault converts a circulating supply as passed in a test vector
|
||||
// (go *big.Int type) to an abi.TokenAmount, or if nil it returns the
|
||||
// DefaultCirculatingSupply.
|
||||
func CircSupplyOrDefault(circSupply *gobig.Int) abi.TokenAmount {
|
||||
if circSupply == nil {
|
||||
return DefaultBaseFee
|
||||
}
|
||||
return big.NewFromGo(circSupply)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package conformance
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
type fixedRand struct{}
|
||||
|
||||
var _ vm.Rand = (*fixedRand)(nil)
|
||||
|
||||
// NewFixedRand creates a test vm.Rand that always returns fixed bytes value
|
||||
// of utf-8 string 'i_am_random_____i_am_random_____'.
|
||||
func NewFixedRand() vm.Rand {
|
||||
return &fixedRand{}
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetChainRandomness(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetBeaconRandomness(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package conformance
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/test-vectors/schema"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
type RecordingRand struct {
|
||||
reporter Reporter
|
||||
api api.FullNode
|
||||
|
||||
// once guards the loading of the head tipset.
|
||||
// can be removed when https://github.com/filecoin-project/lotus/issues/4223
|
||||
// is fixed.
|
||||
once sync.Once
|
||||
head types.TipSetKey
|
||||
lk sync.Mutex
|
||||
recorded schema.Randomness
|
||||
}
|
||||
|
||||
var _ vm.Rand = (*RecordingRand)(nil)
|
||||
|
||||
// NewRecordingRand returns a vm.Rand implementation that proxies calls to a
|
||||
// full Lotus node via JSON-RPC, and records matching rules and responses so
|
||||
// they can later be embedded in test vectors.
|
||||
func NewRecordingRand(reporter Reporter, api api.FullNode) *RecordingRand {
|
||||
return &RecordingRand{reporter: reporter, api: api}
|
||||
}
|
||||
|
||||
func (r *RecordingRand) loadHead() {
|
||||
head, err := r.api.ChainHead(context.Background())
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not fetch chain head while fetching randomness: %s", err))
|
||||
}
|
||||
r.head = head.Key()
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
r.once.Do(r.loadHead)
|
||||
ret, err := r.api.ChainGetRandomnessFromTickets(ctx, r.head, pers, round, entropy)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
r.reporter.Logf("fetched and recorded chain randomness for: dst=%d, epoch=%d, entropy=%x, result=%x", pers, round, entropy, ret)
|
||||
|
||||
match := schema.RandomnessMatch{
|
||||
On: schema.RandomnessRule{
|
||||
Kind: schema.RandomnessChain,
|
||||
DomainSeparationTag: int64(pers),
|
||||
Epoch: int64(round),
|
||||
Entropy: entropy,
|
||||
},
|
||||
Return: []byte(ret),
|
||||
}
|
||||
r.lk.Lock()
|
||||
r.recorded = append(r.recorded, match)
|
||||
r.lk.Unlock()
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
r.once.Do(r.loadHead)
|
||||
ret, err := r.api.ChainGetRandomnessFromBeacon(ctx, r.head, pers, round, entropy)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
r.reporter.Logf("fetched and recorded beacon randomness for: dst=%d, epoch=%d, entropy=%x, result=%x", pers, round, entropy, ret)
|
||||
|
||||
match := schema.RandomnessMatch{
|
||||
On: schema.RandomnessRule{
|
||||
Kind: schema.RandomnessBeacon,
|
||||
DomainSeparationTag: int64(pers),
|
||||
Epoch: int64(round),
|
||||
Entropy: entropy,
|
||||
},
|
||||
Return: []byte(ret),
|
||||
}
|
||||
r.lk.Lock()
|
||||
r.recorded = append(r.recorded, match)
|
||||
r.lk.Unlock()
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (r *RecordingRand) Recorded() schema.Randomness {
|
||||
r.lk.Lock()
|
||||
defer r.lk.Unlock()
|
||||
|
||||
return r.recorded
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package conformance
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/test-vectors/schema"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
type ReplayingRand struct {
|
||||
reporter Reporter
|
||||
recorded schema.Randomness
|
||||
fallback vm.Rand
|
||||
}
|
||||
|
||||
var _ vm.Rand = (*ReplayingRand)(nil)
|
||||
|
||||
// NewReplayingRand replays recorded randomness when requested, falling back to
|
||||
// fixed randomness if the value cannot be found; hence this is a safe
|
||||
// backwards-compatible replacement for fixedRand.
|
||||
func NewReplayingRand(reporter Reporter, recorded schema.Randomness) *ReplayingRand {
|
||||
return &ReplayingRand{
|
||||
reporter: reporter,
|
||||
recorded: recorded,
|
||||
fallback: NewFixedRand(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ReplayingRand) match(requested schema.RandomnessRule) ([]byte, bool) {
|
||||
for _, other := range r.recorded {
|
||||
if other.On.Kind == requested.Kind &&
|
||||
other.On.Epoch == requested.Epoch &&
|
||||
other.On.DomainSeparationTag == requested.DomainSeparationTag &&
|
||||
bytes.Equal(other.On.Entropy, requested.Entropy) {
|
||||
return other.Return, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (r *ReplayingRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
rule := schema.RandomnessRule{
|
||||
Kind: schema.RandomnessChain,
|
||||
DomainSeparationTag: int64(pers),
|
||||
Epoch: int64(round),
|
||||
Entropy: entropy,
|
||||
}
|
||||
|
||||
if ret, ok := r.match(rule); ok {
|
||||
r.reporter.Logf("returning saved chain randomness: dst=%d, epoch=%d, entropy=%x, result=%x", pers, round, entropy, ret)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
r.reporter.Logf("returning fallback chain randomness: dst=%d, epoch=%d, entropy=%x", pers, round, entropy)
|
||||
return r.fallback.GetChainRandomness(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (r *ReplayingRand) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
rule := schema.RandomnessRule{
|
||||
Kind: schema.RandomnessBeacon,
|
||||
DomainSeparationTag: int64(pers),
|
||||
Epoch: int64(round),
|
||||
Entropy: entropy,
|
||||
}
|
||||
|
||||
if ret, ok := r.match(rule); ok {
|
||||
r.reporter.Logf("returning saved beacon randomness: dst=%d, epoch=%d, entropy=%x, result=%x", pers, round, entropy, ret)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
r.reporter.Logf("returning fallback beacon randomness: dst=%d, epoch=%d, entropy=%x", pers, round, entropy)
|
||||
return r.fallback.GetBeaconRandomness(ctx, pers, round, entropy)
|
||||
|
||||
}
|
||||
+5
-16
@@ -13,9 +13,7 @@ import (
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/test-vectors/schema"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-cid"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
@@ -24,6 +22,8 @@ import (
|
||||
"github.com/ipfs/go-merkledag"
|
||||
"github.com/ipld/go-car"
|
||||
|
||||
"github.com/filecoin-project/test-vectors/schema"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
@@ -46,18 +46,6 @@ func ExecuteMessageVector(r Reporter, vector *schema.TestVector) {
|
||||
// Create a new Driver.
|
||||
driver := NewDriver(ctx, vector.Selector, DriverOpts{DisableVMFlush: true})
|
||||
|
||||
var circSupply *abi.TokenAmount
|
||||
if cs := vector.Pre.CircSupply; cs != nil {
|
||||
ta := big.NewFromGo(cs)
|
||||
circSupply = &ta
|
||||
}
|
||||
|
||||
var basefee *abi.TokenAmount
|
||||
if bf := vector.Pre.BaseFee; bf != nil {
|
||||
ta := big.NewFromGo(bf)
|
||||
basefee = &ta
|
||||
}
|
||||
|
||||
// Apply every message.
|
||||
for i, m := range vector.ApplyMessages {
|
||||
msg, err := types.DecodeMessage(m.Bytes)
|
||||
@@ -76,8 +64,9 @@ func ExecuteMessageVector(r Reporter, vector *schema.TestVector) {
|
||||
Preroot: root,
|
||||
Epoch: abi.ChainEpoch(epoch),
|
||||
Message: msg,
|
||||
CircSupply: circSupply,
|
||||
BaseFee: basefee,
|
||||
BaseFee: BaseFeeOrDefault(vector.Pre.BaseFee),
|
||||
CircSupply: CircSupplyOrDefault(vector.Pre.CircSupply),
|
||||
Rand: NewReplayingRand(r, vector.Randomness),
|
||||
})
|
||||
if err != nil {
|
||||
r.Fatalf("fatal failure when executing message: %s", err)
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package conformance
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
type testRand struct{}
|
||||
|
||||
var _ vm.Rand = (*testRand)(nil)
|
||||
|
||||
func (r *testRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
func (r *testRand) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
type testSyscalls struct {
|
||||
runtime.Syscalls
|
||||
}
|
||||
|
||||
// TODO VerifySignature this will always succeed; but we want to be able to test failures too.
|
||||
func (fss *testSyscalls) VerifySignature(_ crypto.Signature, _ address.Address, _ []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO VerifySeal this will always succeed; but we want to be able to test failures too.
|
||||
func (fss *testSyscalls) VerifySeal(_ proof.SealVerifyInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO VerifyPoSt this will always succeed; but we want to be able to test failures too.
|
||||
func (fss *testSyscalls) VerifyPoSt(_ proof.WindowPoStVerifyInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder {
|
||||
return func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls {
|
||||
return &testSyscalls{
|
||||
base(ctx, cstate, cst),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,7 @@
|
||||
* [MsigCreate](#MsigCreate)
|
||||
* [MsigGetAvailableBalance](#MsigGetAvailableBalance)
|
||||
* [MsigGetVested](#MsigGetVested)
|
||||
* [MsigGetVestingSchedule](#MsigGetVestingSchedule)
|
||||
* [MsigPropose](#MsigPropose)
|
||||
* [MsigSwapApprove](#MsigSwapApprove)
|
||||
* [MsigSwapCancel](#MsigSwapCancel)
|
||||
@@ -2143,6 +2144,37 @@ Inputs:
|
||||
|
||||
Response: `"0"`
|
||||
|
||||
### MsigGetVestingSchedule
|
||||
MsigGetLockedBalance returns the locked balance of an msig at a vien epoch.
|
||||
The return may be greater than the multisig actor's actual balance.
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"f01234",
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"InitialBalance": "0",
|
||||
"StartEpoch": 10101,
|
||||
"UnlockDuration": 10101
|
||||
}
|
||||
```
|
||||
|
||||
### MsigPropose
|
||||
MsigPropose proposes a multisig message
|
||||
It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||
|
||||
+7
-2
@@ -30,10 +30,15 @@ type StoragePath struct {
|
||||
|
||||
// LocalStorageMeta [path]/sectorstore.json
|
||||
type LocalStorageMeta struct {
|
||||
ID ID
|
||||
ID ID
|
||||
|
||||
// A high weight means data is more likely to be stored in this path
|
||||
Weight uint64 // 0 = readonly
|
||||
|
||||
CanSeal bool
|
||||
// Intermediate data for the sealing process will be stored here
|
||||
CanSeal bool
|
||||
|
||||
// Finalized sectors that will be proved over time will be stored here
|
||||
CanStore bool
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
Submodule extern/test-vectors updated: 3a6e0b5e06...a8f968adeb
+1
-1
@@ -27,7 +27,7 @@ func main() {
|
||||
types.ExpTipSet{},
|
||||
types.BeaconEntry{},
|
||||
types.StateRoot{},
|
||||
types.StateInfo{},
|
||||
types.StateInfo0{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -29,7 +29,7 @@ require (
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
||||
github.com/filecoin-project/go-data-transfer v0.6.7
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f
|
||||
github.com/filecoin-project/go-fil-markets v0.7.0
|
||||
github.com/filecoin-project/go-fil-markets v0.7.1
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52
|
||||
github.com/filecoin-project/go-multistore v0.0.3
|
||||
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20
|
||||
@@ -41,7 +41,7 @@ require (
|
||||
github.com/filecoin-project/specs-actors v0.9.12
|
||||
github.com/filecoin-project/specs-actors/v2 v2.0.1
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.3
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.4
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||
github.com/go-kit/kit v0.10.0
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
@@ -94,10 +94,10 @@ require (
|
||||
github.com/libp2p/go-libp2p-discovery v0.5.0
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.8.3
|
||||
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.2
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.6
|
||||
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-pubsub v0.3.6
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.8.2
|
||||
github.com/libp2p/go-libp2p-record v0.1.3
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.8
|
||||
|
||||
@@ -244,8 +244,8 @@ github.com/filecoin-project/go-ds-versioning v0.1.0 h1:y/X6UksYTsK8TLCI7rttCKEvl
|
||||
github.com/filecoin-project/go-ds-versioning v0.1.0/go.mod h1:mp16rb4i2QPmxBnmanUx8i/XANp+PFCCJWiAb+VW4/s=
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s=
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
|
||||
github.com/filecoin-project/go-fil-markets v0.7.0 h1:tcEZiUNIYQJ4PBzgVpLwfdJ4ZdC4WCv9LsgvsoCXIls=
|
||||
github.com/filecoin-project/go-fil-markets v0.7.0/go.mod h1:5Pt4DXQqUoUrp9QzlSdlYTpItXxwAtqKrxRWQ6hAOqk=
|
||||
github.com/filecoin-project/go-fil-markets v0.7.1 h1:e0NlpSnaeGyDUhCOzevjcxkSA54kt9BzlXpLRgduUFI=
|
||||
github.com/filecoin-project/go-fil-markets v0.7.1/go.mod h1:5Pt4DXQqUoUrp9QzlSdlYTpItXxwAtqKrxRWQ6hAOqk=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=
|
||||
@@ -280,8 +280,8 @@ github.com/filecoin-project/specs-actors/v2 v2.0.1 h1:bf08x6tqCDfClzrv2q/rmt/A/U
|
||||
github.com/filecoin-project/specs-actors/v2 v2.0.1/go.mod h1:v2NZVYinNIKA9acEMBm5wWXxqv5+frFEbekBFemYghY=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.3 h1:1zuBo25B3016inbygYLgYFdpJ2m1BDTbAOCgABRleiU=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.3/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.4 h1:QTRd0gb/NP4ZOTM7Dib5U3xE1/ToGDKnYLfxkC3t/m8=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.4/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=
|
||||
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
|
||||
@@ -863,6 +863,8 @@ github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLK
|
||||
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
|
||||
github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRhPwSMGpQ=
|
||||
github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=
|
||||
github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk=
|
||||
github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE=
|
||||
github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo=
|
||||
github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es=
|
||||
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
|
||||
@@ -884,12 +886,12 @@ 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-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.6-0.20200910093904-f7f33e10cc18 h1:+ae7vHSv/PJ4xGXwLV6LKGj32zjyB8ttJHtyV4TXal0=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6 h1:9oO8W7qIWCYQYyz5z8nUsPcb3rrFehBlkbqvbSVjBxY=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6/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.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/go.mod h1:F2FG/6Bzz0U6essUVxDzE0s9CrY4XGLbl7QEmDNvU7A=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.8.2 h1:FDaXBCBJ1e5hY6gnWEJ4NbYyLk8eezr4J6AY3q3KqwM=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.8.2/go.mod h1:L+e0q15ZNaYm3seHgbsXjWP8kXLEqz+elLWKk9l8DhM=
|
||||
github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q=
|
||||
github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q=
|
||||
github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg=
|
||||
@@ -1022,8 +1024,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
||||
github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE=
|
||||
github.com/lucas-clemente/quic-go v0.18.0 h1:JhQDdqxdwdmGdKsKgXi1+coHRoGhvU6z0rNzOJqZ/4o=
|
||||
github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=
|
||||
github.com/lucas-clemente/quic-go v0.18.1 h1:DMR7guC0NtVS8zNZR3IO7NARZvZygkSC56GGtC6cyys=
|
||||
github.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=
|
||||
github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
|
||||
@@ -176,7 +176,8 @@
|
||||
"CompactPartitions",
|
||||
"CompactSectorNumbers",
|
||||
"ConfirmUpdateWorkerKey",
|
||||
"RepayDebt"
|
||||
"RepayDebt",
|
||||
"ChangeOwnerAddress"
|
||||
],
|
||||
"fil/2/storagepower": [
|
||||
"Send",
|
||||
|
||||
+7
-5
@@ -11,16 +11,16 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
)
|
||||
@@ -69,6 +69,8 @@ func (api *api) Spawn() (nodeInfo, error) {
|
||||
Meta: (&genesis.AccountMeta{Owner: genm.Owner}).ActorMeta(),
|
||||
})
|
||||
template.VerifregRootKey = gen.DefaultVerifregRootkeyActor
|
||||
template.RemainderAccount = gen.DefaultRemainderAccountActor
|
||||
template.NetworkName = "pond-" + uuid.New().String()
|
||||
|
||||
tb, err := json.Marshal(&template)
|
||||
if err != nil {
|
||||
@@ -188,7 +190,7 @@ func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
||||
|
||||
mux := newWsMux()
|
||||
|
||||
cmd = exec.Command("./lotus-miner", "run", "--api", fmt.Sprintf("%d", 2500+id), "--nosync")
|
||||
cmd = exec.Command("./lotus-miner", "run", "--miner-api", fmt.Sprintf("%d", 2500+id), "--nosync")
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw)
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw)
|
||||
cmd.Env = append(os.Environ(), "LOTUS_MINER_PATH="+dir, "LOTUS_PATH="+fullNodeRepo)
|
||||
@@ -248,7 +250,7 @@ func (api *api) RestartNode(id int32) (nodeInfo, error) {
|
||||
|
||||
var cmd *exec.Cmd
|
||||
if nd.meta.Storage {
|
||||
cmd = exec.Command("./lotus-miner", "run", "--api", fmt.Sprintf("%d", 2500+id), "--nosync")
|
||||
cmd = exec.Command("./lotus-miner", "run", "--miner-api", fmt.Sprintf("%d", 2500+id), "--nosync")
|
||||
} else {
|
||||
cmd = exec.Command("./lotus", "daemon", "--api", fmt.Sprintf("%d", 2500+id))
|
||||
}
|
||||
|
||||
+22
-2
@@ -254,11 +254,31 @@ func (a *ChainAPI) ChainStatObj(ctx context.Context, obj cid.Cid, base cid.Cid)
|
||||
}
|
||||
|
||||
func (a *ChainAPI) ChainSetHead(ctx context.Context, tsk types.TipSetKey) error {
|
||||
ts, err := a.Chain.GetTipSetFromKey(tsk)
|
||||
newHeadTs, err := a.Chain.GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
return a.Chain.SetHead(ts)
|
||||
|
||||
currentTs, err := a.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting head: %w", err)
|
||||
}
|
||||
|
||||
for currentTs.Height() >= newHeadTs.Height() {
|
||||
for _, blk := range currentTs.Key().Cids() {
|
||||
err = a.Chain.UnmarkBlockAsValidated(ctx, blk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unmarking block as validated %s: %w", blk, err)
|
||||
}
|
||||
}
|
||||
|
||||
currentTs, err = a.ChainGetTipSet(ctx, currentTs.Parents())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return a.Chain.SetHead(newHeadTs)
|
||||
}
|
||||
|
||||
func (a *ChainAPI) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) {
|
||||
|
||||
+12
-1
@@ -160,7 +160,18 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message,
|
||||
priorMsgs = append(priorMsgs, m)
|
||||
}
|
||||
|
||||
res, err := a.Stmgr.CallWithGas(ctx, &msg, priorMsgs, ts)
|
||||
// Try calling until we find a height with no migration.
|
||||
var res *api.InvocResult
|
||||
for {
|
||||
res, err = a.Stmgr.CallWithGas(ctx, &msg, priorMsgs, ts)
|
||||
if err != stmgr.ErrExpensiveFork {
|
||||
break
|
||||
}
|
||||
ts, err = a.Chain.GetTipSetFromKey(ts.Parents())
|
||||
if err != nil {
|
||||
return -1, xerrors.Errorf("getting parent tipset: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return -1, xerrors.Errorf("CallWithGas failed: %w", err)
|
||||
}
|
||||
|
||||
+50
-2
@@ -307,12 +307,22 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, ts
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
|
||||
func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (res *api.InvocResult, err error) {
|
||||
ts, err := a.Chain.GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
return a.StateManager.Call(ctx, msg, ts)
|
||||
for {
|
||||
res, err = a.StateManager.Call(ctx, msg, ts)
|
||||
if err != stmgr.ErrExpensiveFork {
|
||||
break
|
||||
}
|
||||
ts, err = a.Chain.GetTipSetFromKey(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting parent tipset: %w", err)
|
||||
}
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.Cid) (*api.InvocResult, error) {
|
||||
@@ -810,6 +820,44 @@ func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Add
|
||||
return types.BigSub(act.Balance, locked), nil
|
||||
}
|
||||
|
||||
func (a *StateAPI) MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MsigVesting, error) {
|
||||
ts, err := a.Chain.GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return api.EmptyVesting, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
|
||||
act, err := a.StateManager.LoadActor(ctx, addr, ts)
|
||||
if err != nil {
|
||||
return api.EmptyVesting, xerrors.Errorf("failed to load multisig actor: %w", err)
|
||||
}
|
||||
|
||||
msas, err := multisig.Load(a.Chain.Store(ctx), act)
|
||||
if err != nil {
|
||||
return api.EmptyVesting, xerrors.Errorf("failed to load multisig actor state: %w", err)
|
||||
}
|
||||
|
||||
ib, err := msas.InitialBalance()
|
||||
if err != nil {
|
||||
return api.EmptyVesting, xerrors.Errorf("failed to load multisig initial balance: %w", err)
|
||||
}
|
||||
|
||||
se, err := msas.StartEpoch()
|
||||
if err != nil {
|
||||
return api.EmptyVesting, xerrors.Errorf("failed to load multisig start epoch: %w", err)
|
||||
}
|
||||
|
||||
ud, err := msas.UnlockDuration()
|
||||
if err != nil {
|
||||
return api.EmptyVesting, xerrors.Errorf("failed to load multisig unlock duration: %w", err)
|
||||
}
|
||||
|
||||
return api.MsigVesting{
|
||||
InitialBalance: ib,
|
||||
StartEpoch: se,
|
||||
UnlockDuration: ud,
|
||||
}, 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 {
|
||||
|
||||
+18
-10
@@ -187,6 +187,7 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) {
|
||||
build.MessagesTopic(in.Nn): 1,
|
||||
}
|
||||
|
||||
var drandTopics []string
|
||||
for _, d := range in.Dr {
|
||||
topic, err := getDrandTopic(d.Config.ChainInfoJSON)
|
||||
if err != nil {
|
||||
@@ -194,6 +195,7 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) {
|
||||
}
|
||||
topicParams[topic] = drandTopicParams
|
||||
pgTopicWeights[topic] = 5
|
||||
drandTopics = append(drandTopics, topic)
|
||||
}
|
||||
|
||||
options := []pubsub.Option{
|
||||
@@ -309,6 +311,17 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) {
|
||||
|
||||
options = append(options, pubsub.WithPeerGater(pgParams))
|
||||
|
||||
allowTopics := []string{
|
||||
build.BlocksTopic(in.Nn),
|
||||
build.MessagesTopic(in.Nn),
|
||||
}
|
||||
allowTopics = append(allowTopics, drandTopics...)
|
||||
options = append(options,
|
||||
pubsub.WithSubscriptionFilter(
|
||||
pubsub.WrapLimitSubscriptionFilter(
|
||||
pubsub.NewAllowlistSubscriptionFilter(allowTopics...),
|
||||
100)))
|
||||
|
||||
// tracer
|
||||
if in.Cfg.RemoteTracer != "" {
|
||||
a, err := ma.NewMultiaddr(in.Cfg.RemoteTracer)
|
||||
@@ -359,14 +372,9 @@ type tracerWrapper struct {
|
||||
topics map[string]struct{}
|
||||
}
|
||||
|
||||
func (trw *tracerWrapper) traceMessage(topics []string) bool {
|
||||
for _, topic := range topics {
|
||||
_, ok := trw.topics[topic]
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (trw *tracerWrapper) traceMessage(topic string) bool {
|
||||
_, ok := trw.topics[topic]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) {
|
||||
@@ -379,12 +387,12 @@ func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) {
|
||||
switch evt.GetType() {
|
||||
case pubsub_pb.TraceEvent_PUBLISH_MESSAGE:
|
||||
stats.Record(context.TODO(), metrics.PubsubPublishMessage.M(1))
|
||||
if trw.tr != nil && trw.traceMessage(evt.GetPublishMessage().Topics) {
|
||||
if trw.tr != nil && trw.traceMessage(evt.GetPublishMessage().GetTopic()) {
|
||||
trw.tr.Trace(evt)
|
||||
}
|
||||
case pubsub_pb.TraceEvent_DELIVER_MESSAGE:
|
||||
stats.Record(context.TODO(), metrics.PubsubDeliverMessage.M(1))
|
||||
if trw.tr != nil && trw.traceMessage(evt.GetDeliverMessage().Topics) {
|
||||
if trw.tr != nil && trw.traceMessage(evt.GetDeliverMessage().GetTopic()) {
|
||||
trw.tr.Trace(evt)
|
||||
}
|
||||
case pubsub_pb.TraceEvent_REJECT_MESSAGE:
|
||||
|
||||
Reference in New Issue
Block a user